/*
    SPDX-FileCopyrightText: 2014-2023 Anne Jan Brouwer <brouwer@annejan.com>
    SPDX-FileCopyrightText: 2018 Lukas Vogel <lukedirtwalker@gmail.com>
    SPDX-FileCopyrightText: 2018 Claudio Maradonna <penguyman@stronzi.org>
    SPDX-FileCopyrightText: 2022 Tobias Leupold <tl@l3u.de>
    SPDX-FileCopyrightText: 2023 g10 Code GmbH
    SPDX-FileContributor: Sune Stolborg Vuorela <sune@vuorela.dk>

    SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "settings.h"

#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QString>

/*!
    \class SettingsConstants
    \brief Table for the naming of configuration items
*/
namespace SettingsConstants
{
#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
constexpr QLatin1String version("version");
constexpr QLatin1String useAutoclear("useAutoclear");
constexpr QLatin1String autoclearSeconds("autoclearSeconds");
constexpr QLatin1String useAutoclearPanel("useAutoclearPanel");
constexpr QLatin1String autoclearPanelSeconds("autoclearPanelSeconds");
constexpr QLatin1String displayAsIs("displayAsIs");
constexpr QLatin1String noLineWrapping("noLineWrapping");
constexpr QLatin1String passStore("passStore");
constexpr QLatin1String profile("profile");
constexpr QLatin1String passwordLength("passwordLength");
constexpr QLatin1String passwordCharsselection("passwordCharsselection");
constexpr QLatin1String passTemplate("passTemplate");
constexpr QLatin1String useTemplate("useTemplate");
constexpr QLatin1String templateAllFields("templateAllFields");
#else
static const QLatin1String version("version");
static const QLatin1String useAutoclear("useAutoclear");
static const QLatin1String autoclearSeconds("autoclearSeconds");
static const QLatin1String useAutoclearPanel("useAutoclearPanel");
static const QLatin1String autoclearPanelSeconds("autoclearPanelSeconds");
static const QLatin1String displayAsIs("displayAsIs");
static const QLatin1String noLineWrapping("noLineWrapping");
static const QLatin1String passStore("passStore");
static const QLatin1String profile("profile");
static const QLatin1String passwordLength("passwordLength");
static const QLatin1String passwordCharsselection("passwordCharsselection");
static const QLatin1String passTemplate("passTemplate");
static const QLatin1String useTemplate("useTemplate");
static const QLatin1String templateAllFields("templateAllFields");
#endif
};

bool Settings::initialized = false;

Settings *Settings::m_instance = nullptr;
Settings *Settings::getInstance()
{
    if (!Settings::initialized) {
        QString portable_ini = QCoreApplication::applicationDirPath() + QStringLiteral("/gnupgpass.ini");
        if (QFile(portable_ini).exists()) {
            m_instance = new Settings(portable_ini, QSettings::IniFormat);
        } else {
            m_instance = new Settings();
        }

        initialized = true;
    }

    return m_instance;
}

PasswordConfiguration Settings::getPasswordConfiguration()
{
    PasswordConfiguration config;

    config.length = getInstance()->value(SettingsConstants::passwordLength, 0).toInt();
    config.selected = static_cast<PasswordConfiguration::characterSet>(getInstance()->value(SettingsConstants::passwordCharsselection, 0).toInt());

    return config;
}

void Settings::setPasswordConfiguration(const PasswordConfiguration &config)
{
    getInstance()->setValue(SettingsConstants::passwordLength, config.length);
    getInstance()->setValue(SettingsConstants::passwordCharsselection, config.selected);
}

QHash<QString, QString> Settings::getProfiles()
{
    getInstance()->beginGroup(SettingsConstants::profile);

    const QStringList childrenKeys = getInstance()->childKeys();
    QHash<QString, QString> profiles;
    for (const QString &key : childrenKeys) {
        profiles.insert(key, getInstance()->value(key).toString());
    }

    getInstance()->endGroup();

    return profiles;
}

void Settings::setProfiles(const QHash<QString, QString> &profiles)
{
    getInstance()->remove(SettingsConstants::profile);
    getInstance()->beginGroup(SettingsConstants::profile);

    QHash<QString, QString>::const_iterator i = profiles.begin();
    for (; i != profiles.end(); ++i) {
        getInstance()->setValue(i.key(), i.value());
    }

    getInstance()->endGroup();
}

QString Settings::getVersion(const QString &defaultValue)
{
    return getInstance()->value(SettingsConstants::version, defaultValue).toString();
}
void Settings::setVersion(const QString &version)
{
    getInstance()->setValue(SettingsConstants::version, version);
}

bool Settings::isUseAutoclear(const bool &defaultValue)
{
    return getInstance()->value(SettingsConstants::useAutoclear, defaultValue).toBool();
}
void Settings::setUseAutoclear(const bool &useAutoclear)
{
    getInstance()->setValue(SettingsConstants::useAutoclear, useAutoclear);
}

int Settings::getAutoclearSeconds(const int &defaultValue)
{
    return getInstance()->value(SettingsConstants::autoclearSeconds, defaultValue).toInt();
}
void Settings::setAutoclearSeconds(const int &autoClearSeconds)
{
    getInstance()->setValue(SettingsConstants::autoclearSeconds, autoClearSeconds);
}

bool Settings::isUseAutoclearPanel(const bool &defaultValue)
{
    return getInstance()->value(SettingsConstants::useAutoclearPanel, defaultValue).toBool();
}
void Settings::setUseAutoclearPanel(const bool &useAutoclearPanel)
{
    getInstance()->setValue(SettingsConstants::useAutoclearPanel, useAutoclearPanel);
}

int Settings::getAutoclearPanelSeconds(const int &defaultValue)
{
    return getInstance()->value(SettingsConstants::autoclearPanelSeconds, defaultValue).toInt();
}
void Settings::setAutoclearPanelSeconds(const int &autoClearPanelSeconds)
{
    getInstance()->setValue(SettingsConstants::autoclearPanelSeconds, autoClearPanelSeconds);
}

bool Settings::isDisplayAsIs(const bool &defaultValue)
{
    return getInstance()->value(SettingsConstants::displayAsIs, defaultValue).toBool();
}
void Settings::setDisplayAsIs(const bool &displayAsIs)
{
    getInstance()->setValue(SettingsConstants::displayAsIs, displayAsIs);
}

bool Settings::isNoLineWrapping(const bool &defaultValue)
{
    return getInstance()->value(SettingsConstants::noLineWrapping, defaultValue).toBool();
}
void Settings::setNoLineWrapping(const bool &noLineWrapping)
{
    getInstance()->setValue(SettingsConstants::noLineWrapping, noLineWrapping);
}

QString Settings::getPassStore(const QString &defaultValue)
{
    QString returnValue = getInstance()->value(SettingsConstants::passStore, defaultValue).toString();

    // Normalize the path string
    returnValue = QDir(returnValue).absolutePath();

    // ensure directory exists if never used pass or misconfigured.
    // otherwise process->setWorkingDirectory(passStore); will fail on execution.
    if (!QDir(returnValue).exists()) {
        QDir().mkdir(returnValue);
    }

    // ensure path ends in /
    if (!returnValue.endsWith(QLatin1Char('/'))) {
        returnValue += QLatin1Char('/');
    }

    return returnValue;
}
void Settings::setPassStore(const QString &passStore)
{
    getInstance()->setValue(SettingsConstants::passStore, passStore);
}

QString Settings::getProfile(const QString &defaultValue)
{
    return getInstance()->value(SettingsConstants::profile, defaultValue).toString();
}
void Settings::setProfile(const QString &profile)
{
    getInstance()->setValue(SettingsConstants::profile, profile);
}

void Settings::setPasswordLength(const int &passwordLength)
{
    getInstance()->setValue(SettingsConstants::passwordLength, passwordLength);
}
void Settings::setPasswordCharsselection(const int &passwordCharsselection)
{
    getInstance()->setValue(SettingsConstants::passwordCharsselection, passwordCharsselection);
}

QString Settings::getPassTemplate(const QString &defaultValue)
{
    return getInstance()->value(SettingsConstants::passTemplate, defaultValue).toString();
}
void Settings::setPassTemplate(const QString &passTemplate)
{
    getInstance()->setValue(SettingsConstants::passTemplate, passTemplate);
}

bool Settings::isUseTemplate(const bool &defaultValue)
{
    return getInstance()->value(SettingsConstants::useTemplate, defaultValue).toBool();
}
void Settings::setUseTemplate(const bool &useTemplate)
{
    getInstance()->setValue(SettingsConstants::useTemplate, useTemplate);
}

bool Settings::isTemplateAllFields(const bool &defaultValue)
{
    return getInstance()->value(SettingsConstants::templateAllFields, defaultValue).toBool();
}
void Settings::setTemplateAllFields(const bool &templateAllFields)
{
    getInstance()->setValue(SettingsConstants::templateAllFields, templateAllFields);
}
