//
// Created by Ht on 2020/7/27.
//

#ifndef LIBDEVCPP_MGBUSCOMMON_H
#define LIBDEVCPP_MGBUSCOMMON_H


namespace jedge {

#ifdef DEBUG
#define PRINT_MESSAGE_SOURCE 1
#define PRINT_MESSAGE_TRACE  0
#else
#define PRINT_MESSAGE_SOURCE 0
#define PRINT_MESSAGE_TRACE  0
#endif
#define SOCK_KEEPALIVE_TIMEOUT_SECOND   600

#define SOCK_READ_SELECT_TIMEOUT_SECOND   10

#define MGBUS_CLIENT_DATA_BUFFER_SIZE 65536

#define UDP_SOCKBUF_MAXSIZE 64512 //63k

#define JSON_RPC_MESSAGE_DEVIDER_CHAR ('\n')
#define JSON_RPC_MESSAGE_DEVIDER_CHAR_R ('\r')

    #define HEART_BEAT_GAP_                         60 * 1000           //30S一个心跳
    #define HEART_BEAT_GAP_TIMEOUT_                 (HEART_BEAT_GAP_ * 4)   //d掉线90S超时
    #define MGBUS_CLIENT_HOST_ONLINE_PERIAD_        6000            //接入等待步骤不低于6000毫秒
    #define MGBUS_CLIENT_HOST_RECHECK_INTERVAL_     5000            //系统检查网络同步地址等待时间，不能低于5000毫秒
    #define MGBUS_CLIENT_RECONNECT_INTERVAL_        3000            //系统重联等等待时间
    #define MGBUS_CLIENT_OPCHECK_INTERVAL_          100             //连续操作等待时间

    static unsigned char ival_count_for_online_step_wait_ = MGBUS_CLIENT_HOST_ONLINE_PERIAD_ / MGBUS_CLIENT_RECONNECT_INTERVAL_;

    static unsigned int ival_watcher_relink_ttl_ = 4 ;
    static unsigned short ival_watcher_refresh_ttl_ = 30;
    static int ival_watcher_timeout_ttl_ = 150;


    static const int max_mgbus_tick_cnt = ival_watcher_relink_ttl_;

    enum SocketMode {
        typeTCP = 0,
        typeUDP,
        typeNone
    };

    static const char* JEDGE_MGBUS_SDK_NAME = "MgbusCPP";

    static const char JMPC = '~';
    static const char JMPH = 'c';
    static const char JEPH = 'e';
    static const char JMNF = '$';
    static const char JMPD = '.';
    static const char JEDGE_MGCALL_PREFIX_HEAD[] = {JMPC, JMPH,'\0'};
    static const char JEDGE_MGEVENT_PREFIX_HEAD[] = {JMPC, JEPH,'\0'};
    static const char JEDGE_MGNAME_FUNCTION_CHAR[] = {JMNF,'\0'};

    static const char* DATA_CHANNEL_MGBUS = "mgbus";

    //基本模块名
    static const char* JEDGE_MGBUS_MODUAL_MGS_SERVER = "mgs";
    static const char* JEDGE_MGBUS_MODUAL_COSS = "coss";
    static const char* JEDGE_MGBUS_MODUAL_MUFIS = "mufis";
    static const char* JEDGE_MGBUS_MODUAL_GAFFIC = "gaffic";
    static const char* JEDGE_MGBUS_MODUAL_VDAL = "vdal";
    static const char* JEDGE_MGBUS_MODUAL_IPVDAL = "ipvdal";
    static const char* JEDGE_MGBUS_MODUAL_ECS = "ecs";

#define IsMgServerKey(src) StringUtils::startsWith(src, "mgs@") || StringUtils::endsWith(src, ".local")

    static const char JEDGE_MGBUS_KEY_SOURCE[] = {JMPC, JMPH, JMPD,'s','\0'};       //mgbus的源module
    static const char JEDGE_MGBUS_KEY_TARGET[] = {JMPC, JMPH, JMPD,'t','\0'};       //mgbus的目标module

    static const char JEDGE_MGBUS_MODUAL_KEY_SOURCE[] = {JMPC, JMPH, JMPD,'s',JMPD,'m','\0'};       //mgbus的源module     : ~c.s.m
    static const char JEDGE_MGBUS_MODUAL_KEY_TARGET[] = {JMPC, JMPH, JMPD,'t',JMPD,'m','\0'};       //mgbus的目标module   : ~c.t.m

    static const char JEDGE_MGBUS_REMOTE_KEY_SOURCE[] = {JMPC, JMPH, JMPD,'s',JMPD,'c','\0'};       //remote源            : ~c.s.c
    static const char JEDGE_MGBUS_REMOTE_KEY_TARGET[] = {JMPC, JMPH, JMPD,'t',JMPD,'c','\0'};       //remote目标          : ~c.t.c

    static const char JEDGE_MGBUS_CHANNEL_KEY_SOURCE[] = {JMPC, JMPH, JMPD,'s',JMPD,'d','\0'};      //channel源           : ~c.s.d
    static const char JEDGE_MGBUS_CHANNEL_KEY_TARGET[] = {JMPC, JMPH, JMPD,'t',JMPD,'d','\0'};      //channel目标         : ~c.t.d

    static const char JEDGE_MGBUS_CLIENT_KEY_SOURCE[] = {JMPC, JMPH, JMPD,'s',JMPD,'k','\0'};       //client源            : ~c.s.k
    static const char JEDGE_MGBUS_CLIENT_KEY_TARGET[] = {JMPC, JMPH, JMPD,'t',JMPD,'k','\0'};       //client目标          : ~c.t.k

    static const char CLIENT_SERVICE_SRC[] = {JMPC, JMPH, JMPD,'m','c',JMPD,'s','\0'};              //mgbus的转发调用目标  : ~c.mc.
    static const char CLIENT_SERVICE_DEST[] = {JMPC, JMPH, JMPD,'m','c',JMPD,'t','\0'};             //mgbus的转发调用目标
    static const char DATA_CLIENT_POST_TARGET_SERVICE[] = {JMPC, JMPH, JMPD,'m','c',JMPD,'r','\0'}; //描述http返回的目标服务的信息

    static const char JEDGE_CALL_CALLID_KEY[] = {JMPC, JMPH, JMPD,'i','\0'};        //callid
    static const char JEDGE_CALL_RESPONSE_KEY[] = {JMPC, JMPH, JMPD,'r','\0'};      //response message of call，同步请求时需要设定
    static const char JEDGE_CALL_REQ_TIMEOUT[] = {JMPC, JMPH, JMPD,'t','o','\0'};   //timeout set.

    static const char JEDGE_MGBUS_CMD_KEY[] = {JMPC, JMPH, JMPD,'c','\0'};          //jedge mgbus command
    static const char* jedge_mgbus_cmd_heart_beat_ = "b";
    static const char* jedge_mgbus_cmd_regist_ = "l";
    static const char* jedge_mgbus_cmd_quit_ = "q";
    static const char* jedge_mgbus_cmd_debug_ = "d";
    static const char* jedge_mgbus_cmd_group_ = "g";      //分组命令
    static const char* jedge_mgbus_cmd_net_ = "n";        //基本网络命令
    static const char* jedge_mgbus_cmd_mgnet_ = "m";        //mgbus网络命令
    static const char* jedge_mgbus_cmd_debug_client_set_ = "d";

    static const char* jedge_mgbus_login_key_ = "_lk";
    static const char* jedge_mgbus_login_sid_ = "_si";
    static const char* jedge_mgbus_login_multi_forbidden_ = "_fm";
    static const char* jedge_mgbus_login_login_debug_ = "_dg";
    static const char* jedge_mgbus_login_sdk_ = "_sdk";

    static const int INVALID_CALL_ID = -1;                      //无效的callid
    static const int default_time_out_msec = 6000;
    static const int default_time_out_msec_udp_read = 30000;
    static const char* vkey_config_mgbus_host = "mg_host";
    static const char* sval_default_mghost_ = "127.0.0.1";
    static const char* vkey_config_mgbus_port = "mg_port";
    static const char* vkey_config_mgbus_type = "sc_type";
    static const char* vkey_config_mgbus_autofind = "mg_auto";
    static const char* vkey_config_mgbus_trylocal = "mg_local";
    static const int ival_default_mgport_ = 8877;

    static const int REQUEST_RESULT_CODE_OK = 200;              //OK
    static const int REQUEST_RESULT_CODE_UNHANDLED = 404;       //未处理
    static const int REQUEST_RESULT_CODE_POST_ERR = 503;        //消息发送错误
    static const int REQUEST_RESULT_CODE_TIMEOUT = 504;         //超时

    static const char* TIME_OUT_MSG = "Request timeout";        //无效的callid

    static const char* MG_SERVICE_URI_PATTERN = "uri";
    static const char* MG_MESSAGE_CODE = "code";
    static const char* MG_MESSAGE_MSG = "msg";
    static const char* MG_MESSAGE_PARAM = "param";
    static const char* MG_MESSAGE_PAYLOAD = "payload";

    static const char* MG_MODULE_PATH_SIGN_PREFIX = "/@mg.";        //@mg.target.module.remote格式
    static const unsigned char MG_MODULE_PATH_SIGN_PREFIX_LEN = 5;

    static const char* JEDGE_MGBUS_MODUAL_MGS_SERVICE_DEBUG_ = "#d";
    static const char* JEDGE_MGBUS_MODUAL_MGS_SERVICE_DEFAULT_ = "#m";
    static const char* JEDGE_MGBUS_URI_DEBUG_LOG = "dbg_log";
    static const char* JEDGE_DEFAULT_SERVICE_COMMAND = "dftSvcCmd";
    static const char* vkey_debug_log_target_module = "k";
    static const char* vkey_debug_log_target_module_ = "param.k";
    static const char* vkey_debug_log_command_ = "param.c";
    static const char* vkey_debug_log_target_module_all = "__all";
    static const char* vkey_loginName = "loginName";

    //配置命令系统
    static const char* JEDGE_MGBUS_CONFIG_SERVICE_NAME = "@c";

    //事件系统
    static const char* JEDGE_MGBUS_EVENT_EVENT = "_e";
    static const char* JEDGE_MGBUS_EVENT_KEY = "_k";
    static const char* JEDGE_MGBUS_EVENT_KEY_DEFAULT = "@";
    static const char* JEDGE_MGBUS_EVENT_CALLBACK = "_cb";
    static const char* JEDGE_MGBUS_EVENT_SRC = "_m";
    static const char* JEDGE_MGBUS_EVENT_WATCH_ID = "_i";
    static const char* JEDGE_MGBUS_EVENT_SERVICE_NAME = "@t";
    static const char* JEDGE_MGBUS_EVENT_URI_WATCH = "/@t/watch";
    static const char* JEDGE_MGBUS_EVENT_URI_REMOVE = "/@t/remove";

#define IsMgdebugModule(_s) \
    ((_s).size()>5 && (_s)[0]=='m' && (_s)[1]=='g' && (((_s)[2]=='u' && (_s)[3]=='t') || (_s)[2]=='d'))

#define MkRsp(msg,code,smsg) \
    setAsyncCallResponse(msg);\
    (msg).setInt(jedge::MG_MESSAGE_CODE, (code));\
    (msg).setString(jedge::MG_MESSAGE_MSG, (smsg))

    //返回一个默认未处理消息
#define unHdlRsp(rsp) \
    MkRsp((rsp), REQUEST_RESULT_CODE_UNHANDLED, StringUtils::formatString("Unhandled Service message request %s", GetMgUri(rsp).c_str()))

#define OkRsp(rsp) MkRsp(rsp, 200, "Ok")
#define OkMsgRsp(rsp,msg) MkRsp(rsp, 200, msg)
#define FailRsp(rsp) MkRsp(rsp, 201, "Failed.")
#define FailMsgRsp(rsp, msg)  MkRsp(rsp, 201, msg)

#define OkPRsp(rsp) \
    if(rsp!=nullptr) {MkRsp(*(rsp), 200, "Ok.");}
#define OkPRspMsg(rsp, msg) \
    if(rsp!=nullptr) {MkRsp(*(rsp), 200, (msg));}
#define OkPRspMsgFmt(rsp, msg, ...) \
    if(rsp!=nullptr) {MkRsp(*(rsp), 200, StringUtils::formatString((msg), ##__VA_ARGS__));}
#define FailPRsp(rsp) \
    if(rsp!=nullptr) {MkRsp(*(rsp), 401, "Failed.");}
#define FailPRspMsg(rsp,msg) \
    if(rsp!=nullptr) {MkRsp(*(rsp), 401, (msg));}
#define FailPRspMsgFmt(rsp, msg, ...) \
    if(rsp!=nullptr) {MkRsp(*(rsp), 401, StringUtils::formatString((msg), ##__VA_ARGS__));}
#define MkPRsp(rsp,code,msg) \
    if(rsp!=nullptr) {MkRsp(*(rsp), code, msg);}
#define NoHandleRsp(rsp) \
    if(rsp!=nullptr) {MkRsp(*(rsp), 404, "Not handled.");}
#define MgMsgCode(msg) \
    (msg).getInt(jedge::MG_MESSAGE_CODE)
#define MgMsgStr(msg) \
    (msg).getString(jedge::MG_MESSAGE_MSG)

#define IsMsgOk(msg) \
    ((msg).getInt(jedge::MG_MESSAGE_CODE) == 200)

    static const char* MG_SERVICE_HOST = "~host";
    static const char* MG_SERVICE_MTHD = "~method";
    static const char* MG_SERVICE_DEST = "~target";

    static const char* MG_SERVICE_FILE = "~file";
    static const char* MG_SERVICE_FILENAME = "~name";
    static const char* MG_SERVICE_MIME = "~mime";


    //判断是否是异步Call的返回消息
#define getJedgeCallId(message)         ((message).getObjFmtInt(jedge::JEDGE_CALL_CALLID_KEY,-1))         //值已经被设置
#define isRequestMessage(message)       ((message).getObjFmtInt(jedge::JEDGE_CALL_CALLID_KEY,-1)!=-1)     //值已经被设置
#define isCallResponse(message)         ((message).getObjFmtInt(jedge::JEDGE_CALL_RESPONSE_KEY,-1)==-1)   //值未被设置
#define setAsyncCallResponse(message)   (message).removeObjFmtKey(jedge::JEDGE_CALL_RESPONSE_KEY)         //设置为-1
#define unsetAsyncCallResponse(message) (message).setObjFmtInt(jedge::JEDGE_CALL_RESPONSE_KEY, 1)          //设置为1

#define isMgbusCall(msg)                 ((msg).containsKey(JEDGE_MGCALL_PREFIX_HEAD))
    //拷贝调用信息，两个变量用于防止同消息交换，拷贝callid
#define copyJedgeCallInfo(res, req)  \
    Json::Value __vt_s,__vt_t;\
    (res).copyObjFmtValue(req, jedge::JEDGE_CALL_CALLID_KEY);\
    (res).copyData(req, jedge::MG_SERVICE_URI_PATTERN, nullptr);\
    ((req)).getObjFmtValue(jedge::JEDGE_MGBUS_KEY_TARGET,__vt_t);\
    ((req)).getObjFmtValue(jedge::JEDGE_MGBUS_KEY_SOURCE,__vt_s);\
    SetMgCallId(res,GetMgCallId(req));\
    if(!__vt_t.isNull()) (res).putObjFmtValue(jedge::JEDGE_MGBUS_KEY_SOURCE,__vt_t); else (res).clearObjFmtKey(jedge::JEDGE_MGBUS_KEY_SOURCE);\
    if(!__vt_s.isNull()) (res).putObjFmtValue(jedge::JEDGE_MGBUS_KEY_TARGET,__vt_s); else (res).clearObjFmtKey(jedge::JEDGE_MGBUS_KEY_TARGET)

#define copyJedgeCallInfoNoUri(res, req)  \
    Json::Value __vt_s,__vt_t;\
    (res).copyObjFmtValue(req, jedge::JEDGE_CALL_CALLID_KEY);\
    ((req)).getObjFmtValue(jedge::JEDGE_MGBUS_KEY_TARGET,__vt_t);\
    ((req)).getObjFmtValue(jedge::JEDGE_MGBUS_KEY_SOURCE,__vt_s);\
    SetMgCallId(res,GetMgCallId(req));\
    if(!__vt_t.isNull()) (res).putObjFmtValue(jedge::JEDGE_MGBUS_KEY_SOURCE,__vt_t); else (res).clearObjFmtKey(jedge::JEDGE_MGBUS_KEY_SOURCE);\
    if(!__vt_s.isNull()) (res).putObjFmtValue(jedge::JEDGE_MGBUS_KEY_TARGET,__vt_s); else (res).clearObjFmtKey(jedge::JEDGE_MGBUS_KEY_TARGET)

    //拷贝调用信息，两个变量用于防止同消息交换
#define switchTSOfJedgeCallInfo(msg)  \
    Json::Value __vt_scp,__vt_tcp;\
    ((msg)).getObjFmtValue(jedge::JEDGE_MGBUS_KEY_TARGET,__vt_tcp);\
    ((msg)).getObjFmtValue(jedge::JEDGE_MGBUS_KEY_SOURCE,__vt_scp);\
    if(!__vt_tcp.isNull()) (msg).putObjFmtValue(jedge::JEDGE_MGBUS_KEY_SOURCE,__vt_tcp); else (msg).clearObjFmtKey(jedge::JEDGE_MGBUS_KEY_SOURCE);\
    if(!__vt_scp.isNull()) (msg).putObjFmtValue(jedge::JEDGE_MGBUS_KEY_TARGET,__vt_scp); else (msg).clearObjFmtKey(jedge::JEDGE_MGBUS_KEY_TARGET)

#define clearJedgeCallInfo(msg) \
    (msg).removeKey(jedge::JEDGE_MGCALL_PREFIX_HEAD)

#define clearJedgeMgbusInfo(msg) \
    (msg).clearObjFmtKey(jedge::JEDGE_MGBUS_KEY_SOURCE); \
    (msg).clearObjFmtKey(jedge::JEDGE_MGBUS_KEY_TARGET)

#define GetJedgeCommand(msg) \
    (msg).getObjFmtString(jedge::JEDGE_MGBUS_CMD_KEY)
#define SetJedgeCommand(msg, cmd) \
    (msg).putObjFmtString(jedge::JEDGE_MGBUS_CMD_KEY, cmd)
#define ClearMgCallCmd(msg) \
    (msg).removeObjFmtKey(jedge::JEDGE_MGBUS_CMD_KEY)

#define MgModTarget(req, mod) \
    std::string mod; (req).getObjFmtString(jedge::JEDGE_MGBUS_MODUAL_KEY_TARGET,mod)
#define GetMgModTarget(req) \
    (req).getObjFmtString(jedge::JEDGE_MGBUS_MODUAL_KEY_TARGET)
#define MgModSource(req, mod) \
    std::string mod;(req).getObjFmtString(jedge::JEDGE_MGBUS_MODUAL_KEY_SOURCE,mod)
#define GetMgModSource(req) \
    (req).getObjFmtString(jedge::JEDGE_MGBUS_MODUAL_KEY_SOURCE)
#define SetMgModTarget(req,val) \
    ((req).putObjFmtString(jedge::JEDGE_MGBUS_MODUAL_KEY_TARGET,val))
#define SetMgModSource(req,val) \
    ((req).putObjFmtString(jedge::JEDGE_MGBUS_MODUAL_KEY_SOURCE,val))

#define MgChnTarget(req,chn) \
    std::string chn;  (req).getObjFmtString(jedge::JEDGE_MGBUS_CHANNEL_KEY_TARGET, chn)
#define MgChnTargetV(req) \
    (req).getObjFmtString(jedge::JEDGE_MGBUS_CHANNEL_KEY_TARGET)
#define MgChnSource(req,chn) \
    std::string chn;  (req).getObjFmtString(jedge::JEDGE_MGBUS_CHANNEL_KEY_SOURCE, chn)
#define SetMgChnTarget(req,val) \
    ((req).putObjFmtString(jedge::JEDGE_MGBUS_CHANNEL_KEY_TARGET,val))
#define SetMgChnSource(req,val) \
    ((req).putObjFmtString(jedge::JEDGE_MGBUS_CHANNEL_KEY_SOURCE,val))

#define MgRmtTarget(req, rmt) \
    std::string rmt;  (req).getObjFmtString(jedge::JEDGE_MGBUS_REMOTE_KEY_TARGET, rmt)
#define MgRmtTargetV(req) \
    (req).getObjFmtString(jedge::JEDGE_MGBUS_REMOTE_KEY_TARGET)
#define MgRmtSource(req, rmt) \
    std::string rmt;  (req).getObjFmtString(jedge::JEDGE_MGBUS_REMOTE_KEY_SOURCE, rmt)
#define SetMgRmtTarget(req,val) \
    ((req).putObjFmtString(jedge::JEDGE_MGBUS_REMOTE_KEY_TARGET,val))
#define SetMgRmtSource(req,val) \
    ((req).putObjFmtString(jedge::JEDGE_MGBUS_REMOTE_KEY_SOURCE,val))

#define MgCltTarget(req, clt) \
    std::string clt;  (req).getObjFmtString(jedge::JEDGE_MGBUS_CLIENT_KEY_TARGET,clt)
#define MgCltTargetV(req, clt) \
    (req).getObjFmtString(jedge::JEDGE_MGBUS_CLIENT_KEY_TARGET)
#define MgCltSource(req, clt) \
    std::string clt;  (req).getObjFmtString(jedge::JEDGE_MGBUS_CLIENT_KEY_SOURCE,clt)
#define SetMgCltTarget(req,val) \
    ((req).putObjFmtString(jedge::JEDGE_MGBUS_CLIENT_KEY_TARGET,val))
#define SetMgCltSource(req,val) \
    ((req).putObjFmtString(jedge::JEDGE_MGBUS_CLIENT_KEY_SOURCE,val))

#define GetMgCallId(req) \
    ((req).getObjFmtInt(jedge::JEDGE_CALL_CALLID_KEY,INVALID_CALL_ID))
#define SetMgCallId(req,id) \
    ((req).setObjFmtInt(jedge::JEDGE_CALL_CALLID_KEY,id))
#define ClearMgCallId(req) \
    ((req).clearObjFmtKey(jedge::JEDGE_CALL_CALLID_KEY))

#define SetMgMsgUri(req, uri) \
    (req).putString(jedge::MG_SERVICE_URI_PATTERN, uri)
#define GetMgUri(req) \
    (req).getString(jedge::MG_SERVICE_URI_PATTERN)

#define SetMgMsgTimeout(req, toms) \
    (req).putObjFmtValue(jedge::JEDGE_CALL_REQ_TIMEOUT, toms)
#define GetMgMsgTimeout(req) \
    (req).getObjFmtValue(jedge::JEDGE_CALL_REQ_TIMEOUT)

#define GetMgHost(mod) \
    StringUtils::getSubStrAfter((mod), '@', 1)
#define GetMgRealMod(mod) \
    StringUtils::getSubStrBefore((mod),'@',1)

#define GetWatchSrc(w) (w).getString(JEDGE_MGBUS_EVENT_SRC)
#define GetCallback(w) (w).getString(JEDGE_MGBUS_EVENT_CALLBACK)
#define GetWatchKey(w) (w).getString(JEDGE_MGBUS_EVENT_KEY)
#define GetWatcherId(w) (w).getInt(JEDGE_MGBUS_EVENT_WATCH_ID)

#define SetWatchSrc(w, target) (w).putString(JEDGE_MGBUS_EVENT_SRC, target)
#define SetWatcherId(w, id) (w).setInt(JEDGE_MGBUS_EVENT_WATCH_ID, id)

#define isEventMessage(w) ((w).containsKey(JEDGE_MGEVENT_PREFIX_HEAD))

}

#ifdef DEBUG
#define MGLogReq(pChr,...) ULogC(qlog_light_green, pChr, ##__VA_ARGS__)
#define MGLogRsp(pChr,...) ULogC(qlog_light_purple, pChr, ##__VA_ARGS__)
#define MGLogTrc(pChr,...) ULogC(qlog_light_cyan, pChr, ##__VA_ARGS__)
#else
#define MGLogReq(pChr,...) ULogC(qlog_light_green, pChr, ##__VA_ARGS__)
#define MGLogRsp(pChr,...) ULogC(qlog_light_purple, pChr, ##__VA_ARGS__)
#define MGLogTrc(pChr,...) ULogC(qlog_light_cyan, pChr, ##__VA_ARGS__)
//    #define MGLogReq(pChr,...)
//    #define MGLogRsp(pChr,...)
//    #define MGLogTrc(pChr,...)
#endif

#endif //LIBDEVCPP_MGBUSCOMMON_H
