//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/View/Numeric/NumberUtil.cpp
//! @brief     Implements GUIHelpers functions
//!
//! @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/Numeric/NumberUtil.h"
#include "Fit/Param/RealLimits.h"
#include "GUI/View/Numeric/ScientificSpinBox.h"
#include <QDoubleSpinBox>
#include <QLineEdit>
#include <cmath>

namespace {

//! Single step for QDoubleSpinBox.
double singleStep(int decimals)
{
    // For item with decimals=3 (i.e. 0.001) single step will be 0.1
    return 1. / std::pow(10., decimals - 1);
}

} // namespace


void GUI::View::NumberUtil::configScientificDoubleEdit(QLineEdit* edit, const RealLimits& limits)
{
    auto* validator = new QDoubleValidator(0.0, 1e200, 1000, edit);
    validator->setNotation(QDoubleValidator::ScientificNotation);

    const double minimum = limits.hasLowerLimit() ? std::max(limits.lowerLimit(), -1e200) : -1e200;
    const double maximum = limits.hasUpperLimit() ? std::min(limits.upperLimit(), +1e200) : +1e200;
    validator->setRange(minimum, maximum, 1000);

    edit->setValidator(validator);
}

void GUI::View::NumberUtil::configSpinbox(QDoubleSpinBox* spinBox, int decimals,
                                          const RealLimits& limits)
{
    spinBox->setMaximum(std::numeric_limits<double>::max());
    spinBox->setMinimum(std::numeric_limits<double>::lowest());

    if (limits.hasLowerLimit())
        spinBox->setMinimum(limits.lowerLimit());
    if (limits.hasUpperLimit())
        spinBox->setMaximum(limits.upperLimit());

    spinBox->setDecimals(decimals);
    spinBox->setSingleStep(singleStep(decimals));
}

void GUI::View::NumberUtil::configSpinbox(ScientificSpinBox* spinBox, int decimals,
                                          const RealLimits& limits)
{
    spinBox->setMaximum(std::numeric_limits<double>::max());
    spinBox->setMinimum(std::numeric_limits<double>::lowest());

    if (limits.hasLowerLimit())
        spinBox->setMinimum(limits.lowerLimit());
    if (limits.hasUpperLimit())
        spinBox->setMaximum(limits.upperLimit());

    spinBox->setDecimals(decimals);
    spinBox->setSingleStep(singleStep(decimals));
}
