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

#ifndef INC_0_LIBDEVCPP_JABASEDOM_H
#define INC_0_LIBDEVCPP_JABASEDOM_H


#include <qlibc/QTimerEngine.h>
#include <qlibc/QObjectEventHolder.h>

#include <utility>
#include <qlibc/QTriggerUtil.h>

#include "JADataTemplate.h"
#include "JAUtil.h"


namespace ja {

    /**
     * Action变量池
     *      分为变量、函数、和对象三种。Method属于对象。
     *      除函数外，仅仅持有访问通道、并不保持。
     *
     */

    static const char* sval_cls_name_object = "object";
    static const char* sval_cls_name_class = "class";
    static const char* sval_cls_name_owner = "owner";


    static const char* vkey_stored_owner_ = "_ow";

    /**
     * 用于将可能被释放的脚本中的handler保存下来，主要用于回调时使用
     *      重复或清理时将自动释放
     */
    class JE_API JAHandlerDocker {
    protected:
        std::shared_ptr<qlibc::QSharedObjectHolder<ja::JAHandler>> mHandlers_ = nullptr;
        std::shared_ptr<qlibc::QSharedObjectHolder<ja::JAHandler>>& handlerHolder() {
            if(mHandlers_ == nullptr)
                mHandlers_ = std::make_shared<qlibc::QSharedObjectHolder<ja::JAHandler>>();
            return mHandlers_;
        }

    public:
        std::shared_ptr<JAHandler> copyInstanceHandler(ja::JAStack &s, const string &block, const string &uri);

        void releaseHandlers();
    };

    using JAObjectContext = qlibc::QObjectSharedContext<JAObject>;

    class JAObjectOwnerBase;

    using QShareVarPool = std::shared_ptr<qlibc::QSharedObjectHolder<qlibc::QData>>;

    class JE_API JAVarAgent {
    protected:
        QShareVarPool vars_;
        std::recursive_mutex                 mutex_;
        qlibc::QData& holder_;
        friend class JAObjectOwnerBase;
    public:
        JAVarAgent(qlibc::QData& data, bool p) : holder_(data) {}

        ~JAVarAgent() { vars_ = nullptr; }


        bool transVarValue(JAStack& stack, const qlibc::QData &base, const std::string& valKey, std::string &target) const;

        virtual qlibc::QRData findVarRef(const std::string &varKey);
        virtual qlibc::QRData findVarRefRaw(const std::string &varKey);

        inline QShareVarPool& varRefPool();

        void VarRef(const std::string& key, qlibc::QData& dataRef);

        virtual void clearVarRef(const std::string& key);

        //优先查找obj、其次查找var
        virtual bool findVar(JAStack& stack, const std::string &varKey, std::string &target);

        virtual bool isVarEmpty();
        bool isVarEmptyRaw();
    };

/**
 * 各参数解释：
 *  stack, 调用栈
 *  jao,  持有该函数的对象
 *  sr,   返回值，字符串格式
 *  slp,  参数，字符串列表格式
 */
#define JAFuncConst(stack, jao, sr, slp) \
        (ja::JAStack& stack, ja::JAObject& jao, std::string& sr, const QStringList& slp)->bool
/**
 * 各参数解释：
 *  s,      执行栈
 *  o,    返回值， qdata格式，用于返回到lastResp对象
 *  qm,     入口消息，qdata格式
 *  sp,     脚本文件参数，string格式
 *      注意：
 *          返回值通常在stack中设置rsp对象进行操作，代表返回的消息
 */
#define JAMethodConst(s,o,qm,sp) \
        (ja::JAStack& s, ja::JAObject& o, const qlibc::QData &qm, const std::string& sp)->bool
    using FuncHandlerSharePool = std::shared_ptr<qlibc::QSharedObjectHolder<ja::JAFunctionHandler>>;
    using MethodHandlerSharePool = std::shared_ptr<qlibc::QSharedObjectHolder<ja::JAMethodHandler>>;

    class JE_API JAObject : public qlibc::QData, public JAVarAgent,
                            public ja::JAHandlerDocker {

    protected:
        FuncHandlerSharePool     funcs_ = nullptr;
        MethodHandlerSharePool   methods_ = nullptr;
        qlibc::QPObjectHolder<std::recursive_mutex>*      mutexes_ = nullptr;
        qlibc::QPObjectHolder<std::condition_variable>*   waits_ = nullptr;
        qlibc::QPObjectHolder<std::mutex>*                wait_mutexs_ = nullptr;   //与waits_配对使用
        qlibc::QObjectEventHolder*                        event_holder_ = nullptr;  //用于映射到外部event_holder，释放时不用做单独处理
        std::string             name_;
        JAContext&              _ctx;
        bool forbid_dynamic_creation_ = false;
        friend class ja::JAContext;
        friend class ja::JAObjectOwnerBase;
        bool      _clear:1;
        bool      _auto_pack:1;
        bool      _context_packed:1;

        virtual void prepareInnerObjects();

        JARClassObject  _cls = nullptr;

    static JARObject getContextPoolObject(JAContext*, JAObject*, bool forceBind = false);
    static void delContextPoolObject(JAContext*, JAObject*);

    public:
        explicit JAObject(JAContext& ctx, const qlibc::QData &data, const std::string& cls = sval_cls_name_object, bool pack_ctx=true);

        explicit JAObject(JAContext& ctx, const std::string& cls = sval_cls_name_object, bool pack_ctx=true);

        ~JAObject() override;

        inline void markPacked() {
            _context_packed = true;
        }

        inline void unmarkPacked() {
            _context_packed = false;
        }

        inline bool isContextPacked() {
            return _context_packed;
        }

        template <typename T = JAObject>
        std::shared_ptr<T> self(bool forceBind = false) {
            //从context中获得自身引用
            auto o = getContextPoolObject(&_ctx, this, forceBind);
            if(forceBind && o!=nullptr) markPacked();
            return std::dynamic_pointer_cast<T>(o);
        }

        inline FuncHandlerSharePool& funcsRefPool() {
            RECURSIVE_LOCK(mutex_);
            if (funcs_==nullptr)
                funcs_ = std::make_shared<qlibc::QSharedObjectHolder<ja::JAFunctionHandler>>();
            return funcs_;
        }

        inline MethodHandlerSharePool& methodsRefPool() {
            RECURSIVE_LOCK(mutex_);
            if (methods_==nullptr)
                methods_ = std::make_shared<qlibc::QSharedObjectHolder<ja::JAMethodHandler>>();
            return methods_;
        }

        bool Call(const std::string& method, ja::JAStack& s, const qlibc::QData &qm, const std::string& sp);

        inline JAContext& getContext(){ return _ctx; }

        inline JARClassObject  getClass(){ return _cls; }

        bool isClass(const std::string& cls);

        void Method(const std::string& key, const JAMethodHandler& method);

        void Func(const std::string& key, const JAFunctionHandler& func);

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

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

        virtual bool handleFuntion(JAStack& stack, const std::string &funcKey, std::string &target);
        bool handleFuntionRaw(JAStack& stack, const std::string &funcKey, std::string &target);

        virtual JARFunctionHandler findFunc(const std::string& func);

        virtual JARMethodHandler findMethod(const std::string& method);

        virtual void showMethods(QStringList& kl);

        virtual void showFunctions(QStringList& kl);

        virtual void showClassInfo(int maxline = 512);
//用于在context之前初始化的对象重建
        void resetClass(const std::string& dftCls = "", JAClassObject *creatorClass = nullptr);

        string getClassName() const override;

        const string& getObjectName() const;

        //这里获得名字的拷贝
        string getName() const override;
        //注意：getNameRef() 获得在JAContext中的对象名称
        virtual const std::string& getNameRef() const;

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

        qlibc::QData& pr_put(const std::string &key, const Json::Value &val);

        qlibc::QData &pr_setBool(const std::string &key, bool val);

        qlibc::QData &pr_setInt(const std::string &key, int val);

        qlibc::QData &pr_setString(const std::string &key, const std::string &val);

        qlibc::QData &pr_putString(const std::string &key, const std::string &val);

        qlibc::QData &pr_setValue(const std::string &key, const Json::Value &val);

        QData &pr_copyDataFromValue(const Json::Value &data);

        QData &pr_copyData(const QData &data);

        QData &pr_copyData(const QData &data, const std::string &key);

        //创建对象
        static bool createObject(ja::JAStack &s, ja::JAObject &o, const qlibc::QData &qm, const std::string &sp);

        static ja::JAObject* createSimpleObject(ja::JAObjectOwnerBase* owner, ja::JAStack &s, ja::JAObject &o, const qlibc::QData &qm, qlibc::JCArgNode &node);

    protected:
        qlibc::QPObjectHolder<std::recursive_mutex>* getMutexMap();

        qlibc::QPObjectHolder<std::condition_variable>* getWaitObjectMap();

        qlibc::QPObjectHolder<std::mutex>* getWaitMutexMap();

    public:
        void setMutexLock(const std::string & key );

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

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

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

        void waitOnCondition( const std::string & key, int timeoutMs);

        void tryClearSyncers();
    };

#define JADelete(jaosp) _ctx.getObjectPool().eraseObj(jaosp)

    using JAObjectCreator = std::function<ja::JAObject*(ja::JAContext& ctx, ja::JAInstance& inst, const std::string& name, const qlibc::QData& data)>;
#define JAObjCreatorLamda(_c,_i,_n,_d) (ja::JAContext& _c, ja::JAInstance& _i, const std::string& _n, const qlibc::QData& _d)->ja::JAObject*
#define bindJAClassCreator(_jacls, _cppcls) \
            _jacls->setCreator([]JAObjCreatorLamda(c,i,n,d) {\
                return new _cppcls(c,d); \
            })

    class JE_API JAClassObject : public JAObject {
    protected:
        JARClassObject              _parent = nullptr;
        std::vector<JARClassObject>* _multi_parents = nullptr;
        const JAObjectCreator*  creator_ = nullptr;
        qlibc::QSharedObjectHolder<ja::JAHandler>*
                                ja_methods_ = nullptr;

        qlibc::QSharedObjectHolder<ja::JAProperty>*
                                ja_properties_ = nullptr;

        friend class ja::JAContext;

    public:
        explicit JAClassObject(JAContext& ctx, bool forbid_dynamic_creation = false);

        explicit JAClassObject(JAContext& ctx, const qlibc::QData& data);

        ~JAClassObject() override;

        void clearClass() {
            _parent = nullptr;
            if(_multi_parents!= nullptr)
                _multi_parents->clear();
            _cls = nullptr;
        }

        void setCreator(const JAObjectCreator& creator);

        JARFunctionHandler findFunc(const std::string &func) override;

        JARMethodHandler findMethod(const std::string &method) override;

        void JAMethod(const std::string& method, JARHandler& handler);

        JARClassObject getParentClass();

        JAObject *createNewObject(const qlibc::QData &data, JAInstance& inst);

        void JAFunction(const std::string &funcName, JARHandler &handler);

        void JAProperty(const std::string &funcName, JAProperty *property);

        void showClassInfo(int maxline = 512) override;

        void showPropterties(QStringList& kl);

        void showMethods(QStringList& kl) override;

        void showFunctions(QStringList& kl) override;

        bool checkPropertyValid(const std::string& prop, const Json::Value& v);  //校验值是否符合要求、否则设定为默认值。
        void setPropertyValidValue(const std::string& prop, Json::Value& v);  //校验值是否符合要求、否则设定为默认值。
        void checkPropertyValues(JAObject *obj);

        bool isProperty(const std::string &propName);

        //设置多重继承类。
        //多重继承，只支持一个主类、多个辅类
        void setMultiParentClass(const std::string &mulClsNameList);

        bool isSubClassOf(const std::string &baseClass);

    protected:
        JAObject *createNewObjectRaw(const qlibc::QData &data, JAInstance& inst);

        void replaceParentClass(const JARClassObject &org, const JARClassObject &target);
    };

    class JE_API JAArrayObject: public JAObject {
    public:
        explicit JAArrayObject(JAContext& ctx, const Json::Value& jv, const std::string& cls = "array") : JAObject(ctx, cls) {
            _obj->operator[](ja_return_val_) =  jv.isArray()?jv:Json::arrayValue;
        }

        //创建对象
        static bool createArrayObject(ja::JAStack &s, ja::JAObject &o, const qlibc::QData &qm, const std::string &sp);

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

        Json::Value &asValue() override;

        bool isEmpty() const override;

        string toJSONString(bool lret) const override;

        void toJSONString(std::string &ret, bool lret) const override;
    };

    using JAObjectPool = qlibc::QPObjectHolder<ja::JAObject>;

    class JE_API JAObjectOwnerBase {
    protected:
        JAObject&                             base_;
        std::shared_ptr<qlibc::QSharedObjectHolder<ja::JAObject>>
                                              obj_refs_ = nullptr;
        std::string                           default_creating_class_ = sval_cls_name_object;
    private:
        std::recursive_mutex&                 mutex_p_o_;

    protected:
        virtual void beforeObjectErase(JAObject *object);

    public:
        explicit JAObjectOwnerBase (JAObject& obj, bool fix) : base_(obj), mutex_p_o_(base_.mutex_) {}

        virtual ~JAObjectOwnerBase();

        bool isObjectEmpty();

        //清理所有的对象引用
        void clearAllObjectRefs();

        std::shared_ptr<qlibc::QSharedObjectHolder<ja::JAObject>> objRefPool();

        qlibc::QRData findVarRefInOwner(const std::string &varKey);

        bool isVarEmptyInOwner();

        bool handleFuntionInOwner(JAStack& stack, const std::string &varKey, std::string &target);

        //优先查找obj、其次查找var
        bool findVarInOwner(JAStack& stack, const std::string &varKey, std::string &target);
        Json::Value* findVarInOwnerRef(JAStack& stack, const std::string &refKey);

        //从当前的对象池中找到当前对象的指针,pool返回找到的对象池
        static JARObject findObjectInStack(JAObjectOwnerBase** pool, const std::string& k, JAStack& s);

        static JARObject findObjectInCollection(const std::string& k, JAObjectOwnerBase& s, JAObjectOwnerBase& i);

        virtual JAObject* createObjectByCreator(JAInstance& inst, const std::string& key, const JAObjectCreator& creator, const qlibc::QData& data = qlibc::QData());

        virtual JAObject* createRunObjectFromData(JAInstance& inst, const std::string& key, qlibc::QData& data);

        virtual void registerClassCreator(const std::string& cls, const JAObjectCreator& creator);

        //仅仅引用、并不创建或释放
        void ObjectRef(const std::string& key, JAObject& obj);

        //引用、并将对象置入内存管理。系统退出时释放内存
        void Object(const std::string& key, JAObject* obj);

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

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

        void renameObject(const std::string& orgname, const std::string& newname );

        void holdVar(const std::string& key, qlibc::QRData& var);

        JARObject findObject(const std::string& objid);

        void getObjectKeySets(QStringList &keySets);

        const std::string& getNameRefInOwner() {
            return base_.getNameRef();
        }

        auto getOwnerNameRef() -> std::string {
            const Json::Value& bv = base_.asValueConst();
            auto hasOwner = bv.isMember(vkey_stored_owner_) && bv.operator[](vkey_stored_owner_).isString();
            return hasOwner?(bv.operator[](vkey_stored_owner_).asString()+"."+base_.getNameRef()): base_.getNameRef();
        }
    };

    class JE_API JAObjectOwner :  public JAObject, public JAObjectOwnerBase {
    public:
        explicit JAObjectOwner(JAContext &context, const std::string &clsName, bool pack_ctx = true);

        qlibc::QRData findVarRef(const std::string &varKey) override;

        bool findVar(JAStack &stack, const std::string &varKey, std::string &target) override;

        bool isVarEmpty() override;

        bool handleFuntion(JAStack &stack, const std::string &funcKey, std::string &target) override;
    };

    class JE_API JAStack : public JAObjectOwner {
    protected:
        std::unordered_map<std::string, bool>
                                dynamic_keys_;
        JAInstance&             inst_;
        std::vector<JARHandler>             call_stack_;            //脚本栈
        std::vector<JARObject>              msg_stack_;             //输入消息引用栈
        std::vector<const std::string*>     obj_stack_;             //对象栈
        std::vector<QRMsgAction>            action_stack_;          //action栈
        qlibc::QPObjectHolder<const Json::Value> jsval_refs_;       //对象化引用         这里涉及到对JsonValue的多级引用，暂时只用指针
        qlibc::QPObjectHolder<const Json::Value> jsval_holders_;    //值                这里涉及到对JsonValue的多级引用，暂时只用指针
        Json::Value                         jsval_null_;            //空值
        bool                    is_returned_;                       //是否已返回，目前整个stack一次返回，而不是按Handler分层返回
        //处理 ${var} 格式的变量作为存储对象
        Json::Value* getTargetValueRef(qlibc::JCArgNode& node, int idx);

    public:
        explicit JAStack(JAContext& ctx, JAInstance&  inst, const std::string& cls = "stack", bool pack_ctx = true);

        ~JAStack() override {
            clearObjectRef("stack");
        };

        inline JARHandler getCurrentHandler() {
            return call_stack_.empty()?nullptr:*call_stack_.rbegin();
        }

        Json::Value* findContextVarRef(qlibc::JCArgNode& node, int idx);

        std::string getRelatedPath(const std::string& path);

        JARObject findContextObject(const std::string& key);

        qlibc::QRData findContextVarData(const std::string& key);

        bool findContextVar(const std::string& key, std::string& val);

        JARMethodHandler findContextMethod(const std::string& key);

        JARFunctionHandler findContextFunction(const std::string& key);

        inline void pushScript(const JARHandler& handler){
            call_stack_.emplace_back(handler);
        }

        void pushMessage(const qlibc::QData& msg);

        void popMessage();

        JAObject *createRunObjectFromData(JAInstance& inst, const std::string &key, qlibc::QData &data) override;

        inline JARHandler popScript(){
            auto p = call_stack_.empty()?nullptr:*call_stack_.rbegin();
            if(p!=nullptr)
                call_stack_.pop_back();
            return p;
        }

        inline JAInstance& getInstance(){
            return inst_;
        }

        inline void pushAction(QRMsgAction& action){
            action_stack_.emplace_back(action);
        }

        inline const QRMsgAction popAction() {
            auto p = action_stack_.empty()?nullptr:*action_stack_.rbegin();
            if(p!=nullptr)
                action_stack_.pop_back();
            return p;
        }

        inline bool isReturned() const {
            return is_returned_;
        }

        inline const QRMsgAction getCurrentAction(){
            return action_stack_.empty()?nullptr:*action_stack_.rbegin();
        }

        void pushObject(const std::string& object);

        const std::string* popObject();

        const std::string* getCurrentObject();

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

        JAObject* createObjectByCreator(JAInstance& inst, const std::string &key, const JAObjectCreator &creator, const qlibc::QData& data ) override;

        JAObject* createObjectByCreator(JAInstance& inst, const std::string &key, const JAObjectCreator &creator);

        void clearDynamicObjects();

        virtual JARObject dynamicObject(const std::string& key, const qlibc::QData& obj);

        void dynamicObjectRef(const std::string& key, JAObject& obj);

        std::string getStackCallInfo();

        void setJsonValueRef(const Json::Value& val, std::string& key, bool autoRelease = false);

        //将参数、message，以及变量的内容汇聚到一个模板参数中
        qlibc::QData& makeDataParamFromContext(qlibc::JCArgNode& node, int keyIdx, const qlibc::QData* msg = nullptr);

        //将参数计算为值，但一般不处理其它命令行参数
        const Json::Value& getValueRefParam(qlibc::JCArgNode& node, int idx);

        //处理 $${var} 格式的变量，作为存储对象，但注意、该格式的对象可自主创建
        Json::Value* getStoredValueTarget(qlibc::JCArgNode& node, int idx, bool asObject = false);

        //检查val的类型，如果为对象引用格式的字符串，则替换为对象本身的引用
        const Json::Value& checkJsonValueRef(const Json::Value& val);

        //获得一个对象引用字符串的对象引用、可以引用后删除，或者不删除
        const Json::Value& getJsonValueRef(const std::string& key, bool clearOnAccess = true);

        //Stack resset时释放
        inline void clearJsonValueRef(){
            if(!jsval_refs_.isEmpty())
                jsval_refs_.releaseAll();
            if(!jsval_holders_.isEmpty())
                jsval_holders_.releaseAll();    //释放本次执行产生的引用缓存
        }

        //运行一个子脚本
        bool runSubBlockHandler(string &block, const QData &m);

        virtual void copyStackResult(QData *resp);

        //check ifnode's value has compacted object vals.
        void extractCompactedRefValue(Json::Value &node);

        inline bool hasValueRef(){
            return !jsval_refs_.isEmpty();
        }

        void markReturned();
    };

    class JE_API JAContext : public JAObjectOwner {
    protected:
        qlibc::QSharedObjectHolder<ja::JAClassObject>
                        classes_;
        JAObjectContext obj_pool_;

        std::string     default_cls_;

        bool prepared_:1;
        bool is_quitting_:1;
        bool final_:1;

    public:

        explicit JAContext(const std::string& cls = "context") :
                JAObjectOwner(*this, cls, false),
                prepared_(false), is_quitting_(false), final_(false) {
            default_cls_ = "context";
        }

        ~JAContext() override;

        void clearContext();

        inline void delMe() {
            clearContext();
            JAObject::delContextPoolObject(this, this);
        }

        inline virtual void onContextJAObjectRelease(JARObject& o) {
            if(o!= nullptr && !final_) {
#if 1 //ifdef DEBUG_MEMORY
                QDHLog("JAObject [%p] %s (class:N/A, UC:%d) releasing ...", o.get(), o->name_.c_str(),
                       /*o->getClass()->getNameRef().c_str(), */o.use_count());
#endif
            }
        }

        inline JAObjectContext& getObjectPool() {
            return obj_pool_;
        }

        template <class T>
        inline std::shared_ptr<T> getPoolJAObject(JAObject* p) {
            auto r = std::dynamic_pointer_cast<T>(obj_pool_.get(p));
            return r;
        }

        /**
         *       系统触发器：
         *
         * @param k             键值
         * @param cond          条件计算函数
         * @param cb            条件满足后的执行函数
         * @param freq          条件检查频率（默认1S）
         * @param delay         延迟检查时间（默认无延迟）
         * @param dur           触发持续时间（默认1次，如果为持续一定时间、则需要设置这段时间的执行频率gap参数，
         *                          如果处于已执行状态未停止、则后续触发可覆盖上次触发）
         * @param gap           反复执行的间隔时间（每次检查后默认执行一次，即，gap=dur）
         * @param overLay       两次触发时、第二次触发时是否中止上次触发的进程，如果是多次触发。仅在dur/gap有效时有效
         */
        const std::string& addTrigger(const std::string& key, const qlibc::QTriggerCondition& cond, const qlibc::QTriggerCallback& cb,
                        long freq = 1000, long delay = 0, long dur = -1, long gap = -1, bool overLay = false);

        const std::string& addTrigger(const std::string& key, const qlibc::QTriggerCondition& cond, const qlibc::QTriggerKeyCallback& cb,
                        long freq = 1000, long delay = 0, long dur = -1, long gap = -1, bool overLay = false);

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

        void packJAObjectToPool(JARObject& obj) {
            QDLog("Try pack outer object %s(%s)", obj->name_.c_str(), obj->getClassName().c_str());
            RECURSIVE_LOCK(mutex_);
            obj->markPacked();
            obj_pool_.outer(obj); //管理外部对象引用
        }

        inline void outerClear(JAObject* obj) {
            RECURSIVE_LOCK(mutex_);
            obj_pool_.eraseObj(obj, true);  //清理外部对象引用
            obj->unmarkPacked();
        }

        bool loadClassDefine(const std::string& filename);

        JARClassObject findClass(const std::string& clsName);

        JARClassObject Class(const std::string& clsName, const std::string& clsParent = sval_cls_name_object, bool forbid_dynamic_creation = false);

        JARClassObject Class(qlibc::QData& clsDefData);

        void releaseClass(const std::string& clsName);

        void removeClassMethod(const std::string& clsName, const std::string& methodName);

        void removeClassFunction(const std::string& clsName, const std::string& funcName);

        virtual bool prepareContext(const qlibc::QData& data);

        JAObject* createObjectFromDataA(const qlibc::QData &data, JAInstance& inst, const std::string& defaultCls = sval_cls_name_object);

        void registerClassCreator(const std::string &clsName, const JAObjectCreator &creator) override;

        void ClassMethod(const std::string &clsName, const std::string &method, const JAMethodHandler &handler);

        virtual qlibc::QRTimerEngine getTimerEngine() { return nullptr;}

        virtual httplib::RThreadPool getThreadPoolRef() { return nullptr;}

        virtual qlibc::QRTriggerEngine getTriggerEngine() { return nullptr;}

        inline virtual bool isQuitting() {
            return is_quitting_;
        }

        inline void setQuitting(bool quitting = true) {
            is_quitting_ = quitting;
        }

        bool isPrepared();

        void getContextClasseKeyset(QStringList &keyset);

    protected:

        void prepareInnerObjects() override;

        virtual void loadInnerClasses();

        virtual void buildClassFromDefData(JAClassObject* cls, const qlibc::QData &data);

        virtual void resetContextClass();

        //释放资源
        virtual void releaseContextResources();

    };

//消息运行调度器：消息在其中
/**
 *  其对消息响应脚本引擎的响应器存储结构是：
 *      {
 *          Pools-->channel[http]-->handler
 *                      +---------->handler
 *                      +----------> ...
 *                      +---------->handler
 *                  channel[mqtt]-->handler
 *                      +---------->handler
 *                      +----------> ...
 *                      +---------->handler
 *                  channel[...]-->handler
 *      }
 */
    class JAInstance;
    class JE_API JAMsgDispatcher {
    protected:
        std::string             uri_key_;
        JAInstance&             instance_;
        std::recursive_mutex    acc_mutex_;

        JAHandlerPools          handlers_;
        int active_ = 0;
        bool closed_ = false;   //操作中
    public:
        explicit JAMsgDispatcher(JAInstance& instance) ;

        //扫描ja脚本引擎
        bool loadHandlers(const qlibc::QData &def, const std::string& actionKeys);

        bool handleJAMessage(JAStack& stack, const std::string& channel, const qlibc::QData &msg);

        bool isEmpty();

        void clearHandlers();

        void printHandlers(Json::Value* ret, const std::string& baseUri, const std::string& keyList = vkey_handler_channel_, bool print = true);

        inline void resetUriKey(const std::string& uriKey) {
            uri_key_ = uriKey;
        }

        bool removeHandlers(const std::string &keylist);

        inline const string &getUriKey() {
            return uri_key_;
        }

        bool containsHandler(const std::string &channel, const std::string &handlerKey);

        JARHandler findChannelHandler(const char *string, const std::string &apiKey);

    protected:
        static void parseJAHandler(JAHandlerPool& pool, const qlibc::QData &data, JAInstance& instance);

        JAHandlerPool &getHandlerPoolCreateIfNotExists(const std::string &actionDefKey);

        void appendHandlersToList(Json::Value *vl,
                                  const std::string& baseUri, const std::string& chn, JAHandlerPool *hdlrPool);
    };


    class JE_API JAInstance : public JAObjectOwner {
    protected:
        qlibc::QSharedObjectMemoryPool<ja::JAStack, 3> *stack_pool_ = nullptr;
        JAMsgDispatcher                              mJaDispatcher;
        JAObject&                                    base_;              //根对象，默认为instance自己
        std::string                                  base_path_;         //对象树路径
        qlibc::QSharedObjectHolder<ja::JADataTemplate>* templates_ = nullptr;
        qlibc::QPObjectHolder<qlibc::QRTimer>*       timers_ = nullptr;    //与属性同步的timer
        std::string             default_cls_;

    public:
        explicit JAInstance(JAContext& ctx, JAObject& baseObj, std::string base_path=DEFAULT_CURRENT_PATH, const std::string& cls = "instance", bool pack_ctx = false ) :
                JAObjectOwner(ctx, cls, pack_ctx), mJaDispatcher(*this), base_(baseObj), base_path_(std::move(base_path)) {
            default_cls_ = "instance";
        }

        ~JAInstance() override;

        virtual bool prepareInstance();

        JARInstance instanceRef();

        bool evalConditionExpr(const std::string& expr);

        void addTimer(const std::string& key, qlibc::QRTimer& timer);
        void delTimer(const std::string& key, bool byDelay = false);

        void tryClearTimers();

        //释放资源
        void releaseInstanceResources();

    protected:

//创建栈
        virtual JAStack *createJAServiceStack();

//获取新栈
        std::shared_ptr<JAStack>
        retrieveStack(qlibc::QData *rsp, const qlibc::QData& message, const std::string& jschn, JAObject& object);

//重置栈
        virtual void resetStackStatus(JAStack &stack, qlibc::QData *rsp, const qlibc::QData& msg, const std::string& jschn , JAObject& object);;

        virtual void clearDynamicObjects(JAStack &stack);;

//释放栈
        void releaseStack(JARStack &stack);

        void prepareTemplates();

        void parseTemplateFromDefData(qlibc::QData &defData);

    public:

        bool listJAHandlers(Json::Value* vl = nullptr, const char* keylist = vkey_default_ja_script_channel_keys, bool show = true);

/**
 *      获取模板
 *
 * @param tempalte
 * @return
 */
        JARDataTemplateFiller getNewTemplateFiller(const std::string& tempalte);

        void releaseTemplateFiller(const std::string& templ, JARDataTemplateFiller &filler);

        JARDataTemplate loadTemplate(const std::string& tempalte);

        const std::string& getBasePath();

        bool loadJAScript(qlibc::QData &d, const std::string& keylist = vkey_default_ja_script_channel_keys);

        void clearJAScript();

        bool runJAScript(const std::string &chn, qlibc::QData *rsp, qlibc::QData &msg);

        bool evalJAScript(const std::string &script, qlibc::QData *rsp, const qlibc::QData &msg,
                          const JARStack& lastStack = nullptr, const std::string& src =vkey_filename_inline_);

        bool runJAScript(const JARHandler &script, const qlibc::QData &msg, const JARStack& lastStack = nullptr, qlibc::QData *rsp = nullptr);

        inline const std::string& getUriKey();

        JARHandler findMsgHandler(const std::string &msgApi);

        bool findVar(JAStack &stack, const string &varKey, string &target) override;

        void runSubBlockJAScript(JARHandler& handler, std::string &subBlock, const qlibc::QData &msg, const std::string &src="inner");

        void clearStacks();
    };

    class JE_API JASimpleContext : public JAContext {
    protected:
        JARInstance instance;
    public:
        explicit JASimpleContext();

        ~JASimpleContext() override;

        bool prepareContext(const qlibc::QData& data) override;

        bool loadJAScript(const std::string &jafile, const std::string& keylist = vkey_default_ja_script_channel_keys);

    public:

        bool runJAScript(const std::string &chn, qlibc::QData *rsp, qlibc::QData &msg);

        bool evalJAScript(const std::string &script, qlibc::QData *rsp, const qlibc::QData &msg, const std::string &src = vkey_filename_inline_);
    };
/**
 *  调用基类方法的宏
 *      ret:    调用返回是否成功
 *      name:   调用方法名，注意不用引号字符串
 */
#define CallBaseMethod(ret, name, s, o, m, p)\
    auto ret = false; \
    auto* baseFunc_##name = o.getClass()->getParentClass()->findMethod(#name); \
    if(baseFunc_##name!=nullptr){            \
        try{ ret = baseFunc_##name->operator()(s,o,m,p); \
        } catch (std::bad_function_call& e) {}\
    }

    static const char* orders[] = {nullptr};

//判断字符串是否为对象引用
#define IS_VAL_REF(__k) \
    (__k.size()>3 && __k[0]=='_' && __k[1]=='$' && __k[2]=='@')

#define IS_AUTO_RELEASE(__k) \
    (__k.size()>4 && __k[0]=='_' && __k[1]=='$' && __k[2]=='@' && __k[3]=='*')

#define JALogObject(stack,obj) \
    QDLog("%s[%12s:%8s:%8s:%02d]%s(%s%s%s)=\n%s", qlog_light_blue, (s).getRelatedPath((s).getCurrentHandler()->filename_).c_str(),  (s).getCurrentHandler()->channel_.c_str(), \
            (s).getCurrentHandler()->uri_.c_str(), (s).getCurrentAction()->getLine(), qlog_none, qlog_light_green, (obj).getName().c_str(), qlog_none, StringUtils::valueToJsonStringByOrderedKeys((obj).asValueConst(), ja::orders).c_str())
#define JALogObjectMsg(stack,fmt,...) \
    QLog((StringUtils::formatString("%s[%12s:%6s:%8s:%02d]%s", qlog_yellow, (s).getRelatedPath((s).getCurrentHandler()->filename_).c_str(),  (s).getCurrentHandler()->channel_.c_str(), \
            (s).getCurrentHandler()->uri_.c_str(), (s).getCurrentAction()->getLine(),qlog_none)+fmt).c_str(), ##__VA_ARGS__)
#define JAErr(s,fmt,...) \
    QLog((StringUtils::formatString("%s[%12s:%6s:%8s:%02d]%s", qlog_yellow, (s).getRelatedPath((s).getCurrentHandler()->filename_).c_str(),  (s).getCurrentHandler()->channel_.c_str(), \
            (s).getCurrentHandler()->uri_.c_str(), (s).getCurrentAction()->getLine(),qlog_ERR) + fmt).c_str(),  ##__VA_ARGS__)
#define JAWarn(s,fmt,...) \
    QLog((StringUtils::formatString("%s[%12s:%6s:%8s:%02d]%s",qlog_yellow, (s).getRelatedPath((s).getCurrentHandler()->filename_).c_str(), (s).getCurrentHandler()->channel_.c_str(), \
            (s).getCurrentHandler()->uri_.c_str(), (s).getCurrentAction()->getLine(),qlog_WARN) + fmt).c_str(), ##__VA_ARGS__)
#define JALog(s,fmt,...) \
    QLog((StringUtils::formatString("%s[%12s:%6s:%8s:%02d]%s",qlog_yellow, (s).getRelatedPath((s).getCurrentHandler()->filename_).c_str(), (s).getCurrentHandler()->channel_.c_str(), \
            (s).getCurrentHandler()->uri_.c_str(), (s).getCurrentAction()->getLine(),qlog_LOG) + fmt).c_str(), ##__VA_ARGS__)
}


#endif //INC_0_LIBDEVCPP_JABASEDOM_H
