//
// Created by Ht on 2021/5/31.
//

#ifndef INC_0_LIBDEVCPP_JACONDEXPR_H
#define INC_0_LIBDEVCPP_JACONDEXPR_H

/**
 * 计算条件参数
 */
#include <mutex>
#include <utility>
#include <qlibc/qlibc.h>


namespace ja {
    static const char* ja_object_val_null_ = "$null";

    using JACondVarSetter = std::function<Json::Value*(const std::string& key, Json::Value& val)>;

#define JACondVarSetterDef(k,v) \
    (const std::string& k, Json::Value& v) -> Json::Value*

    class JE_API JACondVar {
    protected:
        bool isVar = false;
        union {
            Json::Value *val_ = nullptr;
            std::string *var_key_;
        };
    public:
        explicit JACondVar() {}

        virtual ~JACondVar() {
            if(isVar)
                delete var_key_;
            else
                delete val_;
        }

        static Json::Value *makeJsonValueFromString(const std::string &valStr);

        void makeBaseCondValue(const std::string &value);

        //变量格式：${var}
        virtual inline bool isCondVar(const std::string &value) {
            return value.size()>2 && value[0] == '$' && value[1] == '{' && *value.rbegin() == '}';
        }

        virtual inline std::string* getVarKey(const std::string &varExpr) {
            return new std::string(varExpr.substr(2, varExpr.size()-3));
        }

        virtual bool getConstExprResult(std::string& err);

        virtual bool getCalExprResult(std::string& err, const JACondVarSetter* setter);

        static bool CondValOfValue(const Json::Value &value);


    };

    /**
     * 基本的运算函数
     *      主要是值比较
     *
     */
    enum JACondValOpr {
        JACVO_NONE = 0,                 // 表达式是一个单值
        JACVO_EQUAL,                    // ==
        JACVO_NOT_EQUAL,                // !=
        JACVO_GREAT_THAN,               // >
        JACVO_SMALL_THAN,               // <
        JACVO_GREAT_THAN_OR_EQUAL,      // >=
        JACVO_SMALL_THAN_OR_EQUAL       // <=
    };


    //值比较问题：
    //  JsonValue的值比较
    //  字符串的值比较
    class JE_API JACondExpr : public JACondVar {
    protected:
        JACondValOpr val_opr_ = JACVO_NONE;
        bool isSecVar = false;
        union {
            Json::Value *second_;
            std::string *sec_key_= nullptr;
        };

    public:
        //空表达式
        explicit JACondExpr() : JACondVar() {}

        virtual bool handleUdExpr(char type, const std::string &param);

//单一值的表达式
        explicit JACondExpr(const std::string& strExpr);

        ~JACondExpr() override;

        bool getCalExprResult(std::string& err, const JACondVarSetter* setter) override;

        void makeSecondCondValue(string &value);
    };

    enum JACondBoolOpr {
        JACBO_NONE = 0,     // 单表达式
        JACBO_NOT,          // ! / not
        JACBO_AND,          // &&
        JACBO_OR,           // ||
    };


    class JE_API ExprSubBraceSearcher {
    protected:
        std::string var_sign_;

    public:
        static const int MIN_INCREASE_SIZE = 32;
        int len;
        int base = 0;
        int start = 0;
        int current = 0;

        const char* src_buff;
        const std::string& src;

        std::string currentKey;

        char* buff;
        int temp_len;
        bool curr_nested_;

    protected:
        //拷贝 start -> current to base
        inline void copyConsts();

        inline void makeSureBufferSizeSpace(unsigned long size);

    public:
        explicit ExprSubBraceSearcher(const std::string &target, const std::string& vSign="");

        ~ExprSubBraceSearcher();


        inline bool copyValue(const std::string &value);

        /**
        * 显示指定位置的指定长度的错误代码，便于检查代码错误。
         * @param msg     消息提示
         * @param idx     消息指向内容在源码中的位置
         * @param msgLen  显示长度，最小为5
         * @param type    消息类型： 0-错误， 1-警告， 2-日志
         */
        inline void showSrcMsgAt(const char* msg, unsigned long idx, unsigned short type = 0, unsigned short msgLen = 16);
        /**
         *  算法：
         *      搜索变量开始标志，检索结束标志，
         *          复检key中的(个数，如果存在多个，则再检索匹配对应个数的)，如果失败，则：
         *
         *      算法，
         *          从start开始扫描，发现一个(则入栈，记录current， 发现一个)则出栈，记录end_，
         *          直到src结束，或发现)时栈清空，
         *          拷贝current及end，并且如果(曾经大于1，则嵌套为真
         *
         *      未处理转义
         *
         * @return
         */
        inline bool findNextVar();

        inline void copyRest();

        inline bool isCurrentNested() {
            return curr_nested_;
        }
    };

    //将目标串，更换为一个符号子串
    using JABraceSubHandler = std::function<void(const std::string& key, std::string& val)>;

    class JE_API JACondExprGroup : public JACondExpr {
    public:
        //空表达式
        explicit JACondExprGroup() : JACondExpr() {};

    protected:
        //单一原子表达式
        explicit JACondExprGroup(const std::string &singleExpr);

        //非表达式组合
        explicit JACondExprGroup(JACondBoolOpr opr, const std::string &singleExpr);
        explicit JACondExprGroup(JACondBoolOpr opr, JACondExprGroup *targetGroup);  //用于做Not处理的

        //或、与表达式组合
        explicit JACondExprGroup(JACondBoolOpr opr, const QStringList &exprList);

        JACondBoolOpr bool_opr_;
        std::vector<JACondExpr*>*  exprs_ = nullptr;

    public:

        bool getCalExprResult(std::string& err, const JACondVarSetter* setter) override;

        static bool handleBracesSubStr(std::string& dest, bool* nested_, const std::string &expr, const JABraceSubHandler& handler,
                const std::string& vSign="", bool* perr = nullptr);

        static std::string makeSubReplaceRef();

        static JACondExprGroup* parseStaticCondExpr(const std::string &condExpr);

#ifdef DEBUG
    protected:
        std::string org_expr_;
        void setOrginalExpr(const std::string& expr) {
            org_expr_ = expr;
        }
#endif
    };
}


#endif //INC_0_LIBDEVCPP_JACONDEXPR_H
