//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/View/Plot2D/IntensityDataCanvas.cpp
//! @brief     Implements class IntensityDataCanvas
//!
//! @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/Plot2D/IntensityDataCanvas.h"
#include "Base/Util/Assert.h"
#include "GUI/Model/Data/IntensityDataItem.h"
#include "GUI/Model/Project/ProjectDocument.h"
#include "GUI/View/Info/MessageBox.h"
#include "GUI/View/Plot2D/ColorMapCanvas.h"
#include "GUI/View/PlotUtil/ColorMap.h"
#include "GUI/View/PlotUtil/SavePlotAssistant.h"
#include "GUI/View/Tool/Globals.h"
#include <QVBoxLayout>
#include <qcustomplot.h>

namespace {

const QString SettingsGroup = "IntensityDataCanvas/";

const QString SettingsKeyGradient = SettingsGroup + "Gradient";

const QString SettingsKeyInterpolation = SettingsGroup + "Interpolation";

} // namespace

IntensityDataCanvas::IntensityDataCanvas(QWidget* parent)
    : DataAccessWidget(parent)
    , m_colorMapCanvas(new ColorMapCanvas(this))
    , m_resetViewAction(nullptr)
    , m_rotateDataAction(nullptr)
    , m_savePlotAction(nullptr)
{
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    auto* layout = new QVBoxLayout;
    layout->setContentsMargins(0, 0, 0, 0);
    layout->setSpacing(0);
    layout->addWidget(m_colorMapCanvas);
    setLayout(layout);

    m_colorMapCanvas->setStatusLabelEnabled(true);

    m_resetViewAction = new QAction(this);
    m_resetViewAction->setText("Center view");
    m_resetViewAction->setIcon(QIcon(":/images/camera-metering-center.svg"));
    m_resetViewAction->setToolTip("Reset view\n"
                                  "x,y,z axes range will be set to default");
    connect(m_resetViewAction, &QAction::triggered, this, &IntensityDataCanvas::onResetViewAction,
            Qt::UniqueConnection);

    m_savePlotAction = new QAction(this);
    m_savePlotAction->setText("Save");
    m_savePlotAction->setIcon(QIcon(":/images/content-save-outline.svg"));
    m_savePlotAction->setToolTip("Save plot");
    connect(m_savePlotAction, &QAction::triggered, this, &IntensityDataCanvas::onSavePlotAction,
            Qt::UniqueConnection);

    connect(m_colorMapCanvas->customPlot(), &QCustomPlot::mousePress, this,
            &IntensityDataCanvas::onMousePress, Qt::UniqueConnection);
}

void IntensityDataCanvas::setJobOrRealItem(QObject* job_or_real_Item)
{
    DataAccessWidget::setJobOrRealItem(job_or_real_Item);
    m_colorMapCanvas->setIntensityItem(currentIntensityDataItem());

    if (!m_rotateDataAction)
        initRotation();
}

void IntensityDataCanvas::setFourierItem(IntensityDataItem* fftItem)
{
    DataAccessWidget::setFourierItem(fftItem);
    m_colorMapCanvas->setIntensityItem(currentIntensityDataItem());
}

QSize IntensityDataCanvas::sizeHint() const
{
    return QSize(500, 400);
}

QSize IntensityDataCanvas::minimumSizeHint() const
{
    return QSize(128, 128);
}

QList<QAction*> IntensityDataCanvas::actionList()
{
    if (m_rotateDataAction)
        return {m_resetViewAction, m_rotateDataAction, m_savePlotAction};
    else
        return {m_resetViewAction, m_savePlotAction};
}

void IntensityDataCanvas::onResetViewAction()
{
    for (auto item : allIntensityDataItems())
        item->resetView();
    gProjectDocument.value()->setModified();

    // synchronize real item data range with current item
    if (realIntensityDataItem())
        realIntensityDataItem()->copyZRangeFromItem(currentIntensityDataItem());
}

void IntensityDataCanvas::onSavePlotAction()
{
    ASSERT(gProjectDocument.has_value());
    QString dirname = gProjectDocument.value()->userExportDir();
    GUI::Plot::savePlot(dirname, m_colorMapCanvas->customPlot(),
                        currentIntensityDataItem()->c_field());
}

void IntensityDataCanvas::onMousePress(QMouseEvent* event)
{
    if (event->button() == Qt::RightButton)
        emit customContextMenuRequested(event->globalPos());
}

void IntensityDataCanvas::initRotation()
{
    if (!realItem())
        return;

    m_rotateDataAction = new QAction(this);
    m_rotateDataAction->setText("Rotate");
    m_rotateDataAction->setIcon(QIcon(":/images/rotate-left.svg"));
    m_rotateDataAction->setIconText("Rotate");
    m_rotateDataAction->setToolTip("Rotate intensity data by 90 deg counterclockwise");
    connect(m_rotateDataAction, &QAction::triggered, this, &IntensityDataCanvas::rotateData);
}

void IntensityDataCanvas::rotateData()
{
    if (!realItem() || !realItem()->isIntensityData())
        // should never happen because of action disabling => no
        // dialog necessary
        return;

    if (realItem()->rotationAffectsSetup()) {
        const QString title("Rotate data");
        const QString message("Rotation will break the link between the data and the instrument. "
                              "Detector masks or projections, if they exist, will be removed.");
        if (!GUI::Message::question(GUI::Global::mainWindow, title, message,
                                    "Do you wish to rotate the data?", "Yes, please rotate",
                                    "No, cancel data rotation"))
            return;
    }

    QApplication::setOverrideCursor(Qt::WaitCursor);
    realItem()->rotateData();
    QApplication::restoreOverrideCursor();
}
