#ifndef LIBCONFIG_H
#define LIBCONFIG_H

#include <QObject>
#include <QList>
#include <QHash>
#include <QDir>

namespace Config {
    /**
     * @brief 配置文件解析过程异常
     */
    class ParseException: public std::exception
    {
    public:
        virtual QString reason() const = 0;
        virtual QString title() const = 0;
    };

    /**
     * @brief 配置读写交互端口
     */
    class Configration : public QObject
    {
    public:
        explicit Configration(QObject *parent);
        virtual ~Configration() = default;

        /**
         * @brief 载入配置文件
         * @param path 指定配置文件路径
         * @throw ParseException* 配置文件解析异常
         */
        virtual void loadFile(const QString &path) = 0;
        virtual QDir currentDir() const = 0;
        /**
         * @brief 保存配置内容会原始配置文件
         * @throws ParseException* 保存过程中异常
         */
        virtual void save() const = 0;

        virtual void deleteX(const QList<QString> &path) = 0;

        virtual void setConfig(const QList<QString> &path, const QString &value) = 0;
        virtual  QString getConfig(const QList<QString> &path) const = 0;

        virtual  void setList(const QList<QString> &path, const QList<QString> &list) = 0;
        virtual QList<QString> getList(const QList<QString> &path) const = 0;

        virtual void setMap(const QList<QString> &path, const QHash<QString, QString> &map) = 0;
        virtual QHash<QString,QString> getMap(const QList<QString> &path) const = 0;
    };



    class ConfigHelper
    {
    public:
        static QString getConfigAsDefault(Configration *ins, const QList<QString> &path, const QString & default_v)
        {
            auto xval = ins->getConfig(path);
            if(xval.trimmed() == ""){
                ins->setConfig(path, default_v);
                ins->save();
                xval = default_v;
            }
            return xval;
        }
        static QString getConfigAsDefaultSequence(QList<Configration*> seqs, const QList<QString> &path, const QString & default_v)
        {
            QString xval;
            for(auto &ins : seqs){
                if(!ins) continue;

                xval = ins->getConfig(path);
                if(xval.trimmed() != "")
                    break;
            }
            if(xval.trimmed() == ""){
                seqs.last()->setConfig(path, default_v);
                seqs.last()->save();
                xval = default_v;
            }

            return xval;
        }

        static QList<QString> getListAsDefault(Configration *ins, const QList<QString> &path, const QList<QString> & default_v)
        {
            auto xval = ins->getList(path);
            if(xval.size() == 0){
                ins->setList(path, default_v);
                ins->save();
                xval = default_v;
            }
            return xval;
        }
        static QList<QString> getListAsDefaultSequence(QList<Configration*> seqs, const QList<QString> &path, const QList<QString> & default_v)
        {
            QList<QString> xval;
            for(auto &ins : seqs){
                if(!ins) continue;

                xval = ins->getList(path);
                if(!xval.size())
                    break;
            }

            if(!xval.size()){
                seqs.last()->setList(path, default_v);
                seqs.last()->save();
                xval = default_v;
            }

            return xval;
        }

        static QHash<QString,QString> getHashAsDefault(Configration *ins, const QList<QString> &path, const QHash<QString, QString> & default_v)
        {
            auto xval = ins->getMap(path);
            if(xval.size()==0){
                ins->setMap(path, default_v);
                ins->save();
                xval = default_v;
            }
            return xval;
        }
        static QHash<QString,QString> getHashAsDefaultSequence(QList<Configration*> seqs, const QList<QString> &path, const QHash<QString, QString> & default_v)
        {
            QHash<QString, QString> xval;
            for(auto &ins : seqs){
                if(!ins) continue;

                xval = ins->getMap(path);
                if(!xval.size())
                    break;
            }

            if(!xval.size()){
                seqs.last()->setMap(path, default_v);
                seqs.last()->save();
                xval = default_v;
            }

            return xval;
        }

    };

    inline Configration::Configration(QObject *parent)
        : QObject(parent){}

}

#endif // LIBCONFIG_H
