#include "Window.h"

#include "PaintEvent.h"
#include "MouseEvent.h"
#include "KeyboardEvent.h"

#include "Widget.h"
#include "Scene.h"
#include "TriMesh.h"
#include "RootNode.h"
#include "TransformNode.h"
#include "AbstractPainter.h"

#include "DrawingContext.h"
#include "FontsManager.h"

#include "IPlatformWindow.h"
#include "Screen.h"
#include "Image.h"

#include <iostream>

namespace mt
{

Window::Window()
    :   DrawingSurface(),
        mWidget(Widget::Create())
{
    mWidth = 800;
    mHeight = 600;
    mWidget->setBounds(mWidth, mHeight);
    mWidget->setWindow(this);
}

Window::~Window()
{

}

std::unique_ptr<Window> Window::Create()
{
    return std::make_unique<Window>();
}

void Window::setSize(unsigned width, unsigned height)
{
    DrawingSurface::setSize(width, height);
    mWidget->setBounds(width, height);

    if (mPlatformWindow)
    {
        mPlatformWindow->onResize(width, height);
    }
}

void Window::clearPlatformWindow()
{
    mPlatformWindow.reset();
}

void Window::onMouseEvent(const MouseEvent* event)
{
    mWidget->onMouseEvent(event);
}

void Window::onKeyboardEvent(const KeyboardEvent* event)
{
    mWidget->onKeyboardEvent(event);
}

void Window::onPaint(const PaintEvent* event)
{
    mWidget->onPaintEvent(event);
}

void Window::setWidget(WidgetPtr widget)
{
    if (mWidget)
    {
        mWidget.reset();
    }
    mWidget = std::move(widget);
    mWidget->setBounds(mWidth, mHeight);
    mWidget->setWindow(this);
}

IPlatformWindow* Window::getPlatformWindow() const
{
    if (mPlatformWindow)
    {
        return mPlatformWindow.get();
    }
    return nullptr;
}

void Window::setPlatformWindow(IPlatformWindowPtr window, FontsManager* fontsManager, DrawingMode drawingMode)
{
    mPlatformWindow = std::move(window);
    mDrawingContext = std::make_unique<DrawingContext>(this, fontsManager, drawingMode);
}

void Window::map()
{
    if (mPlatformWindow)
    {
        mPlatformWindow->map();
    }
}

void Window::show()
{
    if (mPlatformWindow)
    {
        mPlatformWindow->show();
    }
}

void Window::doPaint(mt::Screen* screen)
{
    if (mPlatformWindow)
    {
        mPlatformWindow->beforePaint(screen);

        auto scene = getScene();
        if (scene->getRootNode()->getNumChildren() == 0)
        {
            scene->getRootNode()->addChild(mWidget->getRootNode());
        }

        mDrawingContext->paint();

        mPlatformWindow->afterPaint(screen);
    }
}

void Window::clear()
{
    if (mPlatformWindow)
    {
        mPlatformWindow->clear();
    }
}

bool Window::isDirty() const
{
    return mWidget->needsUpdate();
}

}
