//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/View/Instrument/GISASBeamEditor.cpp
//! @brief     Implements class GISASBeamEditor
//!
//! @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/Instrument/GISASBeamEditor.h"
#include "Base/Util/Assert.h"
#include "GUI/Model/Beam/BeamAngleItems.h"
#include "GUI/Model/Beam/BeamWavelengthItem.h"
#include "GUI/Model/Beam/SourceItems.h"
#include "GUI/View/Device/FootprintForm.h"
#include "GUI/View/Instrument/DistributionEditor.h"
#include "GUI/View/Numeric/FixupDoubleValidator.h"
#include "GUI/View/Tool/GroupBoxCollapser.h"
#include <QFormLayout>
#include <QLineEdit>

GISASBeamEditor::GISASBeamEditor(QWidget* parent, BeamItem* item)
    : QGroupBox("Beam parameters", parent)
{
    ASSERT(item);
    auto* vLayout = new QVBoxLayout(this);
    vLayout->setContentsMargins(30, 8, 0, 0);
    auto* form = new QFormLayout();
    form->setFieldGrowthPolicy(QFormLayout::FieldsStayAtSizeHint);
    vLayout->addLayout(form);
    auto* intensityEditor = new QLineEdit(this);
    intensityEditor->setToolTip("Beam intensity in neutrons/photons per second.");
    auto* validator = new FixupDoubleValidator(intensityEditor);
    validator->setNotation(QDoubleValidator::ScientificNotation);
    validator->setRange(0.0, 1e32, 1000);
    intensityEditor->setValidator(validator);

    form->addRow("Intensity:", intensityEditor);

    auto* wavelengthEditor = new DistributionEditor(
        "Wavelength", MeanConfig{true}, GUI::ID::Distributions::All, this, item->wavelengthItem());
    vLayout->addWidget(wavelengthEditor);

    auto* inclinationEditor =
        new DistributionEditor("Grazing angle", MeanConfig{false}, GUI::ID::Distributions::All,
                               this, item->beamDistributionItem());
    vLayout->addWidget(inclinationEditor);

    auto* azimuthalEditor =
        new DistributionEditor("Azimuthal angle", MeanConfig{false}, GUI::ID::Distributions::All,
                               this, item->azimuthalAngleItem());
    vLayout->addWidget(azimuthalEditor);

    auto* footprintEditor = new FootprintForm(this, item);
    vLayout->addWidget(footprintEditor);

    intensityEditor->setText(QString::number(item->intensity()));

    auto* collapser = GroupBoxCollapser::installIntoGroupBox(this);
    collapser->setExpanded(item->isExpandBeamParameters());
    connect(collapser, &GroupBoxCollapser::toggled, this,
            [item](bool b) { item->setExpandBeamParameters(b); });

    connect(wavelengthEditor, &DistributionEditor::distributionChanged, this,
            &GISASBeamEditor::dataChanged);
    connect(inclinationEditor, &DistributionEditor::distributionChanged, this,
            &GISASBeamEditor::dataChanged);
    connect(azimuthalEditor, &DistributionEditor::distributionChanged, this,
            &GISASBeamEditor::dataChanged);
    connect(footprintEditor, &FootprintForm::dataChanged, this, &GISASBeamEditor::dataChanged);

    // validate value while typing
    connect(intensityEditor, &QLineEdit::textEdited, [this, intensityEditor, item]() {
        QString str = intensityEditor->text();
        int pos;
        if (intensityEditor->validator()->validate(str, pos) == QValidator::Acceptable) {
            item->setIntensity(intensityEditor->text().toDouble());
            emit dataChanged();
        }
    });
    // if validator does not assert the input value, it says about that,
    // and here we return to the last correct value
    connect(validator, &FixupDoubleValidator::fixupSignal, [validator, item]() {
        auto* editor = qobject_cast<QLineEdit*>(validator->parent());
        editor->setText(QString::number(item->intensity(), 'g'));
    });
}
