/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWaylandCompositor module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#ifndef QWAYLANDQUICKITEM_P_H
#define QWAYLANDQUICKITEM_P_H

//
//  W A R N I N G
//  -------------
//
// This file is not part of the Qt API.  It exists purely as an
// implementation detail.  This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//

#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/QSGMaterialShader>
#include <QtQuick/QSGMaterial>

#include <QtWaylandCompositor/QWaylandQuickItem>
#include <QtWaylandCompositor/QWaylandOutput>

QT_BEGIN_NAMESPACE

class QWaylandSurfaceTextureProvider;
class QMutex;
class QOpenGLTexture;

#if QT_CONFIG(opengl)
class QWaylandBufferMaterialShader : public QSGMaterialShader
{
public:
    QWaylandBufferMaterialShader(QWaylandBufferRef::BufferFormatEgl format);

    bool updateUniformData(RenderState &state,
                           QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
    void updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
                            QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;

private:
    const QWaylandBufferRef::BufferFormatEgl m_format;
};

class QWaylandBufferMaterial : public QSGMaterial
{
public:
    QWaylandBufferMaterial(QWaylandBufferRef::BufferFormatEgl format);
    ~QWaylandBufferMaterial() override;

    void setTextureForPlane(int plane, QOpenGLTexture *texture, QSGTexture *scenegraphTexture);

    void bind();
    void updateScenegraphTextures(QRhi *rhi);

    QSGMaterialType *type() const override;
    QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override;

private:
    friend QWaylandBufferMaterialShader;

    void setTextureParameters(GLenum target);
    void ensureTextures(int count);

    const QWaylandBufferRef::BufferFormatEgl m_format;
    QVarLengthArray<QOpenGLTexture*, 3> m_textures;
    QVarLengthArray<QSGTexture*, 3> m_scenegraphTextures;
};
#endif // QT_CONFIG(opengl)

class QWaylandQuickItemPrivate : public QQuickItemPrivate
{
    Q_DECLARE_PUBLIC(QWaylandQuickItem)
public:
    QWaylandQuickItemPrivate() = default;

    void init()
    {
        Q_Q(QWaylandQuickItem);
        if (!mutex)
            mutex = new QMutex;

        view.reset(new QWaylandView(q));
        q->setFlag(QQuickItem::ItemHasContents);

        q->update();

        q->setSmooth(true);

        setInputEventsEnabled(true);
        QObject::connect(q, &QQuickItem::windowChanged, q, &QWaylandQuickItem::updateWindow);
        QObject::connect(view.data(), &QWaylandView::surfaceChanged, q, &QWaylandQuickItem::surfaceChanged);
        QObject::connect(view.data(), &QWaylandView::surfaceChanged, q, &QWaylandQuickItem::handleSurfaceChanged);
        QObject::connect(view.data(), &QWaylandView::surfaceDestroyed, q, &QWaylandQuickItem::surfaceDestroyed);
        QObject::connect(view.data(), &QWaylandView::outputChanged, q, &QWaylandQuickItem::outputChanged);
        QObject::connect(view.data(), &QWaylandView::outputChanged, q, &QWaylandQuickItem::updateOutput);
        QObject::connect(view.data(), &QWaylandView::bufferLockedChanged, q, &QWaylandQuickItem::bufferLockedChanged);
        QObject::connect(view.data(), &QWaylandView::allowDiscardFrontBufferChanged, q, &QWaylandQuickItem::allowDiscardFrontBuffer);

        q->updateWindow();
    }

    static const QWaylandQuickItemPrivate* get(const QWaylandQuickItem *item) { return item->d_func(); }

    void setInputEventsEnabled(bool enable)
    {
        Q_Q(QWaylandQuickItem);
        q->setAcceptedMouseButtons(enable ? (Qt::LeftButton | Qt::MiddleButton | Qt::RightButton |
                                   Qt::ExtraButton1 | Qt::ExtraButton2 | Qt::ExtraButton3 | Qt::ExtraButton4 |
                                   Qt::ExtraButton5 | Qt::ExtraButton6 | Qt::ExtraButton7 | Qt::ExtraButton8 |
                                   Qt::ExtraButton9 | Qt::ExtraButton10 | Qt::ExtraButton11 |
                                   Qt::ExtraButton12 | Qt::ExtraButton13) : Qt::NoButton);
        q->setAcceptHoverEvents(enable);
        inputEventsEnabled = enable;
    }

    bool shouldSendInputEvents() const { return view->surface() && inputEventsEnabled; }
    qreal scaleFactor() const;

    QWaylandQuickItem *findSibling(QWaylandSurface *surface) const;
    void placeAboveSibling(QWaylandQuickItem *sibling);
    void placeBelowSibling(QWaylandQuickItem *sibling);
    void placeAboveParent();
    void placeBelowParent();

    static QMutex *mutex;

    QScopedPointer<QWaylandView> view;
    QPointer<QWaylandSurface> oldSurface;
    mutable QWaylandSurfaceTextureProvider *provider = nullptr;
    bool paintEnabled = true;
    bool touchEventsEnabled = true;
    bool inputEventsEnabled = true;
    bool isDragging = false;
    bool newTexture = false;
    bool focusOnClick = true;
    bool belowParent = false;
    QPointF hoverPos;
    QMatrix4x4 lastMatrix;

    QQuickWindow *connectedWindow = nullptr;
    QWaylandOutput *connectedOutput = nullptr;
    QWaylandSurface::Origin origin = QWaylandSurface::OriginTopLeft;
    QPointer<QObject> subsurfaceHandler;
    QList<QWaylandSeat *> touchingSeats;
};

QT_END_NAMESPACE

#endif  /*QWAYLANDQUICKITEM_P_H*/
