
#include "Rtp808FrameParser.h"
#include "AppSetting.h"
namespace mfs
{

    static std::string getPackageDisplay(int packageType)
    {
        switch (packageType)
        {
        case 0:
        return "All";
        case 1:
        return "Begin";
        case 2:
        return "End";
        case 3:
        return "Middle";
        default:
        return "Unknow";
        }
    }
    static std::string getPayloadDisplay(int payloadType)
    {
        switch (payloadType)
        {
        case PAYLOAD_TYPE_ADPCM:
        return "ADPCMA";
        case 98:
        return "H.264";
        default:
        return "Unknow";
        }
    }
    static std::string getDataTypeDisplay(int dataType)
    {
        switch (dataType)
        {
        case RTP_808_DATATYPE_I:
        return "V/I";
        case RTP_808_DATATYPE_P:
        return "V/P";
        case RTP_808_DATATYPE_B:
        return "V/B";
        case RTP_808_DATATYPE_A:
        return "A";
        default:
        return "Unknow";
        }
    }


    // 帧头标志，固定 0X30、0X31、0X63、0X64
    static char magic[4] = {0x30, 0x31, 0x63, 0x64};
    static std::vector<char> magicVector(magic, magic+4);
    
    void Rtp808FrameParser::getSimNumberBCD(std::string& str)
    {

    }
    void Rtp808FrameParser::getSimNumber(std::pair<std::vector<uint8_t>, int>& ptrBuffer, int framePos, std::string& str, bool subSimnumber)
    {
        //01 90 00 05 16 75 -> 01 90 00 05 16 75
        // 用以辅助将RTP头部中的BCD编码转为10进制SIM卡号
        if (subSimnumber)
        {
            Rtp808HeadBaseV_YB* head = reinterpret_cast<Rtp808HeadBaseV_YB*>(ptrBuffer.first.data() + framePos);
            char bcdBuffer[21] = {0};
            for(int i = 0; i != 10; ++i)
            {
                bcdBuffer[i << 1] = (head -> simBcd[i] >> 4) + '0';
                bcdBuffer[(i << 1) + 1] = (head -> simBcd[i] & 0x0f) + '0';
            }
            str = bcdBuffer;
            // if (AppSetting::Instance()->typeIndex != 1)
            {
                // PrintBuffer((ptrBuffer.first.data()+framePos),30);
                ptrBuffer.first.erase(ptrBuffer.first.begin()+framePos+8,ptrBuffer.first.begin()+framePos+8+4);
                ptrBuffer.second-=4;
                // PrintBuffer(ptrBuffer.first.data()+framePos,30);
            }
            
        }
        else
        {
            Rtp808HeadBaseV* head = reinterpret_cast<Rtp808HeadBaseV*>(ptrBuffer.first.data() + framePos);
            char bcdBuffer[13] = {0};
            for(int i = 0; i != 6; ++i)
            {
                bcdBuffer[i << 1] = (head -> simBcd[i] >> 4) + '0';
                bcdBuffer[(i << 1) + 1] = (head -> simBcd[i] & 0x0f) + '0';
            }
            str = bcdBuffer;
        }
        
    }
    int Rtp808FrameParser::loadData(std::pair<std::vector<uint8_t>, int>& ptrBuffer, int framePos)
    {
        auto ptrData = ptrBuffer.first.data()+framePos;
        auto ptrDataLen = ptrBuffer.second - framePos;
        if(ptrDataLen < (_isYuebiao?sizeof(Rtp808HeadBaseV_YB):sizeof(Rtp808HeadBaseV)))
        {
            // 直接判断不能小于完整808头部大小，正常数据(包括Rtp808Head2的音频)不会比这个小
            return -2;
        }
        // LOG_DEBUG <<"1ptrBuffer.first.size="<<ptrBuffer.first.size()<<";1="<<ptrBuffer.first[framePos]<<LOG_ENDL;
        if (memcmp(ptrData, magicVector.data(), magicVector.size())!=0)
        {
            // LOG_DEBUG <<"change start:"<<LOG_ENDL;
            // PrintBuffer(ptrData,32);
            
            // 报批稿的数据，单字节中顺序有误，矫正下
            // v p x cc
            uint8_t utmp = ptrData[0];
            ptrData[0] = ((utmp&0b00000011)<<6)|((utmp&0b00000100)<<3)|((utmp&0b00001000)<<1)|((utmp&0b11110000)>>4);
            // m pt
            utmp = ptrData[1];
            ptrData[1] = ((utmp&0b00000001)<<7)|((utmp&0b11111110)>>1);
            // type pack
            utmp = ptrData[11];
            ptrData[11] = ((utmp&0b00001111)<<4)|((utmp&0b11110000)>>4);


            // LOG_DEBUG <<"change middle:"<<LOG_ENDL;
            // PrintBuffer(ptrData,32);

            // 报批稿增加4字节头部，同时由于音频数据多了2个帧间隔字段共4字节，恰好抵消了需要增加的4字节;
            Rtp808HeadBaseV* headTmp = reinterpret_cast<Rtp808HeadBaseV*>(ptrData);
            if (headTmp->dataType != RTP_808_DATATYPE_A)
            {
                ptrBuffer.first.insert(ptrBuffer.first.begin()+framePos, magicVector.begin(),magicVector.end());
                ptrBuffer.second+=4;
                ptrData = ptrBuffer.first.data() + framePos;
                ptrDataLen = ptrBuffer.second - framePos;
            }
            else
            {
                auto rightPos = sizeof(Rtp808HeadBaseV) - sizeof(headTmp->dataLen);
                for (int i = rightPos-1; i >= 4; i--)
                {
                    ptrData[i] = ptrData[i-4];
                }
                memcpy(ptrData, magicVector.data(), 4);
            }
            // LOG_DEBUG <<"change end:"<<LOG_ENDL;
            // PrintBuffer(ptrData,32);
        }
        // LOG_DEBUG <<"2ptrBuffer.first.size="<<ptrBuffer.first.size()<<";1="<<ptrBuffer.first[framePos+4]<<LOG_ENDL;
        // auto magicSize = magicVector.size();

        // FORWORT_ASSERT_RETURN_LOG_MSG(memcmp(data, magic, 4) == 0, "RTP Frame does not contain 30 31 63 64");
        Rtp808HeadBaseV* head = reinterpret_cast<Rtp808HeadBaseV*>(ptrData);
        // LOG_DEBUG<<"OneFrame:"<<LOG_ENDL;
        // PrintBuffer(ptrData,26);
        if (!(head -> headV == 2 && head -> headP == 0 && head -> headX == 0 && head -> headCC == 1))
        {
            do
            {
                LOG_ERROR << "error head" << LOG_ENDL;
                PrintBuffer(ptrData,32);
                _errorField = "Head";
                return -1;
            } while (false);
        }
        
        int currentNumber = swapBigEndian(head -> number);

        // LOG_DEBUG<<"_number="<<_number<<",currentNumber="<<currentNumber<<LOG_ENDL;
        if (!((_number == 65534 && currentNumber == 0) || (_number == 65535 && currentNumber == 0) || _number == -1 || (currentNumber - _number == 1)))
        {
            LOG_ERROR<< "Package Number error:_number="<<_number<<", currentNumber="<<currentNumber <<LOG_ENDL;
            _errorMsg = "package number last="+std::to_string(_number)+", current="+std::to_string(currentNumber);
            _errorField = "Package number";
            return -1;
        }
        
        // PrintBuffer((ptrBuffer.first.data()+framePos),30);
        std::string str;
        getSimNumber(ptrBuffer, framePos, str,_isYuebiao && _isSubHead);
        // PrintBuffer((ptrBuffer.first.data()+framePos),30);
        // LOG_DEBUG << "getSimNumber:"<< str<<LOG_ENDL;
        ptrData = ptrBuffer.first.data() + framePos;
        ptrDataLen = ptrBuffer.second - framePos;
        head = reinterpret_cast<Rtp808HeadBaseV*>(ptrData);
        if(_simNumber.size() == 0)
        {
            _simNumber = str;
        }
        else
        {
            if (_simNumber != str && _isSubHead)
            {
                LOG_ERROR<< "Error sim number  last="+_simNumber+", current="+str <<LOG_ENDL;
                _errorMsg = "sim number last="+_simNumber+", current="+str;
                _errorField = "Simcard";
                return -1;
            }
        }
        _isSubHead = false;
        _logicChannel = _logicChannel == -1 ? head -> logicChannel : _logicChannel;
        if (_logicChannel != head -> logicChannel)
        {
            LOG_ERROR<< "Error channel  last="+std::to_string(_logicChannel)+", current="+ std::to_string(head -> logicChannel) <<LOG_ENDL;
            _errorMsg = "channel last="+std::to_string(_logicChannel)+", current="+ std::to_string(head -> logicChannel);
            _errorField = "Channel";
            return -1;
        }
        if (head->dataType > 4)
        {
            LOG_ERROR<< "Error dataType :"+ std::to_string(head->dataType) <<LOG_ENDL;
            _errorMsg = "dataType =" + std::to_string(head->dataType);
            _errorField = "Datatype";
            return -1;
        }
        
        _currentType = head -> dataType;


        if(head -> partFlag <= 3 && 
        ((_currentState == 0 && (head -> partFlag == 0 || head -> partFlag == 1)) ||
        (_currentState == 1 && (head -> partFlag == 2 || head -> partFlag == 3)) ||
        (_currentState == 2 && (head -> partFlag == 0 || head -> partFlag == 1)) ||
        (_currentState == 3 && (head -> partFlag == 2 || head -> partFlag == 3)) || 
        (_currentState == -1 && (head -> partFlag == 0 || head -> partFlag == 1)))){}
        else{
            LOG_ERROR<< "Error partFlag last="+ std::to_string(_currentState)+", current="+std::to_string(head->partFlag) <<LOG_ENDL;
            _errorMsg = "partFlag last="+ std::to_string(_currentState)+", current="+std::to_string(head->partFlag) ;
            _errorField = "Package";
            return -1;
        }

        if(_url.size() == 0)
        {
            _url = "/" + _simNumber + "/" + std::to_string(_logicChannel);
        }

        uint64_t timestamp = 0;
        switch (_currentType)
        {
        case RTP_808_DATATYPE_A:
        {
            auto _ptrA = reinterpret_cast<Rtp808HeadBaseA*>(ptrData);
            _payloadDataLen = swapBigEndian(_ptrA->dataLen);
            _currentHeadLen = sizeof(Rtp808HeadBaseA);
            memcpy(&timestamp, _ptrA->time, sizeof(uint64_t));
        }
            break;
        case RTP_808_DATATYPE_T:
        {
            auto _ptrT = reinterpret_cast<Rtp808HeadBaseT*>(ptrData);
            _payloadDataLen = swapBigEndian(_ptrT -> dataLen);
            _currentHeadLen = sizeof(Rtp808HeadBaseT);
        }
            break;
        case RTP_808_DATATYPE_I:
        case RTP_808_DATATYPE_P:
        case RTP_808_DATATYPE_B:
        default:
        {
            auto _ptrV = reinterpret_cast<Rtp808HeadBaseV*>(ptrData);
            _payloadDataLen = swapBigEndian(_ptrV -> dataLen);
            _currentHeadLen = sizeof(Rtp808HeadBaseV);
            memcpy(&timestamp, _ptrV->time, sizeof(uint64_t));
            break;
        }
        }
        timestamp = swapBigEndian(timestamp);

        // FORWORT_ASSERT_RETURN(_payloadDataLen <= 950);
        if (_payloadDataLen > 950)
        {
            LOG_ERROR<< "Error dataLen :"+ std::to_string(_payloadDataLen) <<LOG_ENDL;
            _errorMsg = "dataLen :"+ std::to_string(_payloadDataLen);
            _errorField = "Length";
            return -1;
        }

        // _currentHeadLen+=magicSize;
        
        if (ptrDataLen-_currentHeadLen<_payloadDataLen)
        {
            return -2;
        }
        
        _data = ptrData;
        // _payloadData=data+_currentHeadLen;
        _rtpFrameLen = _payloadDataLen+_currentHeadLen;
        _number = currentNumber;
        // LOG_DEBUG<<"parse one frame:"<<_rtpFrameLen<<LOG_ENDL;
        
        _payloadType = PAYLOAD_TYPE_MASK & head->headPT;
        _currentState = head -> partFlag;

        // LOG_DEBUG<<(_currentType==RTP_808_DATATYPE_A?"Audio ":"Video ")<<"time="<< timestamp<<LOG_ENDL;
        // LOG_DEBUG<<"framePos="<<framePos<<",ptrDataLen="<<ptrDataLen<<LOG_ENDL;
        // LOG_DEBUG<<"_payloadType="<<_payloadType<<",_number="<<_number<<",_simNumber="<<_simNumber
        // <<",_logicChannel="<<_logicChannel<<",_currentState="<<_currentState<<",_currentType="<<_currentType<<""<<",timestamp="<<timestamp
        // <<",_rtpFrameLen="<<_rtpFrameLen<<LOG_ENDL;

        // PrintBuffer(ptrData,32);
#if DEBUG
        // LOG_DEBUG << "pack=" << getPackageDisplay(_currentState) << ",payload="<< getPayloadDisplay(_payloadType)<<",number="<<_number<<",datatype="<<getDataTypeDisplay(_currentType)<<",time="<<timestamp << LOG_ENDL;
#endif
        _isSubHead = true;
        return 0;
    }
    
    void Rtp808FrameParser::setTime(uint64_t v)
    {
        uint64_t bigEndianTime = swapBigEndian(v);
        switch (_currentType)
        {

        case RTP_808_DATATYPE_A:
        {
            auto ptrA = reinterpret_cast<Rtp808HeadBaseA*>(_data);
            memcpy(ptrA->time, &bigEndianTime, sizeof(uint64_t));
        }
            break;
        default:
        {
            auto ptrV = reinterpret_cast<Rtp808HeadBaseV*>(_data);
            memcpy(ptrV->time, &bigEndianTime, sizeof(uint64_t));
        }
            break;
        }
    }

    std::unique_ptr<uint8_t[]> Rtp808FrameParser::encodeMessage(std::string content, int& size)
    {
        Rtp808HeadBaseT rtp={0};
        memcpy(rtp.magic,magic,4);
        rtp.headCC = 1;
        rtp.headV = 2;
        rtp.headM = 1;
        rtp.partFlag = 0;
        rtp.dataType = 4;
        rtp.dataLen = content.size();

        std::unique_ptr<uint8_t[]> rtpframe(new uint8_t[sizeof(Rtp808HeadBaseT)+content.size()]());
        memcpy(rtpframe.get(), &rtp, sizeof(Rtp808HeadBaseT));
        memcpy(rtpframe.get()+sizeof(Rtp808HeadBaseT), content.data(), content.size());
        size = sizeof(Rtp808HeadBaseT)+content.size();
        return rtpframe;
    }
}