//
// Created by Ht on 2019/8/8.
//

#ifndef JSONPROTOCOL_JRCOMMAND_H
#define JSONPROTOCOL_JRCOMMAND_H

#include <functional>

#include "JRDpBaseObj.h"
#include "JRPackage.h"
#include "JRParamTable.h"
#include <qlibc/ByteUtils.h>
#include <qlibc/QLogger.h>
#include "JRDpFieldTypes.h"


namespace jedp {


    static const char* vkey_dp_field = "@field";
    static const char* vkey_dp_checker = "@check";
    static const char* vkey_dp_index = "@index";
    static const char* vkey_dp_len = "@bitlen"; //支持用bit位长度描述各字段。
    static const char* sval_dp_end = "@end";

    static const char* vkey_dp_func = "@func";

	static const char* vkey_dp_endian = "@endian";

    static const char* vkey_def_fn = "@file";

    static const char* vkey_dp_type_key_suffix = ".types";
    static const char* vkey_data_type_default = "default";
    static const char* vkey_data_type_key = "typekey";

    /**
     *  Field的定义，描述字段相互之间的关系
     */

    class JRDpFieldDef;

    /**
     *  建立一扩充字节扩展Vector表:
     *      循环检验，每个项为1个字节或2个字节。如果为两个字节，则为大于，若为1个字节，则为
     */
    typedef std::map<QByte,QByte> QByteIndex;

    struct JE_API ByteRangeNode {
        QByte s;
        QByte e;
        QByte x;
    };

    JE_API typedef std::vector<ByteRangeNode>    QByteRange;

    class JE_API JRDpExpandableInfo {
        QByte mLeastLength;
        QByteIndex* mByteTransTable;     //单一字节表？
        QByteRange* mByteTransRange;     //字节范围表？
    public:
        //检查可扩展到的字节范围和抬头。
        explicit JRDpExpandableInfo(const QData& data, QByte leastByteLen);

        //判断一个字节是否为扩展字节
        QByte getExpandByteLength(QByte byte);

        QByte getExpandByteLength(const Json::Value& value);

        ~JRDpExpandableInfo();
    };

    class JE_API JRDpSizeIndexField {
    public:
        std::vector<JRDpFieldDef*>* indexedField;      //长度范围所描述的字段列表；
        JRDpFieldRangeType  rangeType;            //值描述类型，默认为 0-无类型
        inline explicit JRDpSizeIndexField() : indexedField(nullptr), rangeType(rangeTypeNull){}
    };

    class JE_API JRDpArrayValueField {
    public:
        size_t              mUnitSize;         //数组单元字节长度
        JRDpFieldValueType  mArrayUnitType;    //数组单元类型，原始类型或Object类型
        inline explicit JRDpArrayValueField() : mUnitSize(1) , mArrayUnitType(typeByte) {}
    };

    class JE_API JRDpFieldDef {
    public:
        string fieldKey;        //字段名 键值
        JRDpFieldOffsetType offsetType;           //偏移类型
        JRDpFieldValueType  valueType;            //值类型

        union {
            JROffsetDef* fixOffset;                   //固定偏移
            string* relaOffset;                       //相对偏移
        };

        union {
            JROffsetDef* fixSegaSize;        //固定长度
            string* varSegaSize;             //变动长度
        };

        union {
            JRParamTable        *mParamTable ;      //字段表
            QByte               *mBytes;            //固定值缓存
            JRDpArrayValueField *mArrayInfo;        //数组字段信息
            JRDpExpandableInfo  *mExpandable;
        };
        JRDpSizeIndexField  *mSizeIndexField;   //长度索引字段

    public:
        inline explicit JRDpFieldDef() :
                fixOffset(nullptr), fixSegaSize(nullptr), mBytes(nullptr), mSizeIndexField(nullptr) {
            offsetType = otypeNull;
            valueType = JRDpFieldTypeUtils::valueTypeOf(sval_type_default);
        }

        inline ~JRDpFieldDef(){
            switch (offsetType){
                case otypeCommon:
                    delete fixOffset;
                    delete fixSegaSize;
                    break;
                case otypeVar:
                    delete(fixOffset);
                    break;
                case otypeRelative:
                    delete fixSegaSize;
                    break;
                case otypeRelativeVar:
                    break;
                default:    //null ,nothing to do.
                    break;
            }
            if(mSizeIndexField!= nullptr) {
                if(mSizeIndexField->indexedField!=nullptr)
                    delete (mSizeIndexField->indexedField);
                delete mSizeIndexField;
            }
            if(valueType==typeTable)
                delete mParamTable;
            else if(valueType == typeFixBytes)
                delete mBytes;
            else if(valueType == typeArray)
                delete mArrayInfo;
            else if(valueType == typeExpandableInt)
                delete mExpandable;
        }

        //检查合法性
        inline bool isValid() {
            return true;
        }

        inline JRParamTable *getParamTable() {
            return mParamTable;
        }

        inline void appendParamTable(JRParamTable *pTable) {
            mParamTable = pTable;
        }

        inline bool isVarSegSize() const {
            return offsetType==otypeVar || offsetType==otypeRelativeVar || valueType == typeExpandableInt;
        }

        inline bool isRelaField() const {
            return offsetType == otypeRelative || offsetType == otypeRelativeVar;
        }

        inline size_t fieldByteSize() {
            return static_cast<size_t>((!isVarSegSize()) ? (fixSegaSize->offsetByte + (fixSegaSize->offsetBit > 0 ? 1 : 0)) : 0);
        }

        inline bool isExpansionField() const {
            return valueType == typeExpandableInt;
        }

        inline void checkExpantionSetup(const QData &data) {
            if(!data.isEmpty()) {   //如果有+标记，但是没有描述data，也不能作为Expandable字段处理
                valueType = typeExpandableInt;
                //目前最多从1个字节扩展到8个字节 ival_expandable_max_
                auto leastByte = fixSegaSize->byteSize();
                mExpandable = new JRDpExpandableInfo(data, leastByte);
            }
        }
    };


    using JEDPDecoderHandler = std::function <void (Json::Value& targetMsg, const unsigned char *buff, const size_t bufflen)>;

    using JEDPEncoderHandler = std::function <bool(const Json::Value &srcMsg, unsigned char **targetBuff, size_t &bufflen)>;

    using JEDPUserDecoderHandlerTable = std::unordered_map<string, JEDPDecoderHandler>;

    using JEDPUserEncoderHandlerTable = std::unordered_map<string, JEDPEncoderHandler>;


    //基本的解码器类
    class JE_API JRDpBaseCommandDecoder :
            public JRDpBaseObj {
    protected:
        JEDPUserDecoderHandlerTable*          mUddhTable;         // 用户自定义解码函数表
        JEDPUserEncoderHandlerTable*          mUdehTable;         // 用户自定义编码函数表
        std::string                           full_key_;
        std::string                           primary_key_;
        bool mValid = false;

    public:
        explicit JRDpBaseCommandDecoder(const QData& data, JEDPUserDecoderHandlerTable* uddh = nullptr, JEDPUserEncoderHandlerTable* udeh = nullptr);

        explicit JRDpBaseCommandDecoder(JEDPUserDecoderHandlerTable* uddh = nullptr, JEDPUserEncoderHandlerTable* udeh = nullptr);

        virtual bool isValid() const;

        virtual bool checkDataForFieldValid(qlibc::QData &data) {
            return true;
        };

        ~JRDpBaseCommandDecoder() override = default;

        /**
         *      编码package到缓冲区
         * @param msg
         * @param buff
         * @param bufflen
         * @return
         */
        virtual bool encodeBuffer(qlibc::QData &msg, QByte **buff, size_t &bufflen);

        /**
         *      解析缓冲区，生成对应的QData数据
         *
         * @param buff
         * @param bufflen
         * @param aPackage
         * @return
         */
        virtual bool decodeBuffer(const QByte* buff, size_t bufflen, JRPackage& aPackage);

        //获取变动字段的最小数据长度
        //用于判断需要解码的缓存长度是否满足最低要求
        virtual size_t getLeastFixDataSizeInBit() const;

        inline const std::string& getFullIndexKey() {
            return full_key_;
        }

        inline void setIndexFullKey(std::string &fullKey) {
            full_key_ = fullKey;
        }

        inline const std::string& getPrimaryKey() {
            return primary_key_;
        }

        inline void setPrimaryKey(const std::string &prKey) {
            primary_key_ = prKey;
        }

    };

    /**
     * 变化版
     */
    class JE_API JRDpUserDefineDecoder :
            public JRDpBaseCommandDecoder {
    protected:
        string encoderFuncKey;
        string decoderFuncKey;

    public:
        explicit JRDpUserDefineDecoder(const QStringList & funcTable, JEDPUserDecoderHandlerTable* uddh = nullptr, JEDPUserEncoderHandlerTable* udeh = nullptr);

        ~JRDpUserDefineDecoder() override = default;

        bool encodeBuffer(qlibc::QData &msg, unsigned char **buff, size_t &bufflen) override;

        bool decodeBuffer(const QByte *buff, size_t bufflen, JRPackage &aPackage) override;

    };


    class JE_API JRDpCommandDecoder :
            public JRDpBaseCommandDecoder {
    protected:
        qlibc::QPObjectHolder<JRDpFieldDef>              mFieldTable;    //子域索引表
        std::vector<JRDpFieldDef*>                       mFieldList;     //子域顺序表
        qlibc::QPObjectHolder<JRDpBaseCommandDecoder>
                                                         mSubDecorders;  //data解码器:两种寻址模式,一种是直接对字段进行索引,一种是对字段下的对象不同的值进行索引
        qlibc::QPObjectHolder<JRDpBaseCommandDecoder>
                                                         mSubDecordersHolder;  //data解码器列表
        qlibc::QPObjectHolder<JRDpFieldDef>              mSubDecordersPrimaryField;
                                                                         //data解码器的分类列表
        //data解码器的分类列表
        std::unordered_map<string, string>               mSubDataTypes;  //子数据块定义的消息类型
        std::unordered_map<string, std::vector<string>*> mSubDataPropers;//子数据块的键值Key序列

        size_t                                           mBaseLengthInBit = 0;  //基础长度，用于快速计算消息缓冲区长度
        const char*                                      checkCondition = nullptr;

        std::mutex build_m_;
    public:
        explicit JRDpCommandDecoder(QData &data, JEDPUserDecoderHandlerTable* uddh = nullptr, JEDPUserEncoderHandlerTable* udeh = nullptr);

        explicit JRDpCommandDecoder(QData &data, const string& payloadFieldKey, JEDPUserDecoderHandlerTable* uddh = nullptr, JEDPUserEncoderHandlerTable* udeh = nullptr);

        ~JRDpCommandDecoder() override ;

        void addExternalJedpCoder(qlibc::QData &data, const std::string& extKey="");

        jedp::JRParamTable *getParamTable(const string &propname);

		void checkEndianMode(const QData &data);

        void showDecoderInfo(QStringList &tacks, const string &nameTree, int depth, const string &greppedKey, bool showAll = false, Json::Value* logs = nullptr);

        //拷贝元数据中的字段到Package中
        void copyValues(QData &package, const QData &data) ;

        /**
         *      编码package到缓冲区
         * @param aPackage
         * @param buff
         * @param bufflen
         * @return
         */
        bool encodeBuffer(qlibc::QData &msg, unsigned char **buff, size_t &bufflen) override ;

        bool encodeBufferByPath(qlibc::QData &msg, QByte **buff, size_t &bufflen, const string& fieldPath);

        /**
         *      解析缓冲区，生成对应的QData数据
         *
         * @param buff
         * @param totalBuffLen
         * @param aPackage
         * @return
         */
        bool decodeBuffer(const QByte* buff, size_t totalBuffLen, JRPackage& aPackage) override;

        bool decodeBufferByPath(const QByte* buff, size_t totalBuffLen, JRPackage& aPackage, const string& fieldPath);

        //根据入口消息和简单路径,生成准确的调用路径
        void makeDecoderPath(std::string& fullPath, const std::string& path, qlibc::QData& req);

    protected:
        bool buildFieldDefTables(QData &data);

        //把bitlen的描述格式，转换为index格式
        static void transBitToIndex(const Json::Value &bitlen_ls, Json::Value &index_ls);
        //计算各字段的索引长度
        static void calculateOffset(const Json::Value &value, long *offsetByte, QByte *offsetBit);
        //检查索引描述长度字段
        static bool checkRangeIndex(const string& fieldKey, const string& rangeSign, std::unordered_map<string, string> &indexedFieldMap);
        //获取FieldKey
        static JRDpFieldRangeType getRealFieldKey(const string &orgFieldKey, string& fieldKey);

        static bool checkFieldDefValid(Json::Value& fieldList);

        /**
         * 检验offset的设定是否合法
         *
         * @param fieldList
         * @param indexList
         * @param offsetList
         * @return
         */
        static bool checkIndexDefValid(Json::Value&  fieldList, const Json::Value&  indexList, std::unordered_map<string,string>& indexedVarField, JROffsetList& offsetList);

        /**
         * 检验offset的设定是否保持增长。
         * @param byte
         * @param offset
         * @param byteOffset
         * @return
         */
        static bool checkByteOffsetIncreasing(long byte, QByte offset, JROffsetDef byteOffset);

        static bool checkValidFieldKey(const string &fieldKey);

    public:
        size_t getLeastFixDataSizeInBit() const override;

    protected:
        //检查是否一个字段描述了两个变长字段的长度。
        bool checkDualVarIndexedField();

        void checkFieldDecoderType(const QData &data);

        static void appendParamTable(const Json::Value &value, JRDpFieldDef *fieldDef);

        bool decodeFixedSizeBytes(JRDpFieldDef *pDef, const QByte *buff, size_t bufflen, size_t bitlen, JRPackage &aPackage);

        bool decodeVarSizeData(JRDpFieldDef *fldDef, const QByte *buff, size_t bufflen, size_t segSize, JRPackage &aPackage);

        JRDpCommandDecoder* appendDataDecoder(Json::Value def, JRDpFieldDef *field);

        void appendDataDecoders(const QData &data, const string& decoderdef, JRDpFieldDef *field);

        string getCurrentRuleFileName() const;

        JRDpBaseCommandDecoder *findDataDecoder(JRDpFieldDef *fldDef, const QData &data, int dupIndex = -1);

        JRDpBaseCommandDecoder *findMessageEncoder(JRDpFieldDef *field, const QData &data);

        void removeDecoder(const string &fieldKey);

        bool containsVarField();

        void makePrimaryKey(const string &fieldKey, const QData &data, string &targetKey);
        void makeOtherValKey(const string &fieldKey, const QData &data, string &targetKey);

        void setupDataDecoderTypes(const string& fieldKey, const Json::Value& typeList);

        void setupDataDecorderType(const string& fieldKey, const string &typeKey);

        /**
         *      设置特定Decoder中的属性值到每个Message中
         *
         * @param pDecoder
         * @param pDef
         * @param data
         */
        void setupDataValueProperties(JRDpBaseCommandDecoder *pDecoder, JRDpFieldDef *pDef, QData &data);

        bool encodeFixedSizeValue(const Json::Value& value, JRDpFieldDef *fldDef, QByte **buff, size_t byteLen, size_t *bitlen);

        size_t encodeVarSizeValue(std::unordered_map<string, QByte *>& packedBuffer, std::unordered_map<string, size_t >& varSizeMap,
                QData &value, JRDpFieldDef *fldDef, QByte **buff, size_t *bitlen);


        void updateCommonOffsetField(QByte *buff, size_t bufflen, const string &fieldKey, QByte *valueBuff,
                                     size_t valueBitLen);

        void releaseBuffers(std::unordered_map<string, QByte *>& map);

        virtual void makeBufferFromList(std::unordered_map<string, QByte *> &bufferMap, std::unordered_map<string, size_t> &varSizeMap,
                                unsigned char **buff, size_t buffLen);

        void resetSizeIndexField(std::unordered_map<string, QByte *> &bufferMap, std::unordered_map<string, size_t> &varSizeMap);

        void appendPropertiesKeyList(const string& fieldKey, const string& idxls);

        bool resetRelatedSizeField(std::unordered_map<string, QByte *> packBuffermap, JRDpFieldDef *fldDef, size_t sizeValue,
                                   size_t i);

        bool calculateVarSize(JRDpFieldDef* fieldDef, size_t lefSize, JRPackage &package, size_t *bitlen);

        static JRDpFieldValueType setArrayUnitType(const QData& defData, const string &strType);

        void debugShowVarMap(std::unordered_map<string, QByte *> &varMap,
                std::unordered_map<std::string, size_t > &sizeMap,
                std::size_t showByteSize = 6);

        JRDpBaseCommandDecoder* createSubDecoder(qlibc::QData& cmdDecorderData, JRDpFieldDef *field);

        void buildSubCoderItemToTable(qlibc::QData& data, QStringList& sIdxLs, JRDpFieldDef *field, JRDpFieldDef **idxTables);

        void buildMessageChecker();

        void addComposedSubDecoders(QStringList &fields, JRDpFieldDef *fieldDef, qlibc::QData &defVal);

        bool isDecoderDefValid(bool isComposed, const std::string& baseKey, QStringList &fields, qlibc::QData& def);

        void getOtherValKey(const string &primaryKey, QStringList &otherKeyList);

        bool appendMultiSubDecoder(bool isComposed, const std::string &baseKey,
                                   QStringList &indexKeys, qlibc::QData &defData);
    public:
        static void setShowEncoderMiddleBuffer(bool show);
        static bool getShowEncoderMiddleBuffer();

        bool checkDataForFieldValid(qlibc::QData &data) override;

        bool tryDecoderTilValid(JRDpBaseCommandDecoder *decoder, JRDpFieldDef *fldDef,
                                qlibc::QData &basePackage, const QByte *buff, size_t bufflen, JRPackage &aPackage);

    };
}

#endif //JSONPROTOCOL_JRCOMMAND_H
