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

#ifndef JEDGE_SERIALHOLDER_H
#define JEDGE_SERIALHOLDER_H

#include <string>
#include <cstring>
#include <utility>
#include <qlibc/qlibc.h>
#include <thread>
#include <mgbus/ChannelOperator.h>

#include "SerialDevice.h"
#include "QClassifiedQueue.h"
#include <mgbus/MgBusHolder.h>
#include <jedp/jedp.h>
#include <serial/SerialIOGate.h>
#include <jedp/JEDPAnalyzer.h>
#include <src/vdao/QGAActionObjects.h>
#include <src/vdal/QLeveledMergeQueue.h>
#include <src/dbg/JARemoteCommandor.h>

namespace jedge {

    using SerialBytesIncomeHandler = std::function<bool(const char* byte, int bytes_len)>;
    using SerialMessageHandler = std::function<bool(qlibc::QData& msg)>;

    using RSerialBytesIncomeHandler = shared_ptr<SerialBytesIncomeHandler>;
    using RSerialMessageHandler = shared_ptr<SerialMessageHandler>;
    /**
    //  在Holder中添加各种hanlder。
    //  Holder中完成：（1）jedp转换、（2）消息处理器。针对不同的消息处理描述规则，进行描述。
    //  消息规则文件，主要描述消息的响应处理函数。
    //  消息的处理动作：（1）修改属性、（2）转发消息、（3）向串口反馈消息。
    //  在具体的响应过程中，需要：
     *      （1）设定属性的值、变量引用
     *      （2）读取消息来源的数据进行函数计算
     *
     */


    class JE_API SerialHolder :
            public SerialIOHolderInterface,
            public QGaVarHandler,
            public qlibc::JARemoteCommandor,
            public QVdalTransMessager,
            public SerialHolderInterface {

    protected:
        const RSerialBytesIncomeHandler byte_handler_;
        const RSerialMessageHandler     msg_handler_;

        SerialRootDevice     device_root_;           //网关设备

        std::string serial_type_;
        std::string serial_name_;

        QStringList mBindComList;

        std::mutex  com_mutex_;
        std::mutex  init_mutex_;
        std::mutex  last_write_m_;
        MgBusHolder&  operator_;
    public:
        void onSerialStart() override {};

    protected:
        QClassifiedQueue    *q_;

        JEDPRAnalyzer     analyzer_ = nullptr;
        JEDPRAnalyzer     analyzer_decoder_ = nullptr;       //部分可能是编解码分开定义
        SerialRebufferMakerR  rebuffer_;                     //重组buffer函数

    public:
        void onSerialDataRead(const std::string& portName, QByte *data, uint16_t len) override;

    public:
        explicit SerialHolder(MgBusHolder& opr, const std::string &serial_type,const std::string &serial_name, const SerialMessageHandler& handler)
                :  JARemoteCommandor("serial",opr),
                byte_handler_(nullptr), msg_handler_(make_shared<SerialMessageHandler>(handler))
                , device_root_ (opr, *this, serial_type, serial_name, QData(), *this)
                , serial_type_(serial_type)
                , serial_name_(serial_name)
                , operator_(opr){
            buildCommandHandlers();
        };

        void buildCommandHandlers() override;

        ~SerialHolder() override {
            rc_handlers_.releaseAll();
            auto* pGate = SerialIOGate::getGateInstance();
            SINGLE_LOCK(com_mutex_);
            for (const auto& s : mBindComList) {
                pGate->closeSerialPort(s);
            }
            mBindComList.clear();
        }

        SerialRootDevice& getRootDevice() {
            return device_root_;
        }

        //打开串口
        bool openSerial(RSerialIOHolderInterface &ioHolder);
        //关闭串口
        void closeSerialPort();

        //设备向串口写入消息，json格式，需要通过jedp转换为BYTE格式。
        virtual bool writeJsonMessage(qlibc::QData &message);

        bool startSerialRead();

        void getSubDeviceType(qlibc::QData &response, std::string &devType) override {
            //从消息中读取设备类型
            devType = "comm";
        }

        void getSubDeviceId(qlibc::QData &response, std::string &devId) override {
            //从
            devId = std::to_string(NumberUtils::randomIntger(0x1000000, 0xD000000));
        }

        inline JEDPRAnalyzer getDecoderAnalyzer() {
            return analyzer_decoder_ == nullptr?
                    analyzer_:
                    analyzer_decoder_;
        }

        inline JEDPRAnalyzer getEncoderAnalyzer() {
            return analyzer_;
        }

        const std::string &getSerialType() override;

        const std::string &getSerialName();

        bool writeSerialData(uint8_t *buff, int32_t len, unsigned int cmd_gap = 0) override;//
        bool writeSerialRawData(QByte *buff, int32_t len) override;

        void setJedpReqRuleName(const std::string &reqRule);
        void setJedpRspRuleName(const std::string &rspRule);

        bool readDataFromSerialPort(const string &srcPort, const uint8_t *buff, int32_t len);

        bool postAirMessageForModes(SerialDevice* device, qlibc::QData &msg);

        void writeSerialMessage(SerialDevice *device, qlibc::QData &msg);

        bool controlDeviceAvailable();

        bool loadGateConfigInfo(const string &serial_name, const string& serial_type, const string &base_path, const qlibc::QData& config);

        void clearDeviceData();

        bool handleExTypeVar(Json::Value &ret, const string &type, const string &varKey) override;

        void setClassifiedQueue(QClassifiedQueue* q) override;
        void handleIncomeMessage(QData &msg) override;
        void handleConfirmReplayMessage(QData &msg) override;

        void emulateSerialDataRead( const uint8_t* buff, size_t len) {
            readDataFromSerialPort(serial_name_, buff, len);
        }

        void setSerialRebufferHandler(const SerialRebufferMaker& maker) {
            rebuffer_ = make_shared<SerialRebufferMaker>(maker);
            init_mutex_.unlock();    // 在OpenSerial时锁定
        }

        void clearInitLock() {
            init_mutex_.unlock();
        }
        bool handleMogaCtrlResponse(qlibc::QData &msg);
        bool handleMogaConfigResponse(qlibc::QData &msg);
    protected:
        bool serial_emulate(const std::string& cmd, qlibc::QData& req, qlibc::QData* resp);
        bool serial_moga_emulate(const std::string& cmd, qlibc::QData& req, qlibc::QData* resp);

        bool device_run(const std::string& cmd, qlibc::QData& req, qlibc::QData* resp);


        void writeMogaMessage(SerialDevice *device, QData &msg);
    };
}

#endif //JEDGE_SERIALHOLDER_H
