//
// Created by Ht on 2021/12/2.
//

#ifndef INC_0_LIBDEVCPP_JAMGMODULEHELPER_H
#define INC_0_LIBDEVCPP_JAMGMODULEHELPER_H

#include <qlibc/cmd/JCCmdRunnerHelper.h>
#include <exlib/QJAService.h>


namespace jedge {

    using QJAServicePreBinder = std::function<void(jedge::QJAMgServer& server, const qlibc::QData &config)>;

    class JE_API JAMgModuleObjHelper : public QJAMgServer {
    protected:
        //用户自定义服务加载器,可加载一些用户自定义的C++服务
        QJAServicePreBinder* servic_binder_ = nullptr;
    public:
        explicit JAMgModuleObjHelper(qlibc::QData& cfg, const std::string& appName,  const QJAServicePreBinder& binder) :
                QJAMgServer(cfg, rebuildMgbusConfig(cfg, appName), cfg.getString("sc_type")!="tcp"?typeUDP:typeTCP) {
            //处理代码
            servic_binder_ = new QJAServicePreBinder(binder);
        }

        explicit JAMgModuleObjHelper(qlibc::QData& cfg, const std::string& appName) :
                QJAMgServer(cfg, rebuildMgbusConfig(cfg, appName), cfg.getString("sc_type")!="tcp"?typeUDP:typeTCP) {
        }

        ~JAMgModuleObjHelper() override {
            delete servic_binder_;
        }

    protected:
        void prepareService(const qlibc::QData &config) override {
            MgBusHolder::prepareService(config);
            if(servic_binder_!=nullptr) {
                try { servic_binder_->operator()(*this, config);
                } catch (std::bad_function_call& e) {}
            }
        }
    };

    class JE_API JAMgModuleHelperUtil {

    public:
        static void prepareJedgeAppInitParam(qlibc::QData& auxData, const int argc, const char* argv[]);

        /**
         *  快速启动一个JAM应用 可在argv中添加参数
         *      --jam  <name>
         *      --sc_type  <type>               接入类型 tcp : typeTCP, other : typeUDP
         *      --mg_host  <host>:127.0.0.1     mgbus主机地址
         *      --mg_port  <port>:8877          mgbus端口
         *
         * @param argc
         * @param argv
         * @param appname
         */

        static void createJAMgModuleInstance(int argc, const char *argv[], const  char* appname, const qlibc::QData& auxData, bool changePath);

        static void createJAMgModuleInstanceWithInitScripts(int argc, const char *argv[], const char* appname, const qlibc::QData& auxData, bool changePath, bool showPrompt=false, const std::string& initCmd = "");

        static void createJAMgModuleInstance(int argc, const char *argv[], const char* appname, const qlibc::QData& auxData, const QJAServicePreBinder&  binder,
                                             bool changePath, const std::string& initCmd = "");

        static void createJAMgModuleInstance(int argc, const char *argv[], const  char* appname, bool changePath) {
            createJAMgModuleInstance(argc, argv, appname, qlibc::QData(), changePath);
        }

        static void createJAMgModuleInstanceWithInitScripts(int argc, const char *argv[], const char* appname,
                                                            bool changePath, bool showPrompt=false, const std::string& initCmd = "") {
            createJAMgModuleInstanceWithInitScripts(argc, argv, appname, qlibc::QData(), changePath, showPrompt, initCmd);
        }

        static void createJAMgModuleInstance(int argc, const char *argv[], const char* appname,
                                             const QJAServicePreBinder&  binder, bool changePath, const std::string& initCmd = "") {
            createJAMgModuleInstance(argc, argv, appname, qlibc::QData(), binder, changePath, initCmd);
        }
    };

#define createJAInstance(argc, argv, appname) \
    int _nargc = 0; const char** _nargv = nullptr; \
    qlibc::JCCmdRunnerHelper::updateArgsForPath(argc, argv, _nargc, &_nargv, appname, qlibc::changeDirSetForDebug); \
    jedge::JAMgModuleHelperUtil::createJAMgModuleInstance(_nargc, _nargv, appname, qlibc::changeDirSetForDebug); \
    if(_nargv!= nullptr && _nargv!=(argv)) delete _nargv

#define createJAInstanceWithAux(argc, argv, appname, auxData) \
    int _nargc = 0; const char** _nargv = nullptr; \
    qlibc::JCCmdRunnerHelper::updateArgsForPath(argc, argv, _nargc, &_nargv, appname, qlibc::changeDirSetForDebug); \
    jedge::JAMgModuleHelperUtil::createJAMgModuleInstance(_nargc, _nargv, appname, auxData, qlibc::changeDirSetForDebug); \
    if(_nargv!= nullptr && _nargv!=(argv)) delete _nargv

#define createJAInstanceWithInitScript(argc, argv, appname, initCmd) \
    int _nargc = 0; const char** _nargv = nullptr; \
    qlibc::JCCmdRunnerHelper::updateArgsForPath(argc, argv, _nargc, &_nargv, appname, qlibc::changeDirSetForDebug); \
    jedge::JAMgModuleHelperUtil::createJAMgModuleInstanceWithInitScripts(_nargc, _nargv, appname, qlibc::changeDirSetForDebug, false, initCmd); \
    if(_nargv!= nullptr && _nargv!=(argv)) delete _nargv

#define createJAInstanceWithInitScriptWithAux(argc, argv, appname, auxData, initCmd) \
    int _nargc = 0; const char** _nargv = nullptr; \
    qlibc::JCCmdRunnerHelper::updateArgsForPath(argc, argv, _nargc, &_nargv, appname, qlibc::changeDirSetForDebug); \
    jedge::JAMgModuleHelperUtil::createJAMgModuleInstanceWithInitScripts(_nargc, _nargv, appname, auxData, qlibc::changeDirSetForDebug, false, initCmd); \
    if(_nargv!= nullptr && _nargv!=(argv)) delete _nargv

#define createJAInstanceWithInitScriptAndCommand(argc, argv, appname, initCmd) \
    int _nargc = 0; const char** _nargv = nullptr; \
    qlibc::JCCmdRunnerHelper::updateArgsForPath(argc, argv, _nargc, &_nargv, appname,  qlibc::changeDirSetForDebug); \
    jedge::JAMgModuleHelperUtil::createJAMgModuleInstanceWithInitScripts(_nargc, _nargv, appname, qlibc::changeDirSetForDebug, true, initCmd); \
    if(_nargv!= nullptr && _nargv!=(argv)) delete _nargv

#define createJAInstanceWithInitScriptAndCommandWithAux(argc, argv, appname, auxData, initCmd) \
    int _nargc = 0; const char** _nargv = nullptr; \
    qlibc::JCCmdRunnerHelper::updateArgsForPath(argc, argv, _nargc, &_nargv, appname,  qlibc::changeDirSetForDebug); \
    jedge::JAMgModuleHelperUtil::createJAMgModuleInstanceWithInitScripts(_nargc, _nargv, appname, auxData, qlibc::changeDirSetForDebug, true, initCmd); \
    if(_nargv!= nullptr && _nargv!=(argv)) delete _nargv

    //start with argc, argv , appname, binder, initCmd
#define createJAInstanceWithBinder(argc, argv, appname, binder, initCmd) \
    int _nargc = 0; const char** _nargv = nullptr; \
    qlibc::JCCmdRunnerHelper::updateArgsForPath(argc, argv, _nargc, &_nargv, appname, qlibc::changeDirSetForDebug); \
    jedge::JAMgModuleHelperUtil::createJAMgModuleInstance(_nargc, _nargv, appname, binder, qlibc::changeDirSetForDebug, initCmd); \
    if(_nargv!= nullptr && _nargv!=(argv)) delete _nargv

    //start with argc, argv , appname, auxData, binder, initCmd
#define createJAInstanceWithBinderWithAux(argc, argv, appname, auxData, binder, initCmd) \
    int _nargc = 0; const char** _nargv = nullptr; \
    qlibc::JCCmdRunnerHelper::updateArgsForPath(argc, argv, _nargc, &_nargv, appname, qlibc::changeDirSetForDebug); \
    (auxData).putString("plat",APP_PLATFORM);                                                                          \
    jedge::JAMgModuleHelperUtil::createJAMgModuleInstance(_nargc, _nargv, appname, auxData, binder, qlibc::changeDirSetForDebug, initCmd); \
    if(_nargv!= nullptr && _nargv!=(argv)) delete _nargv
}
#endif //INC_0_LIBDEVCPP_JAMGMODULEHELPER_H
