//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/View/Job/JobProgressDelegate.cpp
//! @brief     Implements class JobProgressDelegate.
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2018
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "GUI/View/Job/JobProgressDelegate.h"
#include "Base/Util/Assert.h"
#include "GUI/Model/Job/BatchInfo.h"
#include "GUI/Model/Job/JobItem.h"
#include "GUI/Model/Job/JobStatus.h"
#include "GUI/View/Job/JobsQModel.h"
#include <QApplication>
#include <QMouseEvent>
#include <QPainter>

JobProgressDelegate::JobProgressDelegate(QWidget* parent)
    : QItemDelegate(parent)
{
    m_button_state = QStyle::State_Enabled;
    m_status_to_color[JobStatus::Idle] = QColor(255, 286, 12);
    m_status_to_color[JobStatus::Running] = QColor(5, 150, 230);
    m_status_to_color[JobStatus::Completed] = QColor(5, 150, 230);
    m_status_to_color[JobStatus::Canceled] = QColor(186, 0, 0);
    m_status_to_color[JobStatus::Failed] = QColor(255, 186, 12);
}

void JobProgressDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
                                const QModelIndex& index) const
{
    if (option.state & QStyle::State_Selected)
        painter->fillRect(option.rect, option.palette.highlight());

    const auto* model = dynamic_cast<const JobsQModel*>(index.model());
    ASSERT(model);

    const JobItem* item = model->jobItemForIndex(index);
    ASSERT(item);

    painter->save();

    painter->setRenderHint(QPainter::Antialiasing, true);

    QRect textRect = getTextRect(option.rect);
    painter->drawText(textRect, item->batchInfo()->jobName());

    drawCustomProjectBar(item, painter, option);

    if (isRunning(item->batchInfo()->status())) {
        QStyleOptionButton button;
        button.rect = getButtonRect(option.rect);
        button.state = m_button_state | QStyle::State_Enabled;
        button.icon = QIcon(":/images/dark-close.svg");
        button.iconSize = QSize(12, 12);

        QApplication::style()->drawControl(QStyle::CE_PushButton, &button, painter);
    }

    painter->restore();
}

bool JobProgressDelegate::editorEvent(QEvent* event, QAbstractItemModel* model,
                                      const QStyleOptionViewItem& option, const QModelIndex& index)
{
    if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease) {
    } else {
        m_button_state = QStyle::State_Raised;
        return QItemDelegate::editorEvent(event, model, option, index);
    }

    const auto* jqmodel = dynamic_cast<const JobsQModel*>(index.model());
    ASSERT(model);

    const JobItem* item = jqmodel->jobItemForIndex(index);
    ASSERT(item);

    if (!isRunning(item->batchInfo()->status()))
        return false;

    QRect buttonRect = getButtonRect(option.rect);

    auto* mouseEvent = dynamic_cast<QMouseEvent*>(event);
    if (!buttonRect.contains(mouseEvent->pos())) {
        m_button_state = QStyle::State_Raised;
        return false; // so that selection can change
    }

    if (event->type() == QEvent::MouseButtonPress)
        m_button_state = QStyle::State_Sunken;
    else if (event->type() == QEvent::MouseButtonRelease) {
        m_button_state = QStyle::State_Raised;
        emit cancelButtonClicked({index});
    }
    return true;
}

void JobProgressDelegate::drawCustomProjectBar(const JobItem* item, QPainter* painter,
                                               const QStyleOptionViewItem& option) const
{
    int progress = item->batchInfo()->progress();
    QRect rect = getProgressBarRect(option.rect);

    painter->save();
    painter->setRenderHint(QPainter::Antialiasing);
    painter->setBrush(QColor(204, 223, 230));
    painter->setPen(QColor("transparent"));
    QRect rect2(rect.x(), rect.y(), rect.width(), rect.height());
    painter->drawRoundedRect(rect2, 2, 2);
    painter->restore();

    int progBarWidth = (rect.width() * progress) / 100;
    painter->save();
    painter->setRenderHint(QPainter::Antialiasing);
    painter->setPen(QColor("transparent"));
    painter->setBrush(m_status_to_color[item->batchInfo()->status()]);
    QRect rect5(rect.x(), rect.y(), progBarWidth, rect.height());
    painter->drawRoundedRect(rect5, 2, 2);
    painter->restore();
}

//! Returns rectangle for text
QRect JobProgressDelegate::getTextRect(QRect optionRect) const
{
    int width = optionRect.width() * 0.4;
    int height = optionRect.height();
    int x = optionRect.x() + 3;
    int y = optionRect.y();
    QRect result(x, y, width, height);
    return result;
}

//! Returns rectangle for progress bar
QRect JobProgressDelegate::getProgressBarRect(QRect optionRect) const
{
    int width = optionRect.width() * 0.4;
    int height = optionRect.height() * 0.6;
    int x = optionRect.x() + optionRect.width() * 0.5;
    int y = optionRect.y() + (optionRect.height() - height) / 2.;
    QRect result(x, y, width, height);
    return result;
}

//! Returns rectangle for button
QRect JobProgressDelegate::getButtonRect(QRect optionRect) const
{
    int height = 10;
    int width = 10;
    int x = optionRect.x() + optionRect.width() * 0.92;
    int y = optionRect.y() + (optionRect.height() - height) / 2.;
    QRect result(x, y, width, height);
    return result;
}
