//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/View/Common/IntensityDataPropertyWidget.cpp
//! @brief     Implements class IntensityDataPropertyWidget
//!
//! @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/Common/IntensityDataPropertyWidget.h"
#include "Base/Util/Assert.h"
#include "GUI/Model/Axis/AmplitudeAxisItem.h"
#include "GUI/Model/Axis/BasicAxisItem.h"
#include "GUI/Model/Data/IntensityDataItem.h"
#include "GUI/Model/Project/ProjectDocument.h"
#include "GUI/View/Numeric/NumWidgetUtil.h"
#include "GUI/View/Tool/LayoutUtil.h"
#include <QGroupBox>
#include <QLineEdit>

IntensityDataPropertyWidget::IntensityDataPropertyWidget(QWidget* parent)
    : DataPropertyWidget(parent)
{
}

void IntensityDataPropertyWidget::setFourierItem(IntensityDataItem* fftItem)
{
    ASSERT(jobRealBase());
    DataAccessWidget::setFourierItem(fftItem);
    createPanelElements();
}

void IntensityDataPropertyWidget::unsubscribe()
{
    for (auto item : allIntensityDataItems())
        disconnect(item, nullptr, this, nullptr);
}

void IntensityDataPropertyWidget::createPanelElements()
{
    if (allIntensityDataItems().size() == 0)
        return;

    unsubscribe();
    GUI::Util::Layout::clearLayout(m_mainLayout);
    m_updaters.clear();

    m_mainLayout->addRow("Axes units:",
                         GUI::Util::createUnitsComboBox(
                             axesUnitsList(),
                             [this] { return currentIntensityDataItem()->currentAxesUnits(); },
                             [this](const QString& newVal) {
                                 for (auto item : allIntensityDataItems())
                                     item->setCurrentAxesUnits(newVal);
                                 emit axesRangeResetRequested();
                                 gProjectDocument.value()->setModified();
                             },
                             &m_updaters));

    m_mainLayout->addRow(
        "Color scheme:",
        GUI::Util::createComboBox([this] { return currentIntensityDataItem()->gradientCombo(); },
                                  [this](const QString& newVal) {
                                      for (auto item : allIntensityDataItems())
                                          item->setCurrentGradient(newVal);
                                      gProjectDocument.value()->setModified();
                                  },
                                  &m_updaters));

    m_mainLayout->addRow(GUI::Util::createCheckBox(
        "Interpolate", [this] { return currentIntensityDataItem()->isInterpolated(); },
        [this](bool b) {
            for (auto item : allIntensityDataItems())
                item->setInterpolated(b);
            gProjectDocument.value()->setModified();
        },
        &m_updaters));

    // -- x-axis
    auto* xGroup = new QGroupBox("X axis", this);
    auto* xFormLayout = new QFormLayout(xGroup);
    xFormLayout->setContentsMargins(0, 0, 0, 0);
    xFormLayout->setSpacing(5);

    xFormLayout->addRow("Min:",
                        GUI::Util::createDoubleSpinbox(
                            [this] { return currentIntensityDataItem()->xAxisItem()->min(); },
                            [this](double newValue) {
                                for (auto item : allIntensityDataItems())
                                    item->xAxisItem()->setMin(newValue);
                                gProjectDocument.value()->setModified();
                            },
                            &m_updaters));

    xFormLayout->addRow("Max:",
                        GUI::Util::createDoubleSpinbox(
                            [this] { return currentIntensityDataItem()->xAxisItem()->max(); },
                            [this](double newValue) {
                                for (auto item : allIntensityDataItems())
                                    item->xAxisItem()->setMax(newValue);
                                gProjectDocument.value()->setModified();
                            },
                            &m_updaters));

    xFormLayout->addRow("Title:",
                        GUI::Util::createTextEdit(
                            [this] { return currentIntensityDataItem()->xAxisItem()->title(); },
                            [this](QString newText) {
                                for (auto item : allIntensityDataItems())
                                    item->xAxisItem()->setTitle(newText);
                                gProjectDocument.value()->setModified();
                            },
                            &m_updaters));

    m_mainLayout->addRow(xGroup);

    // -- y-axis
    auto* yGroup = new QGroupBox("Y axis", this);
    auto* yFormLayout = new QFormLayout(yGroup);
    yFormLayout->setContentsMargins(0, 0, 0, 0);
    yFormLayout->setSpacing(5);

    yFormLayout->addRow("Min:",
                        GUI::Util::createDoubleSpinbox(
                            [this] { return currentIntensityDataItem()->yAxisItem()->min(); },
                            [this](double newValue) {
                                for (auto item : allIntensityDataItems())
                                    item->yAxisItem()->setMin(newValue);
                                gProjectDocument.value()->setModified();
                            },
                            &m_updaters));

    yFormLayout->addRow("Max:",
                        GUI::Util::createDoubleSpinbox(
                            [this] { return currentIntensityDataItem()->yAxisItem()->max(); },
                            [this](double newValue) {
                                for (auto item : allIntensityDataItems())
                                    item->yAxisItem()->setMax(newValue);
                                gProjectDocument.value()->setModified();
                            },
                            &m_updaters));

    yFormLayout->addRow("Title:",
                        GUI::Util::createTextEdit(
                            [this] { return currentIntensityDataItem()->yAxisItem()->title(); },
                            [this](QString newText) {
                                for (auto item : allIntensityDataItems())
                                    item->yAxisItem()->setTitle(newText);
                                gProjectDocument.value()->setModified();
                            },
                            &m_updaters));

    m_mainLayout->addRow(yGroup);

    // -- color-axis
    auto* zGroup = new QGroupBox("Color legend", this);
    auto* zFormLayout = new QFormLayout(zGroup);
    zFormLayout->setContentsMargins(0, 0, 0, 0);
    zFormLayout->setSpacing(5);

    zFormLayout->addRow("Min:",
                        GUI::Util::createDoubleSpinbox(
                            [this] { return currentIntensityDataItem()->zAxisItem()->min(); },
                            [this](double newValue) {
                                for (auto item : allIntensityDataItems())
                                    item->zAxisItem()->setMin(newValue);
                                gProjectDocument.value()->setModified();
                            },
                            &m_updaters));

    zFormLayout->addRow("Max:",
                        GUI::Util::createDoubleSpinbox(
                            [this] { return currentIntensityDataItem()->zAxisItem()->max(); },
                            [this](double newValue) {
                                for (auto item : mainIntensityDataItems())
                                    item->zAxisItem()->setMax(newValue);
                                gProjectDocument.value()->setModified();
                            },
                            &m_updaters));

    zFormLayout->addRow(GUI::Util::createCheckBox(
        "log10", [this] { return currentIntensityDataItem()->zAxisItem()->isLogScale(); },
        [this](bool b) {
            for (auto item : allIntensityDataItems())
                item->zAxisItem()->setLogScale(b);
            gProjectDocument.value()->setModified();
        },
        &m_updaters));

    zFormLayout->addRow(GUI::Util::createCheckBox(
        "Visible", [this] { return currentIntensityDataItem()->zAxisItem()->isVisible(); },
        [this](bool b) {
            for (auto item : allIntensityDataItems())
                item->zAxisItem()->setVisible(b);
            gProjectDocument.value()->setModified();
        },
        &m_updaters));

    m_mainLayout->addRow(zGroup);

    updateUIValues();

    // react on external changes (e.g. zooming in customplot shall update the axis values)
    connect(currentIntensityDataItem(), &DataItem::itemAxesRangeChanged, this,
            &IntensityDataPropertyWidget::updateUIValues, Qt::UniqueConnection);

    // update coordinates on axes units change
    for (auto item : allIntensityDataItems())
        connect(item, &DataItem::axesUnitsChanged, this,
                &IntensityDataPropertyWidget::updateItemCoords, Qt::UniqueConnection);
}
