//
// Created by Ht on 2020/8/21.
//

#ifndef LIBDEVCPP_QCOMMONPROTOCOL_H
#define LIBDEVCPP_QCOMMONPROTOCOL_H

#include <jebase/config.h>

namespace jedge {


    using protocolMessageHandler = JE_API std::function<bool(const std::string& sourceKey, const std::string& cmd, qlibc::QData& param, SocketMode mode)>;

    //处理Mgbus的基础通信消息
    class JE_API QCommonProtocol {
    protected:
        qlibc::QSharedObjectHolder<protocolMessageHandler> handlers_;
        qlibc::QSharedObjectHolder<qlibc::QData>  message_templs_d_;
        qlibc::QSharedObjectHolder<std::string>   message_templs_s_;
        bool init_ = false;

        virtual void initProtocol() {
            init_ = true;
        }

        void addMessage(const std::string &action, const char* message){
            auto* s = new string(message);
            (*s)+="\n";
            message_templs_s_.appendNew(action, s);
        }

        void addMessage(const std::string &action, const qlibc::QData& templ){
            auto d = new qlibc::QData(templ);
            message_templs_d_.appendNew(action, d);
        }

    public:
        explicit QCommonProtocol() {
            message_templs_s_.appendNew("",new string());
        }

        virtual ~QCommonProtocol() = default;

        //获取固定消息
        const string &getMessage(const std::string &action) {
            if(!init_)
                initProtocol();
            auto msg = message_templs_s_.findObject(action);
            if(msg != nullptr)
                return *msg;
            auto obj = message_templs_d_.findObject(action);
            if(obj!= nullptr){
                auto* s = new string(obj->toJSONString() + "\n");
                message_templs_s_.appendNew(action, s);
                return *s;
            }
            return *message_templs_s_.findObject("");
        }

        //拷贝消息模板
        bool getMessage(const std::string &action, qlibc::QData& copy) {
            if(!init_)
                initProtocol();
            auto obj = message_templs_d_.findObject(action);
            if(obj!= nullptr){
                copy.setInitData(*obj);
                return true;
            }
            return false;
        }


        void registerHanlder(const char *cmd, const protocolMessageHandler& handler) {
            auto* p = new protocolMessageHandler;
            *p = handler;
            handlers_.appendNew(cmd, p);
        }

        bool handleMessage(const std::string& sourceKey, qlibc::QData datamsg, SocketMode mode) {
            std::string cmd = datamsg.getObjFmtString(JEDGE_MGBUS_CMD_KEY);
            if(!cmd.empty()){
                auto hdlr = handlers_.findObject(cmd);
                try { return hdlr!= nullptr && hdlr->operator()(sourceKey, cmd, datamsg, mode);
                } catch (std::bad_function_call& e) {  }
            }
            return false;
        }
    };

#define defProtocolHandler(protocol,cmd,baseobj,method) \
    protocol.registerHanlder(cmd, [baseobj](const std::string& sourceKey, const std::string& cmd, qlibc::QData& param, SocketMode mode)->bool { \
        if(quit_) return true;                      \
        return method(sourceKey, cmd, param, mode); \
    })

}

#endif //LIBDEVCPP_QCOMMONPROTOCOL_H
