#include "Canvas.h"
#include "CanvasImpl.h"

HsQMLGLDelegate::HsQMLGLDelegate(
    HsQMLGLPaintCb paintCb)
    : mImpl(new HsQMLGLDelegateImpl(paintCb))
{
}

HsQMLGLDelegate::~HsQMLGLDelegate()
{
}

HsQMLCanvas::HsQMLCanvas(QQuickItem* parent)
    : QQuickItem(parent)
    , mWindow(NULL)
    , mBackEnd(NULL)
    , mDisplayMode(Inline)
    , mCanvasWidth(0)
    , mCanvasWidthSet(false)
    , mCanvasHeight(0)
    , mCanvasHeightSet(false)
{
    QObject::connect(
        this, SIGNAL(windowChanged(QQuickWindow*)),
        this, SLOT(doWindowChanged(QQuickWindow*)));
}

HsQMLCanvas::~HsQMLCanvas()
{
    detachBackEnd();
}

void HsQMLCanvas::geometryChanged(const QRectF& rect, const QRectF&)
{
    if (!mCanvasWidthSet) {
        setCanvasWidth(rect.width(), false);
    }
    if (!mCanvasHeightSet) {
        setCanvasHeight(rect.height(), false);
    }
}

void HsQMLCanvas::detachBackEnd()
{
    if (mBackEnd) {
        // The back-end belongs to the rendering thread
        mBackEnd->deleteLater();
        mBackEnd = NULL;
    }
}

HsQMLCanvas::DisplayMode HsQMLCanvas::displayMode() const
{
    return mDisplayMode;
}

void HsQMLCanvas::setDisplayMode(HsQMLCanvas::DisplayMode mode)
{
    bool change = mDisplayMode != mode;
    mDisplayMode = mode;
    if (change) {
        displayModeChanged();
    }
}

qreal HsQMLCanvas::canvasWidth() const
{
    return mCanvasWidth;
}

void HsQMLCanvas::setCanvasWidth(qreal w, bool set)
{
    bool change = mCanvasWidth != w;
    mCanvasWidth = w;
    mCanvasWidthSet |= set;
    if (change) {
        canvasWidthChanged();
    }
}

void HsQMLCanvas::unsetCanvasWidth()
{
    mCanvasWidthSet = false;
    setCanvasWidth(width(), false);
}

qreal HsQMLCanvas::canvasHeight() const
{
    return mCanvasHeight;
}

void HsQMLCanvas::setCanvasHeight(qreal h, bool set)
{
    bool change = mCanvasHeight != h;
    mCanvasHeight = h;
    mCanvasHeightSet |= set;
    if (change) {
        canvasHeightChanged();
    }
}

void HsQMLCanvas::unsetCanvasHeight()
{
    mCanvasHeightSet = false;
    setCanvasHeight(height(), false);
}

void HsQMLCanvas::doWindowChanged(QQuickWindow* win)
{
    if (mWindow) {
        QObject::disconnect(mWindow, NULL, this, NULL);
        detachBackEnd();
    }
    mWindow = win;
    if (mWindow) {
        QObject::connect(
            mWindow, SIGNAL(beforeSynchronizing()),
            this, SLOT(doPreSynchronise()), Qt::DirectConnection);
    }
}

void HsQMLCanvas::doPreSynchronise()
{
    // This executes on the rendering thread
    if (!mBackEnd) {
        mBackEnd = new HsQMLCanvasBackEnd(mWindow);
    }
    mBackEnd->setModeSize(mDisplayMode, mCanvasWidth, mCanvasHeight);
}

HsQMLGLControl::HsQMLGLControl(QQuickItem* parent)
    : QQuickItem(parent)
{}

void hsqml_init_jval_gldelegate(
    HsQMLJValHandle* hndl,
    HsQMLGLPaintCb paintCb)
{
    QJSValue* value = reinterpret_cast<QJSValue*>(hndl);
    HsQMLGLDelegate delegate(paintCb);
}
