/****************************************************************************
 ** ScStw Libraries
 ** Copyright (C) 2020  Itsblue development
 **
 ** This program is free software: you can redistribute it and/or modify
 ** it under the terms of the GNU General Public License as published by
 ** the Free Software Foundation, either version 3 of the License, or
 ** (at your option) any later version.
 **
 ** This program is distributed in the hope that it will be useful,
 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ** GNU General Public License for more details.
 **
 ** You should have received a copy of the GNU General Public License
 ** along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ****************************************************************************/

#ifndef SCSTWSETTINGS_H
#define SCSTWSETTINGS_H

#include <QObject>
#include <QVariant>
#include <QMetaEnum>
#include <QtDebug>
#include <QFile>
#include <QStandardPaths>
#include <QJsonDocument>
#include <ScStw.hpp>
#include <QDir>
#include <scstwsetting.h>

class ScStwSettings : public QObject
{
    Q_OBJECT
public:
    explicit ScStwSettings(QObject *parent = nullptr, bool overwriteFileOnErrors = true);

    typedef QString(*keyToStringConverter)(int);
    typedef QVariant::Type(*keyToTypeConverter)(int);

    /*!
     * \brief The BaseStationSetting enum contains all settings of the base station that can be changed by a client
     *
     * \see ScStw::baseStationSettingFromInt()
     * \see ScStw::baseStationSettingToString()
     * \see ScStw::baseStationSettingFromString()
     * \see ScStw::baseStationSettings
     */
    enum BaseStationSetting {
        InvalidSetting = -1,
        ReadySoundEnableSetting,
        ReadySoundDelaySetting,
        AtYourMarksSoundEnableSetting,
        AtYourMarksSoundDelaySetting,
        SoundVolumeSetting,
        CompetitionModeSetting
    };
    Q_ENUM(BaseStationSetting)

    enum KeyLevelEnum {
        KeyLevel = 0
    };
    Q_ENUM(KeyLevelEnum)

    virtual QVariant readSetting(BaseStationSetting key);
    Q_INVOKABLE virtual QVariant readSetting(int key, int keyLevel);
    virtual bool writeSetting(BaseStationSetting key, QVariant value);
    Q_INVOKABLE virtual bool writeSetting(int key, int keyLevel, QVariant value);
    virtual bool setDefaultSetting(BaseStationSetting key, QVariant defaultValue);
    Q_INVOKABLE virtual bool setDefaultSetting(int key, int keyLevel, QVariant defaultValue);

    Q_INVOKABLE ScStwSetting * getSetting(int key, int keyLevel);

    static BaseStationSetting keyFromInt(int i) {
        QMetaEnum enumeration = QMetaEnum::fromType<BaseStationSetting>();
        return static_cast<BaseStationSetting>(enumeration.keyToValue(enumeration.valueToKey(i)));
    }

    static QString keyToString(int key) {
        return QMetaEnum::fromType<BaseStationSetting>().valueToKey(key);
    }

    static QVariant::Type keyToType(int key) {
        QMap<BaseStationSetting, QVariant::Type> types = {
            {ReadySoundEnableSetting, QVariant::Bool},
            {ReadySoundDelaySetting, QVariant::Double},
            {AtYourMarksSoundEnableSetting, QVariant::Bool},
            {AtYourMarksSoundDelaySetting, QVariant::Double},
            {SoundVolumeSetting, QVariant::Double},
            {CompetitionModeSetting, QVariant::Bool}
        };

        if(types.contains(BaseStationSetting(key)))
            return types[BaseStationSetting(key)];

        return QVariant::Invalid;
    }

protected:
    virtual QVariant readSetting(QString key, int keyInt = -1, int keyLevel = -1);
    virtual bool writeSetting(QString key, QVariant value, int keyInt = -1,int keyLevel = -1);
    virtual bool setDefaultSetting(QString key, QVariant defaultValue, int keyInt,int keyLevel = -1);
    bool registerKeyLevelConverters(int keyLevel, keyToStringConverter, keyToTypeConverter);

private:
    bool fileIsReadonly;

    QFile * settingsFile;
    QVariantMap settingsCache;

    bool loadSettingsFromFile();

    QMap<int, keyToStringConverter> keyToStringConverters;
    QMap<int, keyToTypeConverter> keyToTypeConverters;
    QMap<int, QMap<int, ScStwSetting*>> internalSettingHandlers;

private slots:
    bool writeSettingsToFile();

signals:
    void settingChanged(int key, int keyLevel, QVariant value);

};

#endif // SCSTWSETTINGS_H
