//  ************************************************************************************************
//
//  BornAgain: simulate and fit reflection and scattering
//
//! @file      GUI/Application/ApplicationSettings.cpp
//! @brief     Implements class ApplicationSettings
//!
//! @homepage  http://www.bornagainproject.org
//! @license   GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2021
//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
//  ************************************************************************************************

#include "GUI/Application/ApplicationSettings.h"
#include "Base/Util/Assert.h"
#include <QApplication>
#include <QFile>
#include <QSettings>
#include <QStandardPaths>
#include <QStyle>
#include <QWidget>
namespace {

const QString S_CREATE_NEW_PROJECT_ON_STARTUP = "CreateNewProjectOnStartup";
const QString S_STYLE = "UiStyle";
const QString S_SIZE = "Size";
const QString S_POS = "Pos";
const QString S_DEFAULT_FUNCTIONALITIES = "DefaultFunctionalities";
const QString S_SINGLE_INSTRUMENT_MODE = "SingleInstrumentMode";
const QString S_SINGLE_SAMPLE_MODE = "SingleSampleMode";
const QString S_DEFAULT_UNIT_IS_ANGSTROM = "DefaultUnitIsAngstrom";

} // namespace

ApplicationSettings* appSettings; //!< global pointer to _the_ instance

ApplicationSettings::ApplicationSettings()
    : m_currentStyle(ApplicationSettings::Style::native)
{
    appSettings = this;
}

bool ApplicationSettings::useNativeFileDialog() const
{
#ifdef _WIN32
    return true;
#else
    return false;
#endif
}

bool ApplicationSettings::createNewProjectOnStartup() const
{
    return QSettings().value(S_CREATE_NEW_PROJECT_ON_STARTUP, false).toBool();
}

void ApplicationSettings::setCreateNewProjectOnStartup(bool b)
{
    QSettings().setValue(S_CREATE_NEW_PROJECT_ON_STARTUP, b);
}

ApplicationSettings::Style ApplicationSettings::styleToUse() const
{
    return static_cast<Style>(QSettings().value(S_STYLE, static_cast<int>(Style::native)).toInt());
}

void ApplicationSettings::setStyleToUse(Style style)
{
    QSettings().setValue(S_STYLE, static_cast<int>(style));
}

QVariant ApplicationSettings::defaultFunctionalities(const QVariant& absenceValue) const
{
    return QSettings().value(S_DEFAULT_FUNCTIONALITIES, absenceValue);
}

void ApplicationSettings::setDefaultFunctionalities(const QVariant& functionalities)
{
    QSettings().setValue(S_DEFAULT_FUNCTIONALITIES, functionalities);
}

bool ApplicationSettings::defaultIsSingleInstrumentMode() const
{
    return QSettings().value(S_SINGLE_INSTRUMENT_MODE, false).toBool();
}

void ApplicationSettings::setDefaultIsSingleInstrumentMode(bool b)
{
    QSettings().setValue(S_SINGLE_INSTRUMENT_MODE, b);
}

bool ApplicationSettings::defaultIsSingleSampleMode() const
{
    return QSettings().value(S_SINGLE_SAMPLE_MODE, false).toBool();
}

void ApplicationSettings::setDefaultIsSingleSampleMode(bool b)
{
    QSettings().setValue(S_SINGLE_SAMPLE_MODE, b);
}

bool ApplicationSettings::defaultUnitIsAngstrom() const
{
    return QSettings().value(S_DEFAULT_UNIT_IS_ANGSTROM, false).toBool();
}

void ApplicationSettings::setDefaultUnitIsAngstrom(bool b) const
{
    QSettings().setValue(S_DEFAULT_UNIT_IS_ANGSTROM, b);
}

void ApplicationSettings::saveWindowSizeAndPos(const QWidget* w)
{
    ASSERT(!w->objectName().isEmpty());
    QSettings settings;
    settings.setValue(S_SIZE + "/" + w->objectName(), w->size());
    settings.setValue(S_POS + "/" + w->objectName(), w->pos());
}

void ApplicationSettings::loadWindowSizeAndPos(QWidget* w)
{
    ASSERT(!w->objectName().isEmpty());

    QSettings settings;
    const QSize size = settings.value(S_SIZE + "/" + w->objectName(), QSize()).toSize();
    if (size.isValid())
        w->resize(size);
    if (settings.contains(S_POS + "/" + w->objectName()))
        w->move(settings.value(S_POS + "/" + w->objectName()).toPoint());
}

void ApplicationSettings::loadStyle(ApplicationSettings::Style style)
{
    QString stylesheet;

    switch (style) {
    case ApplicationSettings::Style::light: {
        QFile base(":/styles/Base.stylesheet");
        base.open(QFile::ReadOnly);
        QFile light(":/styles/Light.stylesheet");
        light.open(QFile::ReadOnly);
        stylesheet = base.readAll() + light.readAll();
        break;
    }
    case ApplicationSettings::Style::dark: {
        QFile base(":/styles/Base.stylesheet");
        base.open(QFile::ReadOnly);
        QFile dark(":/styles/Dark.stylesheet");
        dark.open(QFile::ReadOnly);
        stylesheet = base.readAll() + dark.readAll();
        break;
    }
    default: {
        QFile native(":/styles/Native.stylesheet");
        native.open(QFile::ReadOnly);
        stylesheet = native.readAll();
        break;
    }
    }

    m_currentStyle = style;
    m_styleSheetPalette = qApp->style()->standardPalette();

    // -- init palette for later usage; could be improved by parsing the stylesheet
    switch (m_currentStyle) {
    case ApplicationSettings::Style::light: {
        m_styleSheetPalette.setColor(QPalette::Text, Qt::black);
        m_styleSheetPalette.setColor(QPalette::WindowText, Qt::black);
        m_styleSheetPalette.setColor(QPalette::Base, Qt::white);
        m_styleSheetPalette.setColor(QPalette::AlternateBase, QColor(255, 255, 255).darker(105));
        m_styleSheetPalette.setColor(QPalette::Dark, QColor(255, 255, 255).darker(110));
        break;
    }
    case ApplicationSettings::Style::dark: {
        m_styleSheetPalette.setColor(QPalette::Text, QColor(213, 220, 223));
        m_styleSheetPalette.setColor(QPalette::WindowText, QColor(213, 220, 223));
        m_styleSheetPalette.setColor(QPalette::Base, QColor(43, 50, 54));
        m_styleSheetPalette.setColor(QPalette::AlternateBase, QColor(43, 50, 54).darker(130));
        m_styleSheetPalette.setColor(QPalette::Dark, QColor(43, 50, 54).darker(120));
        break;
    }
    default: {
        m_styleSheetPalette = qApp->style()->standardPalette();
        break;
    }
    }
    QApplication::setPalette(m_styleSheetPalette);
    qApp->setStyleSheet("");
    qApp->setStyleSheet(stylesheet);
}

ApplicationSettings::Style ApplicationSettings::currentStyle()
{
    return m_currentStyle;
}

const QPalette& ApplicationSettings::styleSheetPalette() const
{
    return m_styleSheetPalette;
}
