#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(DrawingMode drawingMode, FontsManager* fontsManager)
    :   DrawingSurface(),
        mWidget(Widget::Create())
{
    mWidth = 800;
    mHeight = 600;
    mWidget->setBounds(mWidth, mHeight);
    mWidget->setWindow(this);

    mDrawingContext = std::make_unique<DrawingContext>(this, fontsManager, drawingMode);
}

Window::~Window()
{

}

std::unique_ptr<Window> Window::Create(DrawingMode drawingMode, FontsManager* fontsManager)
{
    return std::make_unique<Window>(drawingMode, fontsManager);
}

void Window::setIsSizingOnGoing(bool sizingOngoing)
{
    mSizingOngoing = sizingOngoing;
}

bool Window::getIsSizingOnGoing() const
{
    return mSizingOngoing;
}

void Window::setSize(unsigned width, unsigned height, bool triggerResize)
{
    if (width == mWidth && height == mHeight)
    {
        return;
    }

    DrawingSurface::setSize(width, height);
    if (triggerResize && !mSizingOngoing)
    {
        onResize();
    }
}

void Window::onResize()
{
    mWidget->setBounds(mWidth, mHeight);

    if (mPlatformWindow)
    {
        mPlatformWindow->onResize(mWidth, mHeight);
    }
}

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)
{
    mPlatformWindow = std::move(window);
}

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

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

DrawingContext* Window::getDrawingContent() const
{
    return mDrawingContext.get();
}

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

        if (auto scene = getScene(); scene->isEmpty())
        {
            scene->addNode(mWidget->getRootNode());
        }

        mDrawingContext->paint();

        mPlatformWindow->afterPaint(screen);
    }
}

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

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

void Window::setDisplayState(WindowState::Display state)
{
    mDisplayState = state;
}

WindowState::Display Window::getDisplayState() const
{
    return mDisplayState;
}

void Window::setTitle(const std::string& title)
{
    mTitle = title;
}

const std::string& Window::getTitle() const
{
    return mTitle;
}

void Window::addPopup(std::unique_ptr<Widget> popupWidget)
{
    if (mPopupFunc)
    {
        mPopupFunc(this, std::move(popupWidget));
    }
}

void Window::setPopupHandler(onPopupFunc func)
{
    mPopupFunc = func;
}

void Window::setParent(Window* parent)
{
    mParent = parent;
}

Window* Window::getParent() const
{
    return mParent;
}

}
