//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/View/Device/RectangularDetectorForm.cpp
//! @brief     Implements class RectangularDetectorForm
//!
//! @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/RectangularDetectorForm.h"
#include "GUI/Model/Detector/RectangularDetectorItem.h"
#include "GUI/View/Device/DetectorAlignmentForm.h"
#include "GUI/View/Device/ResolutionForm.h"
#include "GUI/View/Numeric/DoubleSpinBox.h"
#include "GUI/View/Numeric/SafeSpinBox.h"
#include "GUI/View/Tool/GroupBoxCollapser.h"
#include <QFormLayout>

RectangularDetectorForm::RectangularDetectorForm(QWidget* parent, RectangularDetectorItem* detector)
    : QWidget(parent)
{
    ASSERT(detector);

    auto* grid = new QGridLayout(this);
    grid->setColumnStretch(0, 1);
    grid->setColumnStretch(1, 1);
    grid->setColumnStretch(2, 1);

    // -- x-axis controls
    auto* xAxisGroupBox = new QGroupBox("X axis", this);
    auto* xAxisFormLayout = new QFormLayout(xAxisGroupBox);

    auto* xAxisNbinsSpinBox = new SafeSpinBox;
    xAxisNbinsSpinBox->setRange(1, 65536);
    xAxisNbinsSpinBox->setValue(detector->xSize());
    xAxisFormLayout->addRow("Nbins:", xAxisNbinsSpinBox);

    auto* widthSpinBox = new DoubleSpinBox(detector->width());
    xAxisFormLayout->addRow("Width [mm]:", widthSpinBox);

    connect(xAxisNbinsSpinBox, qOverload<int>(&QSpinBox::valueChanged),
            [this, detector](int newValue) {
                detector->setXSize(newValue);
                emit dataChanged();
            });

    connect(widthSpinBox, qOverload<double>(&DoubleSpinBox::baseValueChanged),
            [this, detector](double newValue) {
                detector->setWidth(newValue);
                emit dataChanged();
            });
    grid->addWidget(xAxisGroupBox, 1, 0);
    auto* collapserX = GroupBoxCollapser::installIntoGroupBox(xAxisGroupBox);
    collapserX->setExpanded(detector->isExpandXaxis());
    connect(collapserX, &GroupBoxCollapser::toggled, this,
            [detector](bool b) { detector->setExpandXaxis(b); });


    // -- y-axis controls
    auto* yAxisGroupBox = new QGroupBox("Y axis", this);
    auto* yAxisFormLayout = new QFormLayout(yAxisGroupBox);

    auto* yAxisNbinsSpinBox = new SafeSpinBox;
    yAxisNbinsSpinBox->setRange(1, 65536);
    yAxisNbinsSpinBox->setValue(detector->ySize());
    yAxisFormLayout->addRow("Nbins:", yAxisNbinsSpinBox);

    auto* heightSpinBox = new DoubleSpinBox(detector->height());
    yAxisFormLayout->addRow("Height [mm]:", heightSpinBox);

    connect(yAxisNbinsSpinBox, qOverload<int>(&QSpinBox::valueChanged),
            [this, detector](int newValue) {
                detector->setYSize(newValue);
                emit dataChanged();
            });

    connect(heightSpinBox, qOverload<double>(&DoubleSpinBox::baseValueChanged),
            [this, detector](double newValue) {
                detector->setHeight(newValue);
                emit dataChanged();
            });
    grid->addWidget(yAxisGroupBox, 1, 1);

    auto* collapserY = GroupBoxCollapser::installIntoGroupBox(yAxisGroupBox);
    collapserY->setExpanded(detector->isExpandYaxis());
    connect(collapserY, &GroupBoxCollapser::toggled, this,
            [detector](bool b) { detector->setExpandYaxis(b); });

    // -- resolution function
    auto* resolutionForm = new ResolutionForm(ResolutionForm::Millimeter, this, detector);
    grid->addWidget(resolutionForm, 1, 2);

    connect(resolutionForm, &ResolutionForm::dataChanged, this,
            &RectangularDetectorForm::dataChanged);

    // alignment selector editors
    auto* alignmentForm = new DetectorAlignmentForm(this, detector);
    grid->addWidget(alignmentForm, 2, 0, 1, 3);

    connect(alignmentForm, &DetectorAlignmentForm::dataChanged, this,
            &RectangularDetectorForm::dataChanged);
}
