//
// Created by Ht on 2022/1/8.
//

#ifndef INC_0_LIBDEVCPP_QJASERVER_H
#define INC_0_LIBDEVCPP_QJASERVER_H

#include <mgbus/QMgbusModule.h>
#include <qlibc/plugin/QPluginManager.h>
#include <jadom2/JAIndexedDom.h>

namespace jedge {

    class JE_API QJAMgServer :
        public ja::JAIndexNodeContext,
        public QMgbusModule {
    protected:
        class QTimeOutObjNode {
        public:
            explicit QTimeOutObjNode(JAObjectOwner &owner, JAObject *obj) :
                    owner_(owner), obj_(obj) {
            }
            JAObjectOwner&          owner_;
            JAObject*               obj_;
        };

        std::vector<QTimeOutObjNode*>* tobjs_ = nullptr;
        qlibc::QRTimer               timeout_cleaner_;
        std::mutex                  clean_mutex_;
        std::string                 target_service_;

        qlibc::QPluginManager*      plugin_mgr_ = nullptr;

        std::string                 pre_command_;

        void loadPluginClassDefs();
        void loadAllPluginServices();

    public:
        explicit QJAMgServer(const qlibc::QData &initConfig, const std::string &name, SocketMode mode = jedge::typeUDP);

        ~QJAMgServer() override;

        bool start(const qlibc::QData &config) override;

        void shutdown() override;

        virtual void prepareJsonActionContext(const qlibc::QData &config) {};

        virtual void clearJsonActionContext();

        void setServerConfig(std::string &result, const std::string &key, const Json::Value &val) override;

        void appendTimeoutObject(JAObjectOwner& owner, JAObject* objKey);

        void clearTimeoutObject(JAObject* obj);

        bool appendUserService (const std::string &key, const qlibc::QData &config, MgService* service) override;

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

        protected:
        void loadInnerClasses() override;

        void removeTimeoutObjects();
        bool runServerScript(const std::string& event, qlibc::QData& param);

        void stopTimeoutCleaner();

        void prepareInnerObjects() override;

    public:
        qlibc::QRTimerEngine getTimerEngine() override;

        httplib::RThreadPool getThreadPoolRef() override;

        qlibc::QRTriggerEngine getTriggerEngine() override;

        bool resetTarget(qlibc::JCArgNode &p);

        bool runJAScriptFromCommand(qlibc::JCArgNode &p);

        bool mgbus(qlibc::JCArgNode &param, qlibc::QData* re);

        bool MgbusVersion(qlibc::JCArgNode &param, qlibc::QData* re);

        bool pre_command(qlibc::JCArgNode &param, qlibc::QData* re);

        bool ping(qlibc::JCArgNode &param, qlibc::QData* re);

        virtual bool makeJedgeRequestPost(qlibc::JCArgNode &param, qlibc::QData* re, ja::JAStack* s);

        virtual bool makeJedgeMessagePost(qlibc::JCArgNode &param, qlibc::QData* re, ja::JAStack* s);

        bool findMgbusHosts(qlibc::JCArgNode &param, qlibc::QData* re);

        bool listMgbusClients(qlibc::JCArgNode &param, qlibc::QData* re);

        bool gather(qlibc::JCArgNode &param, qlibc::QData* re);

        bool ShowSocketIOLog(qlibc::JCArgNode &param, qlibc::QData* re);

        bool listOnlineMgbusNodeSn(qlibc::JCArgNode &param, qlibc::QData* re);

        bool getContextName(qlibc::JCArgNode &param, qlibc::QData* re);

        bool showPool(qlibc::JCArgNode &param, qlibc::QData* re);

        bool getModuleAddress(qlibc::JCArgNode &param, qlibc::QData* re);

        bool handleJsonActionFiles(qlibc::JCArgNode &param, qlibc::QData* re);

        void releasePluginClassDefs();

        static std::string defaultFilePath(const qlibc::QData &cfg, const std::string &name);
    };

#define MgServer(opr)\
    (dynamic_cast<jedge::QJAMgServer&>(opr))

#define PQJAMgServer(opr)\
    auto* opr = (dynamic_cast<jedge::QJAMgServer*>(&operator_))

#define IsAMgServer(opr) \
    (dynamic_cast<jedge::QJAMgServer*>(&(opr)) !=nullptr)

}

#endif //INC_0_LIBDEVCPP_QJASERVER_H
