//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/View/Setup/MasksPanel.cpp
//! @brief     Implements class MasksPanel.
//!
//! @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/Setup/MasksPanel.h"
#include "Fit/Param/RealLimits.h"
#include "GUI/Model/File/DatafilesSet.h"
#include "GUI/Model/Mask/MasksSet.h"
#include "GUI/Model/Project/ProjectDocument.h"
#include "GUI/View/Base/LayoutUtil.h"
#include "GUI/View/Modelview/SetView.h"
#include "GUI/View/Numeric/DoubleSpinBox.h"
#include "GUI/View/Widget/GroupBoxes.h"
#include <QCheckBox>
#include <QLineEdit>

namespace {

void addSpinBox(MaskItem* mask, QFormLayout* layout, DoubleProperty& property)
{
    auto* spinbox = new DoubleSpinBox(&property);
    layout->addRow(property.label() + ":", spinbox);
    QObject::connect(spinbox, &DoubleSpinBox::valueChanged, [mask](double) {
        gDoc->setModified();
        ASSERT(mask);
        emit mask->maskGeometryChanged();
    });
    QObject::connect(&property, &DoubleProperty::setAndNotifyCalled, spinbox,
                     &DoubleSpinBox::updateValue);
}

} // namespace


MasksPanel::MasksPanel(std::function<MasksSet*()> set_source, bool mask_not_prjn)
    : m_set_source(set_source)
    , m_set_view(new SetView(nullptr))
    , m_mask_not_prjn(mask_not_prjn)
{
    auto* layout = new QVBoxLayout(this);
    layout->setContentsMargins(0, 0, 0, 0);
    layout->setSpacing(8);

    // -- mask stack
    auto* g2 = new StaticGroupBox("Stack", this);
    layout->addWidget(g2);
    auto* l2 = new QVBoxLayout(g2->body());
    l2->setContentsMargins(0, 0, 0, 0);
    l2->addWidget(m_set_view);

    // -- mask properties
    auto* g3 = new StaticGroupBox("Selected", this);
    layout->addWidget(g3);
    g3->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
    m_editor_layout = new QFormLayout(g3->body());
    m_editor_layout->setContentsMargins(0, 0, 0, 0);

    connect(gDoc->datafiles(), &DatafilesSet::setChanged, this, &MasksPanel::updateMasksPanel);
}

void MasksPanel::updateMasksPanel()
{
    m_set_view->setModel(m_set_source() ? m_set_source()->model() : nullptr);
    if (m_set_source())
        connect(m_set_source(), &MasksSet::setChanged, this, &MasksPanel::updateMaskEditor);
    updateMaskEditor();
}

//! Private function, called by different functions.
//! Overwrites m_editor_layout.
void MasksPanel::updateMaskEditor()
{
    GUI::Util::Layout::clearLayout(m_editor_layout);

    MaskItem* t = m_set_source() ? m_set_source()->currentItem() : nullptr;
    if (!t)
        return;

    if (m_mask_not_prjn) {
        // -- mask value (only if not RoI)
        if (!dynamic_cast<RegionOfInterestItem*>(t)) {
            auto* check_box = new QCheckBox("Maskvalue", m_editor_layout->parentWidget());
            m_editor_layout->addRow(check_box);
            check_box->setChecked(t->maskValue());
            connect(check_box, &QCheckBox::stateChanged, [t, check_box] {
                ASSERT(check_box);
                t->setMaskValue(check_box->isChecked());
                ASSERT(t);
                emit t->maskGeometryChanged();
                gDoc->setModified();
            });
        }

        // -- mask visibility
        auto* check_box = new QCheckBox("Show", m_editor_layout->parentWidget());
        m_editor_layout->addRow(check_box);
        check_box->setChecked(t->isVisible());
        connect(check_box, &QCheckBox::stateChanged, [this, t, check_box] {
            ASSERT(check_box);
            m_keep_selection = true;
            ASSERT(t);
            t->setIsVisible(check_box->isChecked());
            t->setWasVisible(check_box->isChecked());
            m_keep_selection = false;
            emit t->maskGeometryChanged();
            gDoc->setModified();
        });
    }

    // -- name (only if not RoI)
    if (!dynamic_cast<RegionOfInterestItem*>(t)) {
        auto* edit = new QLineEdit(t->name(), m_editor_layout->parentWidget());
        connect(edit, &QLineEdit::textEdited, [t](const QString& s) { t->setName(s); });
        connect(edit, &QLineEdit::editingFinished, [] { gDoc->setModified(); });
        m_editor_layout->addRow("Name:", edit);
    }

    if (auto* c = dynamic_cast<RectangleItem*>(t)) {
        addSpinBox(t, m_editor_layout, c->xLow());
        addSpinBox(t, m_editor_layout, c->xUp());
        addSpinBox(t, m_editor_layout, c->yLow());
        addSpinBox(t, m_editor_layout, c->yUp());
    } else if (auto* c = dynamic_cast<EllipseItem*>(t)) {
        addSpinBox(t, m_editor_layout, c->xCenter());
        addSpinBox(t, m_editor_layout, c->yCenter());
        addSpinBox(t, m_editor_layout, c->xRadius());
        addSpinBox(t, m_editor_layout, c->yRadius());
        // addSpinBox(t, m_editor_layout, c->angle());
    } else if (auto* c = dynamic_cast<LineItem*>(t))
        addSpinBox(t, m_editor_layout, c->pos());
}
