//-----------------------------------------------------------------------------
//  Copyright (C) 2020-2025 Thomas S. Ullrich
//
//  This file is part of "xyscan".
//
//  This file may be used under the terms of the GNU General Public License.
//  This project is free software; you can redistribute it and/or modify it
//  under the terms of the GNU General Public License.
//
//  Author: Thomas S. Ullrich
//  Last update: Oct 30, 2025
//-----------------------------------------------------------------------------
#include <QObject>
#include <QGridLayout>
#include <QGroupBox>
#include <QComboBox>
#include <QPushButton>
#include <QSpacerItem>
#include <QString>
#include <QTranslator>
#include <QStandardItemModel>
#include <iostream>
#include "xyscanErrorBarScanModeToolBox.h"

#define PR(x) cout << #x << " = " << (x) << endl;

using namespace std;

xyscanErrorBarScanModeToolBox::xyscanErrorBarScanModeToolBox(QWidget* form)
{
    mForm = form;
    
    //
    //   Create combo boxes for one error bar per axis only. This will cover most
    //   cases. Adding and removing further pull-down menus for more error scans
    //   is all handled in other methods of this class.
    //
    QGridLayout *gridLayout = new QGridLayout(form);

    //
    //   X Error Scan Mode
    //
    QGroupBox *groupBoxX = new QGroupBox("x-Error:", form);
    groupBoxX->setStyleSheet("QGroupBox { font-size: 13px; } ");
    mErrorXModeComboBoxVector.push_back(new QComboBox(form));
    mErrorXModeLayout = new QGridLayout(0);
    mErrorXModeLayout->setSpacing(0);
    
    mErrorXModePlusPushButton = new QPushButton(form);
    mErrorXModePlusPushButton->setText("+");
    mErrorXModePlusPushButton->setFixedWidth(mErrorXModePlusPushButton->height()+5);
    mErrorXModeMinusPushButton = new QPushButton(form);
    mErrorXModeMinusPushButton->setText("-");
    mErrorXModeMinusPushButton->setFixedWidth(mErrorXModeMinusPushButton->height()+5);
    
    mErrorXModeLayout->addWidget(mErrorXModeComboBoxVector[0], 0, 0, 1, 1);
    mErrorXModeLayout->addWidget(mErrorXModePlusPushButton, 0, 1, 1, 1);
    mErrorXModeLayout->addWidget(mErrorXModeMinusPushButton, 0, 2, 1, 1);
    groupBoxX->setLayout(mErrorXModeLayout);

    //
    //   Y Error Scan Mode
    //
    QGroupBox *groupBoxY = new QGroupBox("y-Error:", form);
    groupBoxY->setStyleSheet("QGroupBox { font-size: 13px; } ");
    
    mErrorYModeComboBoxVector.push_back(new QComboBox(form));
    mErrorYModeLayout = new QGridLayout(0);
    mErrorYModeLayout->setSpacing(0);
    
    mErrorYModePlusPushButton = new QPushButton(form);
    mErrorYModePlusPushButton->setText("+");
    mErrorYModePlusPushButton->setFixedWidth(mErrorYModePlusPushButton->height()+5);
    mErrorYModeMinusPushButton = new QPushButton(form);
    mErrorYModeMinusPushButton->setText("-");
    mErrorYModeMinusPushButton->setFixedWidth(mErrorYModeMinusPushButton->height()+5);
    
    mErrorYModeLayout->addWidget(mErrorYModeComboBoxVector[0], 0, 0, 1, 1);
    mErrorYModeLayout->addWidget(mErrorYModePlusPushButton, 0, 1, 1, 1);
    mErrorYModeLayout->addWidget(mErrorYModeMinusPushButton, 0, 2, 1, 1);
    groupBoxY->setLayout(mErrorYModeLayout);
    
    gridLayout->addWidget(groupBoxX, 0, 0, 1, 1);
    gridLayout->addWidget(groupBoxY, 1, 0, 1, 1);

    //
    //    Spacers
    //
    QSpacerItem *verticalSpacer = new QSpacerItem(20, 100, QSizePolicy::Minimum, QSizePolicy::Expanding);
    QSpacerItem *horizontalSpacer = new QSpacerItem(100, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
    
    gridLayout->addItem(horizontalSpacer, 0, 1, 1, 1);
    gridLayout->addItem(verticalSpacer, 2, 0, 1, 1);

    //
    //    Set text
    //
    mErrorXModeComboBoxVector[0]->clear();
    mErrorXModeComboBoxVector[0]->insertItems(0, QStringList()
                                              << tr("No Scan")
                                              << tr("Asymmetric")
                                              << tr("Symmetric (mean)")
                                              << tr("Symmetric (max)")
                                              );
    mErrorYModeComboBoxVector[0]->clear();
    mErrorYModeComboBoxVector[0]->insertItems(0, QStringList()
                                              << tr("No Scan")
                                              << tr("Asymmetric")
                                              << tr("Symmetric (mean)")
                                              << tr("Symmetric (max)")
                                              );
    
    //
    //   Connect +/= buttons to referring actions
    //
    connect(mErrorXModePlusPushButton, &QPushButton::clicked, this, [this](){this->addXErrorComboBox();});
    connect(mErrorYModePlusPushButton, &QPushButton::clicked, this, [this](){this->addYErrorComboBox();});
    connect(mErrorXModeMinusPushButton, &QPushButton::clicked, this, [this](){this->removeLastXErrorComboBox();});
    connect(mErrorYModeMinusPushButton, &QPushButton::clicked, this, [this](){this->removeLastYErrorComboBox();});

    //
    //  Connect first pull-down menus with consolidating update()
    //
    connect(mErrorXModeComboBoxVector[0], qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int){ this->update(); });
    connect(mErrorYModeComboBoxVector[0], qOverload<int>(&QComboBox::currentIndexChanged), this, [this](int){ this->update(); });

    //
    //   Tool tips
    //
    mErrorXModeComboBoxVector[0]->setToolTip(tr("Defines scan mode for error bars in x."));
    mErrorYModeComboBoxVector[0]->setToolTip(tr("Defines scan mode for error bars in y."));
    mErrorXModePlusPushButton->setToolTip(tr("Add additional x error bar scans."));
    mErrorYModePlusPushButton->setToolTip(tr("Add additional y error bar scans."));
    mErrorXModeMinusPushButton->setToolTip(tr("Remove additional x error bar scans."));
    mErrorYModeMinusPushButton->setToolTip(tr("Remove additional y error bar scans."));

    update();
}

void xyscanErrorBarScanModeToolBox::addXErrorComboBox()
{
    int nx = mErrorXModeComboBoxVector.size();

    mErrorXModeComboBoxVector.push_back(new QComboBox(mForm));
    mErrorXModeComboBoxVector[nx]->insertItems(0, QStringList()
                                               << tr("Asymmetric")
                                               << tr("Symmetric (mean)")
                                               << tr("Symmetric (max)")
                                               );
    mErrorXModeLayout->addWidget(mErrorXModeComboBoxVector[nx], nx, 0, 1, 1);
    update();
}

void xyscanErrorBarScanModeToolBox::addYErrorComboBox()
{
    int ny = mErrorYModeComboBoxVector.size();

    mErrorYModeComboBoxVector.push_back(new QComboBox(mForm));
    mErrorYModeComboBoxVector[ny]->insertItems(0, QStringList()
                                               << tr("Asymmetric")
                                               << tr("Symmetric (mean)")
                                               << tr("Symmetric (max)")
                                               );
    mErrorYModeLayout->addWidget(mErrorYModeComboBoxVector[ny], ny, 0, 1, 1);
    update();
}

void xyscanErrorBarScanModeToolBox::disable()
{
    mErrorXModePlusPushButton->setDisabled(true);
    mErrorYModePlusPushButton->setDisabled(true);
    mErrorXModeMinusPushButton->setDisabled(true);
    mErrorYModeMinusPushButton->setDisabled(true);

    for (int i=0; i<mErrorXModeComboBoxVector.size(); i++) mErrorXModeComboBoxVector[0]->setDisabled(true);
    for (int i=0; i<mErrorYModeComboBoxVector.size(); i++) mErrorYModeComboBoxVector[0]->setDisabled(true);
}

void xyscanErrorBarScanModeToolBox::enable()
{
    mErrorXModePlusPushButton->setEnabled(true);
    mErrorYModePlusPushButton->setEnabled(true);
    mErrorXModeMinusPushButton->setEnabled(true);
    mErrorYModeMinusPushButton->setEnabled(true);

    for (int i=0; i<mErrorXModeComboBoxVector.size(); i++) mErrorXModeComboBoxVector[0]->setEnabled(true);
    for (int i=0; i<mErrorYModeComboBoxVector.size(); i++) mErrorYModeComboBoxVector[0]->setEnabled(true);

    update();
}

xyscanErrorScanMode xyscanErrorBarScanModeToolBox::modeFromIndex(int idx, int i) const
{
    if (i>0) idx++;      // only the 1st has 'None' as option
    switch (idx) {
    case 3:
        return xyscanErrorScanMode::mMax;
        break;
    case 2:
        return xyscanErrorScanMode::mAverage;
        break;
    case 1:
        return xyscanErrorScanMode::mAsymmetric;
        break;
    case 0:
    default:
        return xyscanErrorScanMode::mNone;
        break;
    }
}

int xyscanErrorBarScanModeToolBox::numberOfXErrorScans() const
{
    int nx = mErrorXModeComboBoxVector.size();
    if (nx == 1 && mErrorXModeComboBoxVector[0]->currentIndex() == 0)  return 0; // 'None' selected
    return nx;
}

int xyscanErrorBarScanModeToolBox::numberOfYErrorScans() const
{
    int ny = mErrorYModeComboBoxVector.size();
    if (ny == 1 && mErrorYModeComboBoxVector[0]->currentIndex() == 0)  return 0; // 'None' selected
    return ny;
}

void xyscanErrorBarScanModeToolBox::removeLastXErrorComboBox()
{
    int nx = mErrorXModeComboBoxVector.size();
    if (nx > 1) {
        mErrorXModeLayout->removeWidget(mErrorXModeComboBoxVector[nx-1]);
        delete mErrorXModeComboBoxVector[nx-1];
        mErrorXModeComboBoxVector.removeLast();
    }
    update();
}

void xyscanErrorBarScanModeToolBox::removeLastYErrorComboBox()
{
    int ny = mErrorYModeComboBoxVector.size();
    if (ny > 1) {
        mErrorYModeLayout->removeWidget(mErrorYModeComboBoxVector[ny-1]);
        delete mErrorYModeComboBoxVector[ny-1];
        mErrorYModeComboBoxVector.removeLast();
    }
    update();
}

void xyscanErrorBarScanModeToolBox::reset()
{
    while (mErrorXModeComboBoxVector.size() != 1) removeLastXErrorComboBox();
    while (mErrorYModeComboBoxVector.size() != 1) removeLastYErrorComboBox();
    mErrorXModeComboBoxVector[0]->setCurrentIndex(0);
    mErrorYModeComboBoxVector[0]->setCurrentIndex(0);
}

xyscanErrorScanMode xyscanErrorBarScanModeToolBox::scanModeX(int i) const
{
    if (i > mErrorXModeComboBoxVector.size())    // out of bound
        return xyscanErrorScanMode::mNone;

    int k = mErrorXModeComboBoxVector[i]->currentIndex();
    return modeFromIndex(k, i);
}

xyscanErrorScanMode xyscanErrorBarScanModeToolBox::scanModeY(int i) const
{
    if (i > mErrorYModeComboBoxVector.size())    // out of bound
        return xyscanErrorScanMode::mNone;

    int k = mErrorYModeComboBoxVector[i]->currentIndex();
    return modeFromIndex(k, i);
}

void xyscanErrorBarScanModeToolBox::update()
{
    //
    //   Make sure the +/- signa are only available if it makes sense
    //
    mErrorXModePlusPushButton->setEnabled(numberOfXErrorScans() != 0);
    mErrorXModeMinusPushButton->setEnabled(numberOfXErrorScans() != 0);
    mErrorXModeMinusPushButton->setEnabled(numberOfXErrorScans() > 1);
    mErrorYModePlusPushButton->setEnabled(numberOfYErrorScans() != 0);
    mErrorYModeMinusPushButton->setEnabled(numberOfYErrorScans() != 0);
    mErrorYModeMinusPushButton->setEnabled(numberOfYErrorScans() > 1);

    //
    //  If there are more pull-down menus than the basic one we need to
    //  disable the 'None' item, otherwise we have holes in our lists.
    //
    auto model = dynamic_cast<QStandardItemModel*>(mErrorXModeComboBoxVector[0]->model());
    model->item(0, 0)->setEnabled(mErrorXModeComboBoxVector.size() == 1);
    model = dynamic_cast<QStandardItemModel*>(mErrorYModeComboBoxVector[0]->model());
    model->item(0, 0)->setEnabled(mErrorYModeComboBoxVector.size() == 1);
}
