/***************************** LICENSE START ***********************************

 Copyright 2014 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include "MvQRequestPanelWidget.h"

#include <QApplication>
#include <QDebug>
#include <QDropEvent>
#include <QGridLayout>
#include <QPainter>
#include <QPalette>
#include <QTimer>

#include "MvQIconMimeData.h"
#include "MvQMethods.h"
#include "MvQTheme.h"
#include "MvLog.h"

#include "IconClass.h"
#include "IconObject.h"


QPen MvQRequestPanelWidget::linePen_;
QPen MvQRequestPanelWidget::framePen_;
QBrush MvQRequestPanelWidget::bgBrush_;
QBrush MvQRequestPanelWidget::helperBrush_;

MvQRequestPanelWidget::MvQRequestPanelWidget(const std::vector<std::string>& cls, QWidget* parent) :
    QWidget(parent),
    classes_(cls),
    delayedRepaintScheduled_(false)
{
    if (helperBrush_.style() == Qt::NoBrush) {
        linePen_ = QPen(MvQTheme::colour("iconeditor", "line_item_pen"));
        framePen_ = QPen(MvQTheme::colour("iconeditor", "frame_pen"));
        bgBrush_ = MvQTheme::brush("iconeditor", "bg_brush");
        helperBrush_ = MvQTheme::brush("iconeditor", "helper_brush");
    }
    setAcceptDrops(true);
}

// We paint the grid lines to the widget holding the gridlayout. The problem is that
// it is not called all the time when the gridlayout changes (items are hidden/shown)!
void MvQRequestPanelWidget::paintEvent(QPaintEvent* event)
{
    QPainter painter(this);

    // paint bg
    QPalette pal = palette();
    painter.fillRect(0, 0, this->width(), this->height(), bgBrush_);
    // pal.color(QPalette::Window));

    auto* grid = dynamic_cast<QGridLayout*>(layout());
    if (!grid) {
        QWidget::paintEvent(event);
        return;
    }

    painter.setPen(linePen_);

    const int widgetPos = 4;
    int firstY = 0;
    int lastY = 0;
    int bgSplitX = 0;
    int rowNum = grid->rowCount();

    // The spacing in the gridlayout
    int spacingV = grid->verticalSpacing();

    // Find right pos of the widget preceding the main widget
    int leftWidgetX =0;
    for (int i = 0; i < rowNum; i++) {
        for (int j=1; j < widgetPos; j++) {
            if (QLayoutItem* item = grid->itemAtPosition(i, j)) {
                QWidget* w = item->widget();
                if (w && w->isVisible() && w->property("paintAsHelper") != "1") {
                    auto r = item->geometry();
                    if (r.right() > leftWidgetX) {
                        leftWidgetX = r.right();
                    }
                }
            }
        }
    }

    // Find the border between the left and right hand side
    for (int i = 0; i < rowNum; i++) {
        if (QLayoutItem* item = grid->itemAtPosition(i, widgetPos)) {
            QWidget* w = item->widget();
            if (w && w->isVisible()) {
                QRect r = item->geometry();
                int h = r.height() + spacingV;
                int y = r.y() - spacingV / 2;

                if (firstY == 0)
                    firstY = y;

                lastY = y + h;

                if (bgSplitX == 0)
                    bgSplitX = (r.x() + leftWidgetX) / 2;
            }
        }
    }

    if (firstY == 0 || lastY == 0 || bgSplitX == 0)
        return;

    // Note: using drawLine() does not work properly in this function,
    // that is why we use QPolygon instead! See METV-3069.

    // The vertical separator line between the left and right hand side
    MvQ::safeDrawLine(QPoint(bgSplitX, firstY), QPoint(bgSplitX, lastY), &painter);

    // Draw the horizontal lines
    for (int i = 0; i < rowNum; i++) {
        if (QLayoutItem* item = grid->itemAtPosition(i, widgetPos)) {
            QWidget* w = item->widget();
            if (w && w->isVisible()) {
                QRect r = item->geometry();
                int h = r.height() + spacingV;
                int y = r.y() - spacingV / 2;

                if (w->property("paintAsHelper") == "1") {
                    painter.fillRect(0, y, this->width(), h, helperBrush_);
                }

                // Horizontal line
                MvQ::safeDrawLine(QPoint(0, y), QPoint(this->width(), y), &painter);
            }
        }
    }

    // The last horizontal line
    MvQ::safeDrawLine(QPoint(0, lastY), QPoint(this->width(), lastY), &painter);

    // Frame
    painter.setPen(framePen_);
    painter.drawRect(0, 0, this->width(), this->height());
}

void MvQRequestPanelWidget::delayedForceRepaint()
{
    if (!delayedRepaintScheduled_) {
        QTimer::singleShot(1, this, SLOT(forceRepaint()));
        delayedRepaintScheduled_ = true;
    }
}

void MvQRequestPanelWidget::forceRepaint()
{
    repaint();
    qApp->processEvents();
    delayedRepaintScheduled_ = false;
}

bool MvQRequestPanelWidget::isAccepted(const IconClass&) const
{
    // if the user drops an icon into the icon editor then we should
    // always accept it and try to merge the requests
    return true;
}

//===========================
// Drop from the new Desktop
//===========================

void MvQRequestPanelWidget::dragEnterEvent(QDragEnterEvent* event)
{
    if ((event->proposedAction() == Qt::CopyAction ||
         event->proposedAction() == Qt::MoveAction)) {
        event->accept();
    }
}

void MvQRequestPanelWidget::dragMoveEvent(QDragMoveEvent* event)
{
    if ((event->proposedAction() == Qt::CopyAction ||
         event->proposedAction() == Qt::MoveAction)) {
        event->accept();
    }
}

void MvQRequestPanelWidget::dropEvent(QDropEvent* event)
{
    if (event->proposedAction() != Qt::CopyAction &&
        event->proposedAction() != Qt::MoveAction) {
        event->ignore();
        return;
    }

    if (event->mimeData()->hasFormat("metview/icon")) {
        const auto* mimeData = qobject_cast<const MvQIconMimeData*>(event->mimeData());

        if (!mimeData) {
            event->ignore();
            return;
        }

        IconObject* obj = mimeData->dragObject();

        if (!obj || !isAccepted(obj->iconClass())) {
            event->ignore();
            return;
        }

        emit iconDropped(obj);

        event->accept();
        return;
    }

    event->ignore();
}
