//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/View/Device/AlphaScanEditor.cpp
//! @brief     Defines class AlphaScanEditor.
//!
//! @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/Device/AxisScanEditor.h"
#include "GUI/Model/Beam/BeamDistributionItem.h"
#include "GUI/Model/Beam/DistributionItems.h"
#include "GUI/Model/Beam/SourceItems.h"
#include "GUI/Model/Project/ProjectDocument.h"
#include "GUI/View/Base/LayoutUtil.h"
#include "GUI/View/Device/DistributionPlot.h"
#include "GUI/View/Device/DistributionSelector.h"
#include "GUI/View/Device/ScanRangeForm.h"
#include "GUI/View/Numeric/NumWidgetUtil.h"

AxisScanEditor::AxisScanEditor(QWidget* parent, ScanItem* item, const QString& title,
                               const QString& units, bool allow_distr)
    : StaticGroupBox(title, parent)
    , m_scan_item(item)
    , m_plot(new DistributionPlot(this))
{
    auto* layout = new QFormLayout(body());

    //... axis type combo
    auto* typeComboBox = new QComboBox;
    typeComboBox->addItem("Uniform axis");
    typeComboBox->addItem("Non-uniform axis"); // for use with experimental data ?
    layout->addRow("Axis type:", typeComboBox);
    const int idx = m_scan_item->pointwiseAxisSelected() ? 1 : 0;

    //... axis parameters
    m_form = new ScanRangeForm(layout, units);

    //... update axis type combo (needs m_form)
    typeComboBox->setCurrentIndex(idx);
    onAxisTypeSelected(idx); // enable currently selected axis

    typeComboBox->setEnabled(m_scan_item->pointwiseAxisDefined());
    connect(typeComboBox, &QComboBox::currentIndexChanged, this,
            &AxisScanEditor::onAxisTypeSelected);

    //... beam distribution

    QString distribution_units = units;
    QString frac_units = "fraction";
    ScanTypeItem* type = m_scan_item->scanTypeSelection().certainItem();
    if (auto typeItem = dynamic_cast<QzScanTypeItem*>(type)) {
        distribution_units = typeItem->isUseRelativeResolution() ? frac_units : units;
        QCheckBox* cb = GUI::Util::createCheckBox(
            "Use relative resolution", [typeItem] { return typeItem->isUseRelativeResolution(); },
            [this, typeItem, frac_units, allow_distr, units](bool b) {
                typeItem->setUseRelativeResolution(b);
                QString dist_units = b ? frac_units : units;
                updateSelectorWidget(allow_distr, dist_units);
            });
        layout->addRow(cb);
    }

    m_selector_layout = new QFormLayout();
    layout->addRow(m_selector_layout);

    //... distribution plot

    m_plot->setFixedHeight(170);
    m_plot->setShowMouseCoords(false);
    m_selector_layout->addRow(m_plot);
    layout->addRow(m_plot);

    updateSelectorWidget(allow_distr, distribution_units);
    setFixedWidth(300);
}

void AxisScanEditor::updateSelectorWidget(bool allow_distr, const QString& distr_units)
{
    GUI::Util::Layout::clearLayout(m_selector_layout);

    m_scan_item->scanDistributionItem()->distributionItem()->setUnits(distr_units);

    m_selector = new DistributionSelector(false, DistributionSelector::Category::All, this,
                                          m_scan_item->scanDistributionItem(), allow_distr);
    connect(m_selector, &DistributionSelector::distributionChanged, this,
            &AxisScanEditor::dataChanged);
    connect(m_selector, &DistributionSelector::distributionChanged, this,
            &AxisScanEditor::updatePlot);
    m_selector_layout->addRow(m_selector);

    updatePlot();
}

void AxisScanEditor::updateIndicators()
{
    m_form->updateData();
}

void AxisScanEditor::onAxisTypeSelected(int index)
{
    if (m_scan_item) {
        if (index == 0 && m_scan_item->pointwiseAxisSelected()) {
            m_scan_item->selectUniformAxis();
            emit dataChanged();
        } else if (index == 1 && !m_scan_item->pointwiseAxisSelected()) {
            m_scan_item->selectListScan();
            emit dataChanged();
        }

        m_form->setAxisItem(m_scan_item->currentAxisItem());
        m_form->setEnabled(index == 0);
        gDoc->setModified();
    }
}

void AxisScanEditor::updatePlot()
{
    auto* d = m_selector->item()->distributionItem();
    m_plot->setVisible(!dynamic_cast<const DistributionDeltaItem*>(d));
    m_plot->setDistItem(d);
    m_plot->plotItem();
}
