//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/View/Mask/MaskEditorCanvas.cpp
//! @brief     Implements class MaskEditorCanvas
//!
//! @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/Mask/MaskEditorCanvas.h"
#include "GUI/Model/Data/IntensityDataItem.h"
#include "GUI/Model/Data/MaskItems.h"
#include "GUI/Model/Project/ProjectDocument.h"
#include "GUI/View/Mask/MaskGraphicsScene.h"
#include "GUI/View/Mask/MaskGraphicsView.h"
#include "GUI/View/Mask/MaskResultsPresenter.h"
#include "GUI/View/PlotUtil/ColorMap.h"
#include "GUI/View/PlotUtil/PlotStatusLabel.h"
#include "GUI/View/PlotUtil/SavePlotAssistant.h"
#include <QVBoxLayout>

MaskEditorCanvas::MaskEditorCanvas(QWidget* parent)
    : QWidget(parent)
    , m_scene(new MaskGraphicsScene(this))
    , m_view(new MaskGraphicsView(m_scene))
    , m_intensityDataItem(nullptr)
    , m_statusLabel(new PlotStatusLabel(nullptr, this))
    , m_resultsPresenter(new MaskResultsPresenter(this))
{
    setObjectName("MaskEditorCanvas");
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    auto* mainLayout = new QVBoxLayout;
    mainLayout->addWidget(m_view);
    mainLayout->addWidget(m_statusLabel);
    mainLayout->setContentsMargins(0, 0, 0, 0);
    mainLayout->setSpacing(0);
    setLayout(mainLayout);

    connect(m_view, &MaskGraphicsView::changeActivityRequest, this,
            &MaskEditorCanvas::changeActivityRequest);
    connect(m_view, &MaskGraphicsView::deleteSelectedRequest, this,
            &MaskEditorCanvas::deleteSelectedRequest);
}

void MaskEditorCanvas::setMaskContext(IntensityDataItem* intensityItem)
{
    m_intensityDataItem = intensityItem;

    m_scene->setMaskContext(intensityItem, intensityItem->maskContainerItem());
    m_resultsPresenter->setMaskContext(intensityItem);
    m_view->updateSize(m_view->size());

    m_statusLabel->addPlot(m_scene->colorMap());
}

void MaskEditorCanvas::resetContext()
{
    m_intensityDataItem = nullptr;
    m_scene->resetContext();
    m_statusLabel->reset();
}

void MaskEditorCanvas::setSelectionModel(QItemSelectionModel* model)
{
    m_scene->setSelectionModel(model);
}

MaskGraphicsScene* MaskEditorCanvas::getScene()
{
    return m_scene;
}

void MaskEditorCanvas::onPresentationTypeRequest(MaskEditorFlags::PresentationType presentationType)
{
    m_scene->clearSelection(); // important to avoid crash (unsubscribe while calling subscribers)
    m_resultsPresenter->updatePresenter(presentationType);

    if (auto* container = m_intensityDataItem->maskContainerItem()) {
        bool tempVisible = presentationType.testFlag(MaskEditorFlags::MASK_EDITOR);
        for (MaskItem* mask : container->maskItems())
            mask->setIsVisible(tempVisible && mask->wasVisible());
    }
}

//! Saves plot into project directory.

void MaskEditorCanvas::onSavePlotRequest()
{
    ASSERT(gProjectDocument.has_value());
    QString dirname = gProjectDocument.value()->userExportDir();
    GUI::Plot::savePlot(dirname, m_scene->colorMap()->customPlot(), m_intensityDataItem->c_field());
}

void MaskEditorCanvas::onResetViewRequest()
{
    m_view->onResetViewRequest();

    if (isAxisRangeMatchData())
        setZoomToROI();
    else
        m_intensityDataItem->resetView();
    gProjectDocument.value()->setModified();
}

//! Returns true if IntensityData is currently at 100% zoom level

bool MaskEditorCanvas::isAxisRangeMatchData() const
{
    ASSERT(m_intensityDataItem);

    if (m_intensityDataItem->lowerX() != m_intensityDataItem->xMin())
        return false;
    if (m_intensityDataItem->upperX() != m_intensityDataItem->xMax())
        return false;
    if (m_intensityDataItem->lowerY() != m_intensityDataItem->yMin())
        return false;
    if (m_intensityDataItem->upperY() != m_intensityDataItem->yMax())
        return false;
    return true;
}

void MaskEditorCanvas::setZoomToROI()
{
    if (MaskContainerItem* maskContainer = m_intensityDataItem->maskContainerItem()) {
        if (auto* roiItem = maskContainer->regionOfInterestItem()) {
            m_intensityDataItem->setLowerX(roiItem->xLow());
            m_intensityDataItem->setUpperX(roiItem->xUp());
            m_intensityDataItem->setLowerY(roiItem->yLow());
            m_intensityDataItem->setUpperY(roiItem->yUp());
        }
    }
}
