//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/View/Main/CentralWidget.cpp
//! @brief     Implements class CentralWidget.
//!
//! @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/Main/CentralWidget.h"
#include "Base/Util/Assert.h"
#include "GUI/Model/Project/ProjectDocument.h"
#include "GUI/View/Setup/FrameActions.h"
#include "GUI/View/View/DataView.h"
#include "GUI/View/View/InstrumentView.h"
#include "GUI/View/View/JobView.h"
#include "GUI/View/View/SampleView.h"
#include "GUI/View/View/SimulationView.h"
#include <QAction>
#include <QApplication>
#include <QDir>
#include <QOpenGLWidget>

CentralWidget::CentralWidget()
    : m_progress_bar(new QProgressBar)
    , m_view_selection_buttons(new QButtonGroup(this))
    , m_views_stack(new QStackedLayout)
    , m_view_selection_buttons_layout(new QVBoxLayout)
    , m_projects_view(nullptr)
    , m_instrument_view(nullptr)
    , m_sample_view(nullptr)
    , m_data_view(nullptr)
    , m_simulation_view(nullptr)
    , m_job_view(nullptr)
{
    auto* layout = new QHBoxLayout(this);
    layout->setContentsMargins(0, 0, 0, 0);
    layout->setSpacing(0);

    m_view_selection_buttons_layout->setContentsMargins(0, 0, 0, 0);
    m_view_selection_buttons_layout->setSpacing(0);

    auto* fillerButton = createViewSelectionButton();
    fillerButton->setMinimumSize(5, 5);
    fillerButton->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
    fillerButton->setEnabled(false);
    m_view_selection_buttons_layout->insertWidget(-1, fillerButton);

    connect(m_view_selection_buttons, &QButtonGroup::idClicked, this, &CentralWidget::raiseView);

    auto* vlayout = new QVBoxLayout;
    vlayout->setContentsMargins(0, 0, 0, 0);
    vlayout->setSpacing(0);
    vlayout->addLayout(m_views_stack);

    vlayout->addWidget(new QOpenGLWidget); // quick fix to reset surface format

    layout->addLayout(m_view_selection_buttons_layout);
    layout->addLayout(vlayout);

    m_progress_bar->hide();
    m_progress_bar->setTextVisible(false);
    m_progress_bar->setFixedHeight(QApplication::fontMetrics().boundingRect("M").height());
    m_progress_bar->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
    m_view_selection_buttons_layout->addWidget(m_progress_bar);

    addButton(ViewId::Datafile, QIcon(":/images/view/data.svg"), "Data",
              "Import intensity data to fit");
    addButton(ViewId::Instrument, QIcon(":/images/view/instrument.svg"), "Instrument",
              "Define the beam and the  detector");
    addButton(ViewId::Sample, QIcon(":/images/view/sample.svg"), "Sample", "Build the sample");
    addButton(ViewId::Simulation, QIcon(":/images/view/simulate.svg"), "Simulation",
              "Run simulation");
    addButton(ViewId::Job, QIcon(":/images/view/job.svg"), "Jobs",
              "Switch to see job results, tune parameters real time,\nfit the data");
    updateViewSelectionButtonsGeometry();

    m_instrument_view = new InstrumentView;
    m_sample_view = new SampleView;
    m_data_view = new DataView;
    m_simulation_view = new SimulationView;
    m_job_view = new JobView(m_progress_bar);

    m_views_stack->insertWidget(ViewId::Datafile, m_data_view);
    m_views_stack->insertWidget(ViewId::Instrument, m_instrument_view);
    m_views_stack->insertWidget(ViewId::Sample, m_sample_view);
    m_views_stack->insertWidget(ViewId::Simulation, m_simulation_view);
    m_views_stack->insertWidget(ViewId::Job, m_job_view);

    connect(m_job_view, &JobView::requestSwitchToJobView,
            [this]() { m_view_selection_buttons->button(ViewId::Job)->click(); });
    m_job_view->switchWidgetsToJob();
}

CentralWidget::~CentralWidget() = default;

QWidget* CentralWidget::currentView() const
{
    return m_views_stack->currentWidget();
}

void CentralWidget::raiseView(int viewId)
{
    ASSERT(checkViewId(viewId));

    if (m_views_stack->currentIndex() != viewId) {
        m_views_stack->setCurrentIndex(viewId);
        gDoc->setViewId(viewId);
        emit currentViewChanged();
    }
}

void CentralWidget::restoreView(int viewId)
{
    ASSERT(checkViewId(viewId));

    m_views_stack->setCurrentIndex(viewId);
    m_view_selection_buttons->button(viewId)->setChecked(true);
    m_views_stack->currentWidget()->show();
    emit currentViewChanged();
}

bool CentralWidget::checkViewId(int viewId) const
{
    return viewId >= 0 && viewId < m_views_stack->count();
}

void CentralWidget::updateViews()
{
    for (auto* button : m_view_selection_buttons->buttons())
        button->setEnabled(true);
    if (auto* filler =
            m_view_selection_buttons_layout->itemAt(m_view_selection_buttons->buttons().size()))
        if (auto* fillerBtn = dynamic_cast<QToolButton*>(filler->widget())) {
            fillerBtn->setEnabled(true);
            fillerBtn->setCheckable(false);
        }
}

void CentralWidget::addButton(ViewId id, const QIcon& icon, const QString& title,
                              const QString& tooltip)
{
    QToolButton* btn = createViewSelectionButton();
    btn->setText(title);
    btn->setToolTip(tooltip);
    btn->setIcon(icon);
    btn->setEnabled(false);
    m_view_selection_buttons_layout->insertWidget(id, btn);
    m_view_selection_buttons->addButton(btn, id);
}

void CentralWidget::updateViewSelectionButtonsGeometry() const
{
    if (m_view_selection_buttons->buttons().isEmpty())
        return;

    const QFontMetrics fontMetrics = m_view_selection_buttons->buttons().first()->fontMetrics();

    // Find the maximum text extents
    int maxTextWidth = 0;
    int maxTextHeight = 0;
    for (auto* b : m_view_selection_buttons->buttons()) {
        const auto r = fontMetrics.boundingRect(b->text());
        maxTextWidth = std::max(maxTextWidth, r.width());
        maxTextHeight = std::max(maxTextHeight, r.height());
    }

    // calculate the button extent by width (width == height!). Ensure an extent of 70 for normal
    // DPI devices (legacy value)
    const int margin = fontMetrics.boundingRect("M").width();
    const int buttonExtent = std::max(70, maxTextWidth + 2 * margin);

    // calculate the icon extent by height (width == height!)
    const int iconExtent = buttonExtent - margin - maxTextHeight;

    // set new values in all buttons
    for (auto* b : m_view_selection_buttons->buttons()) {
        b->setFixedSize(buttonExtent, buttonExtent);
        b->setIconSize({iconExtent, iconExtent});
    }
    // set fixed width in filler and progress bar
    auto* filler =
        m_view_selection_buttons_layout->itemAt(m_view_selection_buttons->buttons().size());
    if (filler)
        if (auto* fillerBtn = dynamic_cast<QToolButton*>(filler->widget()); fillerBtn)
            fillerBtn->setFixedWidth(buttonExtent);

    m_progress_bar->setFixedWidth(buttonExtent);
}

QToolButton* CentralWidget::createViewSelectionButton() const
{
    auto* btn = new QToolButton;
    btn->setObjectName("ViewSelectionButton"); // for addressing in style sheet
    btn->setCheckable(true);
    btn->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
    return btn;
}
