/******************************************************************************
 * QSkinny - Copyright (C) The authors
 *           SPDX-License-Identifier: BSD-3-Clause
 *****************************************************************************/

#include "GridQuick.h"
#include <QQuickItem>
#include <QtQml>
#include <QDebug>

static QQuickItem* createQml( const char* qmlCode )
{
    QQmlEngine engine( nullptr );

    QQmlComponent component( &engine );
    component.setData( qmlCode, QUrl() );

    if ( component.status() != QQmlComponent::Ready )
        qWarning() << component.errorString();

    return qobject_cast< QQuickItem* >( component.create() );
}

static QQuickItem* itemAt( const QQuickItem* grid, int index )
{
    const auto children = grid->childItems();
    if ( ( index >= 0 ) && ( index < children.count() ) )
        return children.at( index );

    return nullptr;
}

static QObject* attachedProperties( const QQuickItem* item )
{
    for ( auto child : item->children() )
    {
        if ( child->inherits( "QQuickLayoutAttached" ) )
            return child;
    }

    return nullptr;
}

static QObject* attachedPropertiesAt( const QQuickItem* grid, int index )
{
    if ( auto item = itemAt( grid, index ) )
        return attachedProperties( item );

    return nullptr;
}

GridQuick::GridQuick( QWidget* parent )
    : QQuickWidget( parent )
{
    setContentsMargins( QMargins() );
    setResizeMode( QQuickWidget::SizeRootObjectToView );

    auto contentItem =
        createQml( "import QtQuick 2.0\nimport QtQuick.Layouts 1.1\nItem { GridLayout {} }" );
    setContent( QUrl(), nullptr, contentItem );

    m_grid = contentItem->childItems().constFirst();
    m_grid->setProperty( "rowSpacing", 5 );
    m_grid->setProperty( "columnSpacing", 5 );
}

GridQuick::~GridQuick()
{
}

void GridQuick::insert( const QByteArray& colorName,
    int row, int column, int rowSpan, int columnSpan )
{
    /*
        We need to create a temporary layout in QML, so that the
        object for the attachedProperties is created early
     */
    auto layout = createQml(
        "import QtQuick 2.0\nimport QtQuick.Layouts 1.15\nGridLayout { Rectangle {} }" );

    auto rectangle = layout->childItems().constFirst();
    rectangle->setParent( nullptr );

    delete layout;

    rectangle->setParent( m_grid );
    rectangle->setParentItem( m_grid );

    rectangle->setImplicitWidth( 50 );
    rectangle->setImplicitHeight( 50 );
    rectangle->setProperty( "color", QColor( colorName.constData() ) );

    if ( auto props = attachedProperties( rectangle ) )
    {
        props->setProperty( "row", row );
        props->setProperty( "column", column );
        props->setProperty( "rowSpan", rowSpan );
        props->setProperty( "columnSpan", columnSpan );
        props->setProperty( "fillWidth", true );
        props->setProperty( "fillHeight", true );
    }
}

void GridQuick::setSpacing( Qt::Orientations orientations, int spacing )
{
    if ( orientations & Qt::Vertical )
        m_grid->setProperty( "rowSpacing", spacing );

    if ( orientations & Qt::Horizontal )
        m_grid->setProperty( "columnSpacing", spacing );
}

void GridQuick::setSizeHint( int, Qt::Orientation, Qt::SizeHint, int )
{
    qWarning() << "setSizeHint is not supported by Quick Layouts.";
}

void GridQuick::setStretchFactor( int, Qt::Orientation, int )
{
    qWarning() << "setStretchFactor is not supported by Quick Layouts.";
}

void GridQuick::setSizeHintAt( int index, Qt::Orientation orientation,
    Qt::SizeHint which, int hint )
{
    if ( auto props = attachedPropertiesAt( m_grid, index ) )
    {
        const qreal size = hint;

        switch( static_cast< int >( which ) )
        {
            case Qt::MinimumSize:
            {
                if ( orientation == Qt::Horizontal )
                    props->setProperty( "minimumWidth", size );
                else
                    props->setProperty( "minimumHeight", size );

                break;
            }
            case Qt::PreferredSize:
            {
                if ( orientation == Qt::Horizontal )
                    props->setProperty( "preferredWidth", size );
                else
                    props->setProperty( "preferredHeight", size );

                break;
            }
            case Qt::MaximumSize:
            {
                if ( orientation == Qt::Horizontal )
                    props->setProperty( "maximumWidth", size );
                else
                    props->setProperty( "maximumHeight", size );

                break;
            }
        }
    }
}

void GridQuick::setSizePolicyAt(
    int index, Qt::Orientation orientation, int policy )
{
    const auto qPolicy = static_cast< QSizePolicy::Policy >( policy & 0xF );

#if 0
    const bool isConstrained = policy & ( 1 << 4 );
#endif

    const bool doFill = ( qPolicy & QSizePolicy::GrowFlag )
        || ( qPolicy & QSizePolicy::ExpandFlag );

    if ( auto props = attachedPropertiesAt( m_grid, index ) )
    {
        if ( orientation == Qt::Horizontal )
            props->setProperty( "fillWidth", doFill );
        else
            props->setProperty( "fillHeight", doFill );
    }
}

void GridQuick::setAlignmentAt( int index, Qt::Alignment alignment )
{
    if ( auto props = attachedPropertiesAt( m_grid, index ) )
        props->setProperty( "alignment", QVariant::fromValue( alignment ) );
}

void GridQuick::setRetainSizeWhenHiddenAt( int, bool )
{
    qWarning() << "setRetainSizeWhenHidden is not supported by Quick Layouts.";
}

void GridQuick::setVisibleAt( int index, bool on )
{
    if ( auto item = itemAt( m_grid, index ) )
        item->setVisible( on );
}

static const qreal margin = 10.0;

QSize GridQuick::preferredSize() const
{
    return QSize(
        m_grid->implicitWidth() + 2 * margin,
        m_grid->implicitHeight() + 2 * margin );
}

void GridQuick::resizeEvent( QResizeEvent* event )
{
    QQuickWidget::resizeEvent( event );

    m_grid->setX( margin );
    m_grid->setY( margin );
    m_grid->setWidth( width() - 2 * margin );
    m_grid->setHeight( height() - 2 * margin );
}

