
#ifndef _IMEDIACLIENTCONNECTION_H_
#define _IMEDIACLIENTCONNECTION_H_

#include "MFSPublic.h"
#include "BaseProtocol.h"
#include "AppSetting.h"
#include "ZWRedisTool.h"
namespace mfs
{
    #define DEVICETYPE_YUEBIAO  "28"        // 粤标

    // 返回给客户端信息CODE
    enum EErrorCode
    {
        
        RtcIceCandidate = 2002,         // RTC - Ice Candidate
        RtcAnswer = 2001,               // RTC - Offer Answer   (SDP协议)
        RoomKey = 1101,                 // 房间KEY
        ConnectTerminal = 1001,         // 终端建立连接
        ParameterMissBase = -1001,      // 
        ParameterMissPlayback = -1002,  // 
        PlayCommandFail = -1003,  // 
        PlayCommandTimeout = -1004,  // 
        MediaDataTimeout = -1005,
        MediaDataError = -1006,
        ParameterMissControl = -1007,
        ChannelBusy = -1008,
        TerminalBusy = -1009,
        ErrorMessageData = -1010,
        TerminalBreak = -1011,
        DuplicateCommand = -1012,
    };

    inline std::string GetErrorMessage(EErrorCode code){
        switch (code)
        {
        case EErrorCode::ConnectTerminal:
            return "终端连接成功，等待媒体数据";
        case EErrorCode::ParameterMissBase:
            return "缺少播放必填参数";
        case EErrorCode::ParameterMissPlayback:
            return "缺少回放参数";
        case EErrorCode::PlayCommandFail:
            return "指令下发失败";
        case EErrorCode::PlayCommandTimeout:
            return "指令应答超时";
        case EErrorCode::MediaDataTimeout:
            return "终端数据获取超时";
        case EErrorCode::MediaDataError:
            return "终端数据异常";
        case EErrorCode::ParameterMissControl:
            return "缺少控制参数";
        case EErrorCode::ChannelBusy:
            return "通道被占用";
        case EErrorCode::TerminalBusy:
            return "通道重置中";
        case EErrorCode::ErrorMessageData:
            return "解析透传消息失败";
        case EErrorCode::TerminalBreak:
            return "终端已断开";
        case EErrorCode::DuplicateCommand:
            return "重复发送指令";
        default:
            return "未知错误!";
        }
    }

    struct PlayerFragment
    {
        std::string startTime;
        std::string endTime;
        std::chrono::system_clock::time_point start_point;
        std::chrono::system_clock::time_point end_point;
    };
    struct PlayerSetting
    {
        std::string vehicleId;      // 车辆id
        std::string simcardNumber;  // 终端手机卡号
        std::string channelNumber;	        // 终端通道号
        std::string sampleRate;	            // 音频采样率
        std::string channelCount;	        // 音频声道数
        std::string audioFormat;    // 音频编码
        std::string playType;       // 播放类型(实时 REAL_TIME，回放 TRACK_BACK，对讲 BOTH_WAY，监听 UP_WAY，广播 DOWN_WAY)
        std::string dataType;               // 播放数据类型(0：音视频，1：视频，2：双向对讲，3：监听，4：中心广播，5：透传)
        std::string userID;         // 用户ID
        std::string deviceID;       // 终端ID
        std::string streamType;             // 码流类型(0：主码流，1：子码流)
        // 播放参数 - 回放时使用
        std::string startTime;      // 开始时间
        std::string endTime;        // 结束时间
        std::string remoteMode;             // 回放方式(0：正常回放 1：快进回放 2：关键帧快退回放 3：关键帧播放 4：单帧上传)
        std::string forwardOrRewind;        // 快进快退倍数(回放方式为1和2时，此字段有效，否则为0. 0：无效 1：1倍 2：2倍 3：4倍 4：8倍 5：16倍)
        std::string storageType;            // 存储器类型(1主存储器 2灾备存储器)
        std::string forward0Copy;           // 1:0拷贝;其它：和包数据
        std::string disableData;            // 1:禁用数据转发； 其它：正常转发
        std::string deviceType;         // 设备类型
        std::string monitorId;          // 监控对象ID
        std::string clientId;           // 细分ID

        std::vector<PlayerFragment> fragments;  // 所有的回放片段
        // int fragmentIndex;                  // 当前正在播放的片段索引
        std::chrono::system_clock::time_point startTimePointAbs;   // 开始时间对应的调用绝对时间点
        std::chrono::system_clock::time_point startTimePoint;       // 开始时间


    };

    struct ControlSetting
    {
        // 实时视频
        std::string streamType;         // 码流类型(0：主码流，1：子码流)
        std::string closeVideoType;     // 关闭类型 0:全关 1:只关音频 2:只关视频
        std::string control;            // 0: 关闭音视频传输指令；1 : 切换码流（增加暂停和继续）；2: 暂停该通道所有流的发送；3: 恢复暂停前流的发送，与暂停前的流类型一致；4: 关闭双向对讲
        // 视频回放
        std::string dragPlaybackTime;   // 拖动回放时间点（YYMMDDHHmmss）回放控制为5时有效，否则全为0
        std::string forwardOrRewind;    // 快进快退 回放控制为3或4是有效，否则为0 0：无效 1：1倍 2：2倍 3：4倍 4：8倍 5：16倍
        std::string remote;             // 回放控制 0：开始回放 1：暂停回放 2：结束回放 3：快进回放 4：关键帧快退回放 5：拖地回放 6：关键帧播放
    };


    class MediaClientConnection: public BaseProtocol
    {
        private:
            void OnReadyWebSocket();
        protected:
            // BaseProtocol
            std::pair<std::vector<uint8_t>, int> _readParam;
            bool _isPause = false;
            bool _firstFrame = true;
            bool _isSaveTalk = false;
            bool _isTalk = false;
            bool _isPlayback = false;                                                   // 是否回放
            bool _waitIFrame = false;
            uint64_t _currentDataLen = 0;
            
            
            std::string _url;
            std::string _temp;
            std::string _key;
            std::string _version;
            std::string _audioFormat;
            std::string _roomKey;                                                       // 房间uuid
            PlayerSetting _playerSetting;
            bool _firstFrameSend=true;
            // uint64_t _
            WEBSOCKET_STATUS _status = WEBSOCKET_INIT;

            int _isRecordAudio = 0;                                                     // 是否是录音流

            std::string _uuid;                                                          // 车辆uuid

            virtual int parse(int length) = 0;
            virtual int recvHandShakeData() = 0;
            virtual int sendHandShakeData() = 0;

            int preWriteData(char* data, int dataLen);
            int preFilter(uint8_t* data, int len);
        public:
            // BaseProtocol
            MediaClientConnection(std::shared_ptr<uvw::Loop> loop, std::shared_ptr<uvw::TCPHandle> client, const std::string& name)
            :BaseProtocol(loop, client, name)
            {
                client->userAlloc(true);
                _readParam.second = 0;
                _isPlayback = IsContainsStr(name,"Playback"); 
                _isTalk = IsContainsStr(name,"Talkback"); 
                _isSaveTalk = AppSetting::Instance()->holdTalkWeb;
                logd(std::to_string((int64_t)this));
            }
            ~MediaClientConnection(){
                logd(std::to_string((int64_t)this));
            }
            virtual bool CheckTimeout(int timeoutMilli) override;
            virtual void OnData(char* data, int dataLen) override;
            virtual void OnAlloc(uv_buf_t *buf, int suggested) override; 
            virtual void OnClose() override;
            virtual void OnConnection() override;
            virtual void OnReady() override; 

            void OnRecvData();
        public:
            // ZWRoom
            void closeConnection(const char* msg){
                _streamInfo.message=msg; 
                logd(msg);
                this->Close();
            };
            void sendMessage(int code) { this->sendMessage(code, GetErrorMessage((EErrorCode)code)); }
            void sendMessage(int code, const std::string& message);
            inline const std::string& getUrl() {return _url;}    
            inline const std::string& getUuid(){return _uuid;};
            PLAY_TYPE getPlayType()
            {return _serviceName == "RealStream" ?PLAY_TYPE::REALTIME:_serviceName=="Talkback"?PLAY_TYPE::TALKBACK:PLAY_TYPE::PLAYBACK;}

            
            virtual int writeData(char* data, int dataLen) = 0;
            virtual void sendMessage(const char* data, int dataLen)=0;
            virtual void generatePackageHead(int dataLen, char* head, int& headLen);
            virtual void generatePackageTail(int dataLen, char* tail, int& tailLen);
                    
            inline const PlayerSetting& getPlayerSetting(){return _playerSetting;}; 
            
            virtual bool onlyRaw(){return false;}

            void setOnRelease(std::function<void(MediaClientConnection*,BaseProtocol*)> callback)
            {
                _onRelease = callback;
            }
            void setOnDataCallback(std::function<void(MediaClientConnection*,BaseProtocol*,char*,int)> callback)
            {
                _onDataCallback = callback;
            }
            void setOnAudioDataCallback(std::function<void(MediaClientConnection*,BaseProtocol*,char*,int)> callback)
            {
                _onAudioDataCallback = callback;
            }
            void setOnControlMediaClient(std::function<void(MediaClientConnection*,BaseProtocol*,const ControlSetting& setting)> callback)
            {
                _onControlCallback = callback;
            } 
            
        protected:
            std::function<void(MediaClientConnection*,BaseProtocol*)> _onRelease;
            std::function<void(MediaClientConnection*,BaseProtocol*,char*,int)> _onAudioDataCallback;
            std::function<void(MediaClientConnection*,BaseProtocol*,char*,int)> _onDataCallback;
            std::function<void(MediaClientConnection*,BaseProtocol*,const ControlSetting& setting)> _onControlCallback;
        
            void onRtpData(uint8_t* data, int len);
            // messgae
            void onMessage(const std::string& str);
            void onMessagePlay(cJSON* pars);
            void onMessageControl(cJSON* pars);
            // RTC - Offer (SDP协议)
            void onMessageRtcOffer(cJSON* pars);
            // RTC - Ice Candidate ()
            void onMessageRtcIceCandidate(cJSON* pars);
            
            int loadPlayerSetting(cJSON* pars);
            int loadControlSetting(cJSON* pars, ControlSetting &controlSetting);

    };
}
#endif // _IMEDIACLIENTCONNECTION_H_