//  ************************************************************************************************
//
//  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);

    initProgressBar();
    initButtons();
    initViews();
}

CentralWidget::~CentralWidget() = default;

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

void CentralWidget::setCurrentView(int viewId)
{
    if (auto* btn = m_view_selection_buttons->button(viewId); btn != nullptr)
        btn->click();
}

void CentralWidget::raiseView(int viewId)
{
    if (m_views_stack->currentIndex() != viewId) {
        m_views_stack->setCurrentIndex(viewId);
        emit currentViewChanged(GUI::ID::ViewId(viewId));
    }
}

void CentralWidget::initProgressBar()
{
    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);
}

void CentralWidget::initButtons()
{
    addButton(GUI::ID::ViewId::Datafile, QIcon(":/images/main_importview.svg"), "Data",
              "Import intensity data to fit");
    addButton(GUI::ID::ViewId::Instrument, QIcon(":/images/main_instrumentview.svg"), "Instrument",
              "Define the beam and the  detector");
    addButton(GUI::ID::ViewId::Sample, QIcon(":/images/main_sampleview.svg"), "Sample",
              "Build the sample");
    addButton(GUI::ID::ViewId::Simulation, QIcon(":/images/main_simulationview.svg"), "Simulation",
              "Run simulation");
    addButton(GUI::ID::ViewId::Job, QIcon(":/images/main_jobview.svg"), "Jobs",
              "Switch to see job results, tune parameters real time,\nfit the data");

    for (auto* button : m_view_selection_buttons->buttons())
        button->setEnabled(false);
}

void CentralWidget::updateViews(bool open)
{
    if (!open)
        return;
    for (auto* button : m_view_selection_buttons->buttons())
        button->setEnabled(true);
    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->setEnabled(true);
}

void CentralWidget::initViews()
{
    ASSERT(gDoc);

    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(progressBar());

    resetView(GUI::ID::ViewId::Datafile, m_data_view);
    resetView(GUI::ID::ViewId::Instrument, m_instrument_view);
    resetView(GUI::ID::ViewId::Sample, m_sample_view);
    resetView(GUI::ID::ViewId::Simulation, m_simulation_view);
    resetView(GUI::ID::ViewId::Job, m_job_view);

    connect(m_job_view, &JobView::jobSelected,
            [this](int index) { m_view_selection_buttons->button(index)->click(); });

    m_job_view->onJobSelectionChanged();
}

void CentralWidget::addButton(GUI::ID::ViewId id, const QIcon& icon, const QString& title,
                              const QString& tooltip)
{
    QToolButton* btn = createViewSelectionButton();
    m_view_selection_buttons_layout->insertWidget(id, btn);

    btn->setText(title);
    btn->setToolTip(tooltip);
    btn->setIcon(icon);
    m_view_selection_buttons->addButton(btn, id);

    updateViewSelectionButtonsGeometry();
}

void CentralWidget::resetView(GUI::ID::ViewId id, QWidget* view)
{
    m_views_stack->insertWidget(id, view);
}

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);
}

void CentralWidget::onAboutToCloseDocument()
{
    updateViewSelectionButtonsGeometry();
}

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;
}
