#include "tcpsockethelper.h"

#include <QCryptographicHash>
#include <QDateTime>
#include <QJsonDocument>
#include <QJsonObject>

TCPSocketHelper::TCPSocketHelper(QObject *parent) : QObject(parent)
{
    m_TCPSocket = new QTcpSocket(this);
    m_HeartBeatTimer = new QTimer(this);
    m_HeartBeatTimer->setInterval(2*1000);                    //10秒进行一次心跳检测
    m_tcpServerTimer = new QTimer(this);
    //断开连接后，定时重连服务器（使用lambda表达式）
    connect(m_tcpServerTimer,&QTimer::timeout,[=](){
        if(m_tcpServerStatus == false){
            m_CloseFlag = false;
            setHostAndePort(m_ServerHost,m_ServerPort);
            qDebug()<<"/*----------m_tcpServerTimer---------"<<m_ServerHost<<m_ServerPort;
        }
    });
    connect(m_TCPSocket,&QTcpSocket::connected,this,&TCPSocketHelper::onConnected);
    connect(m_TCPSocket,&QTcpSocket::readyRead,this,&TCPSocketHelper::onReadyRead);
    connect(m_TCPSocket,&QTcpSocket::disconnected,this,&TCPSocketHelper::onDisconnected);
    connect(m_HeartBeatTimer, &QTimer::timeout, this, &TCPSocketHelper::checkHeartBeat);
}

TCPSocketHelper::~TCPSocketHelper()
{

}
void TCPSocketHelper::setHostAndePort(const QString &_Host,const int &_Port)
{
    if(!getCloseFlag()){
        qDebug()<<QDateTime::currentDateTime()<<"Socket set Host and Port"<<_Host<<_Port<<endl;
        m_ServerHost = _Host;
        m_ServerPort = quint16(_Port);
        qDebug()<<"/*-------setHostAndePort------"<<m_ServerHost<<m_ServerPort;

        m_TCPSocket->abort();       //重置套接字
        m_TCPSocket->connectToHost(m_ServerHost,m_ServerPort,QTcpSocket::ReadWrite);
    }else{
        qDebug()<<QDateTime::currentDateTime()<<Q_FUNC_INFO<<"Error CloseFlag is On!!!";
    }
}

void TCPSocketHelper::closeTCPSocker()
{
    qDebug()<<QDateTime::currentDateTime()<<Q_FUNC_INFO<<endl;
    setCloseFlag(true);
    m_TCPSocket->close();       //关闭套接字
    m_ArrBuff.clear();//断开后清除缓存
    emit TCPSocketIsDisconnected();
    if(m_LossCount != 0) m_LossCount = 0;
}

void TCPSocketHelper::openTCPSocket()
{
    qDebug()<<QDateTime::currentDateTime()<<Q_FUNC_INFO<<endl;
    setCloseFlag(false);
    if(m_LossCount != 0) m_LossCount = 0;
    setHostAndePort(m_ServerHost,m_ServerPort);
}

void TCPSocketHelper::Register()
{
    PacketRegister from;
    from.stationCode = "JM0001";
    if(writeData(Send_Register(from))){
        //qDebug()<<"数据发送成功,Data:"<<Send_HeartBeat_rv(from);
        return;
    }else {
        qDebug()<<"发送注册失败";
    }
}

void TCPSocketHelper::Binding(QString epc, QString carPlnum)
{
    PacketBinding from;
    from.plateNum = carPlnum.toStdString();
    from.vehicleId = epc.toStdString();
    if(writeData(Send_Binding(from))){
        //qDebug()<<"数据发送成功,Data:"<<Send_HeartBeat_rv(from);
        return;
    }else {
        qDebug()<<"发送绑定失败";
    }
}

void TCPSocketHelper::onConnected()
{
    qDebug()<<Q_FUNC_INFO<<QDateTime::currentDateTime()<<"TcpSocket Connected!!!"<<endl;
    m_tcpServerStatus = true;
    m_HeartBeatTimer->start(); //连接后,启动心跳检查,以跟踪连接状态
}

void TCPSocketHelper::onReadyRead()
{
    if(!getCloseFlag()){            //如果 Socket 不是主动断开
        m_ArrBuff = m_TCPSocket->readAll();                         //向缓冲区尾部追加数据                                             //开始从缓冲区读取有效帧
        qDebug()<<m_ArrBuff;
        if(!m_ArrBuff.isEmpty()){                                  //如果取出了有效帧
            classifyByOPCode(m_ArrBuff);
        }
    }else{
        qDebug()<<QDateTime::currentDateTime()<<Q_FUNC_INFO<<"Error CloseFlag is On!!!";
    }
}
void TCPSocketHelper::classifyByOPCode(const QByteArray& Arrtmp){
    if(getOpCode(Arrtmp) == 0x55){                        //如果这是一个心跳返回,则过滤
        qDebug()<<"心跳";
        setHeartBeatFlag(true);                         //置心跳标记为真
    }
    else{                                              //如果返回的数据为正常数据
        //analyzeData(getPayloadData(Arrtmp));            //发送数据
        if(getOpCode(Arrtmp) == 0x56){
            qDebug()<<"绑定成功";
        }
    }
}

QByteArray TCPSocketHelper::Send_HeartBeat_rv(PacketHeartBeat &heartBeat)
{
    QByteArray send_data;
    int index =0;
    send_data[index++] =0xAA;
    send_data[index++] =0xAA;
    send_data[index++] =0x05;
    CJsonObject cjson;
    cjson.Add("pang",heartBeat.pang);
    int data_len =cjson.ToString().size();
    send_data[index++] = (unsigned char)(data_len % (0x100));
    send_data[index++] = (unsigned char)(data_len % (0x10000) / 0x100);
    send_data[index++] = (unsigned char)(data_len % (0x1000000) / 0x10000);
    send_data[index++] = (unsigned char)(data_len % (0x100000000) / 0x1000000);
    send_data.append(cjson.ToString().c_str(),data_len);
    index+=data_len;
    string ss =  MD5(cjson,heartBeat.key);
    send_data.append(ss.c_str(),32);
    index+=32;
    send_data[index++] =0xEE;
    send_data[index++] =0xEE;
    return send_data;
}

QByteArray TCPSocketHelper::Send_Register(PacketRegister &m_register)
{
    QByteArray send_data;
    int index =0;
    send_data[index++] =0xAA;
    send_data[index++] =0xAA;
    send_data[index++] =0x00;
    CJsonObject cjson;
    cjson.Add("stationCode",m_register.stationCode);
    int data_len =cjson.ToString().size();
    send_data[index++] = (unsigned char)(data_len % (0x100));
    send_data[index++] = (unsigned char)(data_len % (0x10000) / 0x100);
    send_data[index++] = (unsigned char)(data_len % (0x1000000) / 0x10000);
    send_data[index++] = (unsigned char)(data_len % (0x100000000) / 0x1000000);
    send_data.append(cjson.ToString().c_str(),data_len);
    index+=data_len;
    string ss =  MD5(cjson,m_register.key);
    send_data.append(ss.c_str(),32);
    index+=32;
    send_data[index++] =0xEE;
    send_data[index++] =0xEE;
    return send_data;
}

QByteArray TCPSocketHelper::Send_Binding(PacketBinding &form)
{
    QByteArray send_data;
    int index =0;
    send_data[index++] =0xAA;
    send_data[index++] =0xAA;
    send_data[index++] =0x06;
    CJsonObject cjson;
    cjson.Add("plateNum",form.plateNum);
    cjson.Add("vehicleId",form.vehicleId);
    int data_len =cjson.ToString().size();
    send_data[index++] = (unsigned char)(data_len % (0x100));
    send_data[index++] = (unsigned char)(data_len % (0x10000) / 0x100);
    send_data[index++] = (unsigned char)(data_len % (0x1000000) / 0x10000);
    send_data[index++] = (unsigned char)(data_len % (0x100000000) / 0x1000000);
    send_data.append(cjson.ToString().c_str(),data_len);
    index+=data_len;
    string ss =  MD5(cjson,form.key);
    send_data.append(ss.c_str(),32);
    index+=32;
    send_data[index++] =0xEE;
    send_data[index++] =0xEE;
    return send_data;
}
string TCPSocketHelper::MD5(CJsonObject cj, string key)
{
    QString md5;
    string strRet;
    strRet = cj.ToString();
    string md;
    md =strRet + key;
    QByteArray tmpByteArray(md.c_str(), md.length());
    QByteArray str;
    str = QCryptographicHash::hash(tmpByteArray,QCryptographicHash::Md5 );
    md5.append(str.toHex());
    return md5.toStdString();
}

void TCPSocketHelper::onDisconnected()
{
    qDebug()<<QDateTime::currentDateTime()<<Q_FUNC_INFO<<"TcpSocket Disconnected  "<<"Error:"<<m_TCPSocket->error()<<"---"<<m_TCPSocket->errorString()<<endl;
    closeTCPSocker();//断开后关闭套接字
    m_tcpServerStatus = false;
    //2秒重连，重启重连服务器的定时器
    m_tcpServerTimer->start(2000);
}

void TCPSocketHelper::checkHeartBeat()
{
    if(!getCloseFlag()){            //如果 Socket 不是主动断开
        if(getHeartBeatFlag()){     //获取心跳标志.如果为真,发送 ping,并置心跳标志为假

            if(m_LossCount != 0){
                emit TCPSocketUnstable();
                qDebug()<<QDateTime::currentDateTime()<<"TCPSocketUnstable!!!!!!!!!!!!!!!";
                m_LossCount = 0;
            }
            sendPing();
            setHeartBeatFlag(false);
        }else{                      //如果心跳标志为假,说明没有收到对应的 pong,启动异常检测
            ++m_LossCount;
            if(m_LossCount > 6){
                qDebug()<<QDateTime::currentDateTime()<<"m_LossCount:"<<m_LossCount;
            }
        }
    }else{                          //如果是主动断开,则关闭心跳计时器,并置心跳标志为真.
        if(m_HeartBeatTimer->isActive())
            m_HeartBeatTimer->stop(); //启动心跳检查,以保持连接
        setHeartBeatFlag(true);
    }
}

char TCPSocketHelper::getOpCode(const QByteArray& Arr){
    QByteArray data_buf = Arr.mid(7,Arr.size()-41);
    QJsonObject json;
    json = QJsonDocument::fromJson(data_buf).object();
    //解析JSON
    QJsonParseError jsonError;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(data_buf, &jsonError);
    if (jsonError.error != QJsonParseError::NoError)
    {
        qDebug() << "Json文件解析错误。";
    }

    QByteArray msg = Arr;
    unsigned short size = msg.size();
    unsigned char *p =(unsigned char *)msg.data();
    char *p1 =( char *)msg.data();
    string tmp(&p1[7]);
    return char(p[2]);
}
bool TCPSocketHelper::writeData(const QByteArray& Data){
    if(getCloseFlag()){
        return false;
    }
    //分包发送
    const int PayloadSize = 64*1024;//一个帧数据包大小
    int totalSize = Data.size();
    int bytesWritten = 0;
    int bytesToWrite = totalSize;
    while(bytesWritten<totalSize)
    {
        int startIdx = bytesWritten;
        int length = std::min(PayloadSize,bytesToWrite);
        if(startIdx+length>totalSize)
            return false;

        QByteArray smallBlock = Data.mid(startIdx,length);
        qint64 written = m_TCPSocket->write(smallBlock);
        bool success = m_TCPSocket->waitForBytesWritten();

        if(!success)//发送失败包时，停止发送
            return false;

        bytesWritten+=written;
        bytesToWrite-=written;
    }
    m_TCPSocket->flush();
    return true;
}

void TCPSocketHelper::sendPing()
{
    PacketHeartBeat from;
    from.ping = "1";
    if(writeData(Send_HeartBeat_rv(from))){
        //qDebug()<<"数据发送成功,Data:"<<Send_HeartBeat_rv(from);
        return;
    }else {
        qDebug()<<"发送心跳数据失败";
    }
}
