//
//  QData.hpp
//  qlibcDev
//
//  Created by 胡涛 on 2017/11/15.
//  Copyright © 2017年 胡涛. All rights reserved.
//

#ifndef QData_hpp
#define QData_hpp

#include <stdio.h>
#ifdef __GNUC__
#include <unordered_map>
#else
#include <unordered_map>
#endif
#include "qlibc/StringUtils.hpp"

#include <json/json.h>
#include <jebase/config.h>

namespace qlibc {

    static Json::Value QNullValue;

    class QDataList;
    class QData;

    using QRData = std::shared_ptr<qlibc::QData>;
    using QRDataList = std::shared_ptr<qlibc::QDataList>;

    class JE_API QData {
    protected:
        Json::Value* _obj;

    public:
        QData();
        QData(const QData& data);
        virtual ~QData();

        explicit QData(const std::string& source);
        explicit QData(const Json::Value& val);
        explicit QData(const str_vector& sv);
        explicit QData(int argc,const char* argv[]);
        explicit QData(Json::Value& val);

        virtual void printValue() const;
        static void printValue(const Json::Value& val);

        virtual std::string getClassName() const ;

        qlibc::QData& operator = (const qlibc::QData& d);

        virtual bool isDataList() const {
            return false;
        }

        virtual bool isEmpty() const;

        std::string getClassType() const;

        virtual std::string getType() const;
        virtual void setType(const std::string& type);

        std::string getKey();
        void setKey(const std::string& key);


        virtual bool loadFromString(const std::string &str);
        virtual bool loadFromFile(const std::string& fn);
        virtual bool saveToFile(const std::string& fn, bool styled = false, const char* orders[] = nullptr);
        virtual bool saveToFile(const std::string& fn, const QStringList& orders, bool styled = false);

        void get(const std::string& key,Json::Value& ret) const ;
        virtual qlibc::QData& put(const std::string& key, const Json::Value& val);
        qlibc::QData& put(const std::string& key, Json::Value* val);

        //
        //         virtual void putDataItem(const std::string& key, QData* data);
        //         virtual QData* getDataItem(const std::string& key);

        virtual void toJSONString(std::string& ret,bool lret = false) const;
        virtual std::string toJSONString(bool lret = false) const ;
        virtual std::string toParaString() const;
        virtual std::string toParaString(const std::string& keylist) const;

        virtual void initWithParaList(str_vector vl);

        virtual void initWithJsonStr(const std::string& str);

        bool getBool(const std::string& key) const;
        bool getBool(const std::string& key,bool defVal) const;

        virtual QData&  setBool(const std::string&key, bool val);

        int getInt(const std::string& key) const;
        int getInt(const std::string& key, int defVal) const;

        virtual QData&  setInt(const std::string& key, int val);

        std::string getString(const std::string& key) const;
        std::string getString(const std::string& key,const std::string& defVal) const;

        std::string removeString(const std::string& key);

        virtual QData& setString(const std::string& key, const std::string& val);
        virtual QData& putString(const std::string& key, const std::string& val);

        void putData(const std::string& key, const QData& data);
        QData getData(const std::string& key) const;
        void getData(const std::string& key, QData& data) const;
        QData getObjFmtData(const std::string& key) const;
        void getObjFmtData(const std::string& key, QData& data) const;
        QData& putObjFmtData(const std::string& key, const QData& data);

        std::string getObjFmtString(const std::string& key) const;
        std::string getObjFmtString(const std::string& key, const std::string& defVal) const;
        void getObjFmtString(const std::string& key, std::string& target) const;
        void getObjFmtString(const std::string& key, std::string target, const std::string& defVal) const;
        virtual QData& putObjFmtString(const std::string& key, const std::string& value);

        virtual QData& clearObjFmtKey(const std::string& key);
        virtual QData& removeObjFmtKey(const std::string& key);

        Json::Value getObjFmtValue(const std::string& key) const;
        void getObjFmtValue(const std::string& key, Json::Value& v) const;
        virtual QData& putObjFmtValue(const std::string& key, const Json::Value& value);
        virtual void copyObjFmtValue(const QData& src, const std::string& key);

        int getObjFmtInt(const std::string& key, int defVal = -1) const;
        virtual QData& setObjFmtInt(const std::string& key, int value);

        virtual QData& setValue(const std::string& key, const Json::Value& val);
        Json::Value getValue(const std::string& key) const;
        void getValue(const std::string& key,Json::Value& val) const;

        void removeKey(const std::string& key);

        virtual void clear();

        virtual QData&  setInitData(const QData& data);
        virtual QData&  setInitValue(const Json::Value& value);

        QData& updateDataIfExist(const QData& data);
        QData& appendData(const QData& data);

        void getDataList(const std::string& key, QDataList& ret) const ;
        void getObjectData(const std::string& key,QData& data) const ;

        QStringList getMemberNames() const;
        virtual std::string getName() const;

        virtual qlibc::QData& setName(const std::string& name);

        virtual const Json::Value &asValueConst() const;

        virtual Json::Value &asValue();

        static void copyValue(Json::Value& target, const Json::Value &source, const std::string &keylist);
        virtual QData&  copyDataFromValue(const Json::Value &data);
        virtual QData&  copyData(const qlibc::QData &data);
        virtual QData&  copyData(const qlibc::QData &data, const std::string& key);
        virtual QData&  copyDataIfNotExists(const Json::Value &val);
        virtual QData&  copyDataIfNotExists(const qlibc::QData &data);
        //变参最后一个必须为nullptr
        virtual QData&  copyData(const qlibc::QData &data, const char* key, ...);
        virtual QData&  copyDataNotStartWith(const qlibc::QData &data, char start);
        virtual QData&  copyDataNotStartWith(const qlibc::QData &data, const std::string& start);
        virtual QData&  copyDataStartWith(const qlibc::QData &data, char start);
        virtual QData&  copyDataStartWith(const qlibc::QData &data, const std::string& start);

        static void clearValueStartWith(Json::Value& val, const std::string& start);
        static void clearValueNotStartWith(Json::Value& val, const std::string& start);

        virtual QData&  clearDataStartWith(const std::string& start);
        virtual QData&  clearDataNotStartWith(const std::string& start);

        virtual QData&  expandCompactedField();
        virtual QData&  compactField(const std::string& field);

        bool containsKey(const char *key) const;
        bool containsKey(const std::string& key) const;

        static QData fromObject(const Json::Value& var);

        static QData& fromObject(QData &data, const Json::Value& var);

        static QData fromFile(const std::string& filename);

        static QData& fromFile(QData &data, const std::string& filename);

        static QData fromString(const std::string& js);

        static QData& fromString(QData &data, std::string s);

        Json::Value& getObjectValue(const std::string& k){
            if(_obj== nullptr) _obj=new Json::Value;
            if(!_obj->isMember(k)) _obj->operator[](k) = Json::nullValue;
            return _obj->operator[](k);
        }

        Json::Value* getValueRef(const std::string& k){
            if(_obj== nullptr) return nullptr;
            if(!_obj->isMember(k)) return nullptr;
            return &_obj->operator[](k);
        }

        Json::Value* getObjFmtValueRef(const std::string& k) const {
            return doGetObjFmtValueRef(*_obj, k);
        }

    protected:
        static int parseArrayIndex(const std::string &source, std::string &sub_key);

        //Json复杂语法处理工具代码
        static void tryExpandField(Json::Value &target, const std::string& k, std::string& v);

        static void doExpandValue(Json::Value &target);
        static bool isFmtKey(const std::string &key);

        static int getLastFmtKey(std::string &fmtKey, std::string& lastkey);

        static int getNextFmtKey(std::string &curKey, std::string& leftkey);

        static Json::Value* getOpRefObjFmtValue(Json::Value &target, const std::string &fmtKey);

        static void copyPropertyByAppendding(Json::Value &target, const Json::Value &source, const std::string &key);
        static void copySimplePropertyByAppendding(Json::Value &target, const Json::Value &source, const std::string &key);

        static void doDelObjFmtKey(Json::Value &target, const std::string &fmtKey);

        static bool doPutObjFmtValue(Json::Value &target, const std::string &fmtKey, const Json::Value &v);

        static const Json::Value& doGetObjFmtValueConst(const Json::Value &target, const std::string &fmtKey, Json::Value &v);
        static const Json::Value& doGetObjFmtValueConst(const Json::Value &target, const std::string &fmtKey, Json::Value &v,  const Json::Value &defVal);

    public:
        static Json::Value* doGetObjFmtValueRef(Json::Value &target, const std::string &fmtKey);

        void clearNullFields();
    };

#define DLog(qd)  ULog(qlibc::QLT_Log, "[%s%s%s]=%s", qlog_light_cyan, #qd, qlog_none, (qd).toJSONString(true).c_str())
#define DPLog(qd)  ULog(qlibc::QLT_Log, "[%s%s%s]=%s", qlog_light_cyan, #qd, qlog_none, (qd)->toJSONString(true).c_str())
#define DDLog(qd)  QDLog("[%s%s%s]=%s", qlog_light_cyan, #qd, qlog_none, (qd).toJSONString(true).c_str())
#define DDPLog(qd)  QDLog("[%s%s%s]=%s", qlog_light_cyan, #qd, qlog_none, (qd)->toJSONString(true).c_str())
#define DLogMsg(qd,msg)  ULog(qlibc::QLT_Log, "[%s%s%s(%s)]=%s", qlog_light_cyan, #qd, qlog_none, msg, (qd).toJSONString(true).c_str())
#define DPLogMsg(qd,msg)  ULog(qlibc::QLT_Log, "[%s%s%s(%s)]=%s", qlog_light_cyan, #qd, qlog_none, msg, (qd)->toJSONString(true).c_str())
#define VLog(v)  ULog(qlibc::QLT_Log, "[%s%s%s]=%s", qlog_light_cyan, #v, qlog_none, StringUtils::valueToJsonString(v).c_str())
#define VLogMsg(v,msg)  ULog(qlibc::QLT_Log, "[%s%s%s]=%s", qlog_light_cyan, #v, qlog_none, msg, StringUtils::valueToJsonString(v).c_str())
#define VDLog(v)  QDLog("[%s%s%s]=%s", qlog_light_cyan, #v, qlog_none, StringUtils::valueToJsonString(v).c_str())
#define VDLogMsg(v,msg)  QDLog("[%s%s%s]=%s", qlog_light_cyan, #v, qlog_none, msg, StringUtils::valueToJsonString(v).c_str())

}

#endif /* QData_hpp */
