
#include "MediaInfoProtocol.h"
#include "MediaWebSocketService.h"
#include "MediaClientService.h"
#include "Rtp808Service.h"

namespace mfs
{

    enum ECommandID
    {
        ECOMMANDID_LOGLEVEL = 61001,            // 设置日志级别
        ECOMMANDID_SAVESTREAM = 61002,          // 抓取数据
        ECOMMANDID_CLOSEROOM = 61003,           // 关闭房间
        ECOMMANDID_SELECTSTREAM = 62001,        // 查询连接信息
        
        ECOMMANDID_FLOWINFO1 = 65601,           // 流量信息
    };
    void MediaInfoProtocol::SendMessage(const std::string& msg)
    {
        uint32_t size = msg.size();
        uint32_t dataSize = swapBigEndian(size);
        iovec datas[2] = {{&dataSize, 4}, {const_cast<char*>(msg.data()), static_cast<size_t>(size)}};
        int result = BaseProtocol::WriteV(datas, 2);
        if(result == -3){
            std::stringstream ss;
            ss << _serviceName <<">Write buffer is full, data len: " << msg.size() << ", buffer size: " << _writeBufferSize;
            loge(ss.str());
            _streamInfo.message = "Buffer full(w)";
        }
    }

    void MediaInfoProtocol::OnData(char* data, int dataLen) 
    {
        _readParam.second += dataLen;
        while(true)
        {
            auto parseResult = parseCLBSCommand();
            if(parseResult != 0)
            {
                break;
            }
        }
    };
    
    
    void MediaInfoProtocol::OnAlloc(uv_buf_t *buf, int suggested)
    {
        int freeSize = _readParam.first.size() - _readParam.second;
        if(freeSize < READ_BUFFER_STEP)
        {
            int newSize = _readParam.first.size() + READ_BUFFER_STEP;
            if (newSize >  AppSetting::Instance()->readbufferMax)
            {
                std::stringstream ss;
                ss << "Read buffer full:"<<errno;
                loge(ss.str());
                _streamInfo.message = "Buffer full(r)!";
                this->Close();
                return;
            }
            _readParam.first.resize(newSize);
        }
        buf->base = (char*)_readParam.first.data() + _readParam.second;
        buf->len = _readParam.first.size() - _readParam.second;
    } 
    int MediaInfoProtocol::parseCLBSCommand()
    {
        // 检测缓存数据是否足够
        int sizeOffset = sizeof(uint32_t);
        if (_readParam.second < sizeOffset)
        {
            return -1;
        }
        uint32_t dataSize = *((uint32_t*)_readParam.first.data());
        dataSize = swapBigEndian(dataSize);
        auto oneCommandSize = sizeOffset + dataSize;
        if (_readParam.second < oneCommandSize)
        {
            return -2;
        }

        // 处理一条指令
        std::vector<char> strCommand(dataSize+1, 0);
        memcpy(strCommand.data(), _readParam.first.data()+sizeOffset, dataSize);
        LOG_DEBUG << "executeCLBSCommand:"<<strCommand.data()<<LOG_ENDL;
        int iret = executeCLBSCommand(strCommand.data());
        if (iret != 0)
        {
            LOG_ERROR << "fail parse command:"<<strCommand.data()<<LOG_ENDL;
        }

        _readParam.second -= oneCommandSize;
        if (_readParam.second>0)
        {
            memcpy(_readParam.first.data(), _readParam.first.data()+oneCommandSize, _readParam.second);
        }
        

        return iret;
    }
    
    int MediaInfoProtocol::getMessageID(cJSON* dataNode, int& msgID)
    {
        cJSON* headNode = cJSON_GetObjectItem(dataNode, "msgHead");
        if (!headNode)
        {
            return -1;
        }
        cJSON* msgIDNode = cJSON_GetObjectItem(headNode, "msgID");
        if (!msgIDNode)
        {
            return -1;
        }
        msgID = msgIDNode->valueint;
        return 0;
    }
    int MediaInfoProtocol::executeCLBSCommand(const char* strJson)
    {
        // LOG_DEBUG << "executeCLBSCommand - start"<<LOG_ENDL;
        auto result = -1;

        cJSON* cjson = nullptr;
        do
        {
            // LOG_DEBUG << "executeCLBSCommand - parse json"<<LOG_ENDL;
            cjson = cJSON_Parse(strJson);
            if (!cjson)
            {
                LOG_WARN << "executeCLBSCommand - fail parse json"<<LOG_ENDL;
                break;
            }
            // LOG_DEBUG << "executeCLBSCommand - get data"<<LOG_ENDL;
            cJSON* dataNode = cJSON_GetObjectItem(cjson, "data");
            if (!dataNode)
            {
                LOG_WARN << "executeCLBSCommand - no data"<<LOG_ENDL;
                break;
            }

            // LOG_DEBUG << "executeCLBSCommand - get msgid"<<LOG_ENDL;
            int messageID = 0;
            int iret = getMessageID(dataNode, messageID);
            if (iret != 0)
            {
                LOG_WARN << "executeCLBSCommand - no message id"<<LOG_ENDL;
                break;
            }

            cJSON* bodyNode = cJSON_GetObjectItem(dataNode, "msgBody");
            // LOG_DEBUG << "executeCLBSCommand - execute msgid:"<< messageID<<LOG_ENDL;
            switch (messageID)
            {
            case ECOMMANDID_LOGLEVEL:
                iret = commandSetLogLevel(bodyNode);
                break;
            case ECOMMANDID_SAVESTREAM:
                iret = commandSaveStreamData(bodyNode);
                break;
            case ECOMMANDID_SELECTSTREAM:
                iret = commandSelectStream(bodyNode);
                break;
            default:
                LOG_WARN << "Unknow message ID!"<< LOG_ENDL;
                break;
            }
            result = iret;
        }while(0);
        if (cjson)
        {
            cJSON_Delete(cjson);
        }
        return result;
    }


    
    int MediaInfoProtocol::commandSetLogLevel(cJSON* dataNode)
    {
        cJSON* levelNode = cJSON_GetObjectItem(dataNode, "level");
        if (!levelNode)
        {
            LOG_WARN << "commandSetLogLevel - no parameter"<<LOG_ENDL;
            return -1;
        }
        auto level = levelNode->valueint;
        Log::setCurrentLevel(LogLevel(level));
        return 0;
    }
    
    int MediaInfoProtocol::commandSaveStreamData(cJSON* dataNode)
    {
        cJSON* targetIDNode = cJSON_GetObjectItem(dataNode, "targetID");
        cJSON* enableNode = cJSON_GetObjectItem(dataNode, "enable");
        if (!targetIDNode || !enableNode)
        {
            LOG_WARN << "commandSaveStreamData - no parameter"<<LOG_ENDL;
            return -1;
        }
        auto targetIDStr = targetIDNode->valuestring;
        uint64_t targetID = std::stoul(targetIDStr);
        int enable = enableNode->valueint;
    
        Rtp808Service::Instance(AppSetting::Instance()->childProcessState[AppSetting::Instance()->typeIndex].rtpPort)->SaveDataByTargetID(targetID, enable);
        Rtp808Service::Instance(AppSetting::Instance()->childProcessState[AppSetting::Instance()->typeIndex].rtpPortyb)->SaveDataByTargetID(targetID, enable);
        MediaWebSocketService::Instance()->SaveDataByTargetID(targetID, enable);
        MediaClientService::Instance()->SaveDataByTargetID(targetID, enable);
        return 0;
    }

    int MediaInfoProtocol::commandSelectStream(cJSON* dataNode)
    {
        cJSON* targetNode = cJSON_GetObjectItem(dataNode, "target");
        if (!targetNode)
        {
            LOG_WARN << "commandSelectStream - no parameter"<<LOG_ENDL;
            return -1;
        }

        std::vector<StreamInfo> streamInfos;
        auto target = targetNode->valueint;
        if (target & 1)
        {
            MediaWebSocketService::Instance()->GetAllStreamInfo(streamInfos);
        }
        if (target & 2)
        {
            Rtp808Service::Instance(AppSetting::Instance()->childProcessState[AppSetting::Instance()->typeIndex].rtpPort)->GetAllStreamInfo(streamInfos);
            Rtp808Service::Instance(AppSetting::Instance()->childProcessState[AppSetting::Instance()->typeIndex].rtpPortyb)->GetAllStreamInfo(streamInfos);
        }
        if (target & 4)
        {
            MediaClientService::Instance()->GetAllStreamInfo(streamInfos);
        }

        std::string jsonstr;
        parseStreamInfoJson(streamInfos, jsonstr);
        SendMessage(jsonstr);

        return 0;
    }
    void MediaInfoProtocol::parseStreamInfoJson(const std::vector<StreamInfo>& vec, std::string& result)
    {

        std::stringstream ss;
        ss << "{\"data\":{\"msgHead\":{\"msgID\":63001},\"msgBody\":{	\"result\":[";

        for(auto info : vec)
        {
            ss<<"{"
            << "\"targetID\":"+info.targetID+","   
            << "\"targetType\":"+info.targetType+","                  
            << "\"ip\":\""+info.ip+"\","                      
            << "\"port\":"+info.port+","                      
            << "\"state\":"+info.state+","                    
            << "\"timestampStart\":"+info.timestampStart+","  
            << "\"timestampEnd\":"+info.timestampEnd+","      
            << "\"message\":\""+info.message+"\","            
            << "\"sendBytes\":"+info.sendBytes+","            
            << "\"recvBytes\":"+info.recvBytes+","            
            << "\"simNumber\":\""+info.simNumber+"\","        
            << "\"channel\":"+info.channel+","                
            << "\"uuid\":\""+info.uuid+"\""           
            <<"}";
        }

        ss << "]}}}";
        result = ss.str();
    }
}