#include "clientthread.h"

ClientThread::ClientThread(qintptr socketDescriptor, QObject *parent) : QThread(parent)
{
    this->SocketDescriptor = socketDescriptor;
}

ClientThread::~ClientThread()
{
    deleteLater();
}

void ClientThread::close_self(QTcpSocket *so)
{
    so->abort();
    keepcomm = false;
}

void ClientThread::setAppPDataList(QList<AppPData> list){
    AppPDataList.clear();
    AppPDataList.append(list);
}

bool ClientThread::chkversion(QByteArray body, QTcpSocket *so){
    if(body.length()>4){
        quint16 hashLen = static_cast<quint16>(((body.at(1)&0x00ff)<<8)|(body.at(2)&0x00ff));
        if((body.length()==(hashLen+4))&&(hashLen>0)){
            QString AppHash = QString(body.mid(3,hashLen));
            printf("AppPDataList.length() [%d]\n",AppPDataList.length());
            if(AppPDataList.length()>0){
                printf("test2444444\n");
                for(int i=0;i<AppPDataList.length();i++){
                    AppPData pData = AppPDataList.at(i);
                    printf("AppHash [%s] ,static_cast<const QString>(pData.AppId()) [%s] \n",AppHash.toUtf8().data(),static_cast<const QString>(pData.AppId()).toUtf8().data());
                    if(QString::compare(AppHash,static_cast<const QString>(pData.AppId()))==0){
                        QDateTime currenttime = QDateTime::currentDateTime();
                        quint8 MajroVersion = static_cast<quint8>(pData.majroVersion()&0xff);
                        quint8 MinroVersion = static_cast<quint8>(pData.minroVersion()&0xff);
                        uint ProgramLength = static_cast<uint>(pData.programLength());
                        QByteArray Checksum = pData.chksum().toUtf8();
                        uint uptime = pData.upTime();
                        quint16 rtnLen = (17+hashLen+Checksum.length())&0xffff;
                        QByteArray ret = QByteArray(rtnLen+14,0x00);
                        int cur = 0, crc = 0;
                        ret[cur++] = static_cast<char>(0x7e);
                        ret[cur++] = static_cast<char>(0x01);
                        ret[cur++] = static_cast<char>((rtnLen>>8)&0xff);
                        ret[cur++] = static_cast<char>(rtnLen&0xff);
                        ret[cur++] = static_cast<char>(0x85&0xff);
                        ret[cur++] = static_cast<char>(0x85);
                        ret[cur++] = static_cast<char>(0x83);
                        ret[cur++] = static_cast<char>(0x75);
                        ret[cur++] = static_cast<char>(0x89);
                        ret[cur++] = static_cast<char>(0x73);
                        ret[cur++] = static_cast<char>(0x79);
                        ret[cur++] = static_cast<char>(0x84);
                        ret[cur++] = static_cast<char>(0x01);
                        ret[cur++] = body.at(1);
                        ret[cur++] = body.at(2);
                        for(int i=0;i<hashLen;i++)
                            ret[cur++] = body.at(3+i);
                        ret[cur++] = static_cast<char>(0x00);
                        ret[cur++] = static_cast<char>(MajroVersion);
                        ret[cur++] = static_cast<char>(MinroVersion);
                        ret[cur++] = static_cast<char>((ProgramLength>>24)&0xff);
                        ret[cur++] = static_cast<char>((ProgramLength>>16)&0xff);
                        ret[cur++] = static_cast<char>((ProgramLength>>8)&0xff);
                        ret[cur++] = static_cast<char>(ProgramLength&0xff);
                        ret[cur++] = static_cast<char>((Checksum.length()>>8)&0xff);
                        ret[cur++] = static_cast<char>(Checksum.length()&0xff);
                        for(int i=0;i<Checksum.length();i++)
                            ret[cur++] = Checksum.at(i);
                        ret[cur++] = static_cast<char>(0x00);
                        ret[cur++] = static_cast<char>((uptime>>24)&0xff);
                        ret[cur++] = static_cast<char>((uptime>>16)&0xff);
                        ret[cur++] = static_cast<char>((uptime>>8)&0xff);
                        ret[cur++] = static_cast<char>(uptime&0xff);
                        ret[cur] = static_cast<char>(0x00);
                        ret[cur+1] = static_cast<char>(0xe7&0xff);
                        for(int i=1;i<cur;i++)
                            crc += static_cast<int>(ret[i]&0xff);
                        ret[cur] = static_cast<char>(crc&0xff);
                        so->write(ret);
                        emit commlog(ret,false);
                        return true;
                    }
                }
            }
        }
    }
    return false;
}

bool ClientThread::getversion(QByteArray body, QTcpSocket *so){
    if(body.length()>8){
        quint16 hashLen = static_cast<quint16>(((body.at(1)&0x00ff)<<8)|(body.at(2)&0x00ff));
        if((body.length()==(hashLen+8))&&(hashLen>0)){
            QString AppHash = QString(body.mid(3,hashLen));
            quint8 MajroVersion = body.at(hashLen+4)&0xff;
            quint8 MinroVersion = body.at(hashLen+5)&0xff;
            quint16 PakIdx = static_cast<quint16>(((body.at(hashLen+6)&0x00ff)<<8)|(body.at(hashLen+7)&0x00ff));
            for(int i=0;i<AppPDataList.length();i++){
                AppPData pData = AppPDataList.at(i);
                if((QString::compare(AppHash,static_cast<const QString>(pData.AppId()))==0)
                        &&(MajroVersion==pData.majroVersion())&&(MinroVersion==pData.minroVersion())){
                    if(PakIdx<pData.Size()){
                        PData data = pData.DataAt(PakIdx);
                        QByteArray pdata =data.data();
                        quint16 dLen = pdata.length()&0xffff;
                        quint16 subSum =data.check();
                        QDateTime currenttime = QDateTime::currentDateTime();
                        quint16 rtnLen = 13+hashLen+dLen;
                        QByteArray ret = QByteArray(13+rtnLen,0x00);
                        int cur = 0, crc = 0;
                        ret[cur++] = static_cast<char>(0x7e);
                        ret[cur++] = static_cast<char>(0x01);
                        ret[cur++] = static_cast<char>((rtnLen>>8)&0xff);
                        ret[cur++] = static_cast<char>(rtnLen&0xff);
                        ret[cur++] = static_cast<char>(0x85&0xff);
                        ret[cur++] = static_cast<char>(0x85);
                        ret[cur++] = static_cast<char>(0x83);
                        ret[cur++] = static_cast<char>(0x75);
                        ret[cur++] = static_cast<char>(0x89);
                        ret[cur++] = static_cast<char>(0x73);
                        ret[cur++] = static_cast<char>(0x79);
                        ret[cur++] = static_cast<char>(0x84);
                        ret[cur++] = static_cast<char>(0x02);
                        ret[cur++] = body.at(1);
                        ret[cur++] = body.at(2);
                        for(int i=0;i<hashLen;i++)
                            ret[cur++] = body.at(3+i);
                        ret[cur++] = static_cast<char>(0x00);
                        ret[cur++] = body.at(hashLen+4);
                        ret[cur++] = body.at(hashLen+5);
                        ret[cur++] = body.at(hashLen+6);
                        ret[cur++] = body.at(hashLen+7);
                        ret[cur++] = static_cast<char>((dLen>>8)&0xff);
                        ret[cur++] = static_cast<char>(dLen&0xff);
                        for(int i=0;i<dLen;i++)
                            ret[cur++] = pdata.at(i);
                        ret[cur++] = 0x00;
                        ret[cur++] = static_cast<char>((subSum>>8)&0xff);
                        ret[cur++] = static_cast<char>(subSum&0xff);
                        ret[cur] = 0x00;
                        ret[cur+1] = static_cast<char>(0xe7&0xff);
                        for(int i=1;i<cur;i++)
                            crc += static_cast<int>(ret[i]&0xff);
                        ret[cur] = static_cast<char>(crc&0xff);
                        so->write(ret);
                        emit commlog(ret,false);
                        return true;
                    }
                }
            }
        }
    }
    return false;
}

bool ClientThread::readData(QTcpSocket *so)
{
    QByteArray cmd = so->readAll();
    emit commlog(cmd,true);
    if(((cmd.at(0)&0xff)==0x7e)&&((cmd.at(1)&0x0f)==0x01)&&((cmd.at(4)&0x0f)==0x05)&&((cmd.at(cmd.length()-1)&0xff)==0xe7)&&(cmd.length()>13)){
        quint16 datalen = static_cast<quint16>(((cmd.at(2)&0x00ff)<<8)|(cmd.at(3)&0x00ff));
        quint8 crc = 0x00;
        if(cmd.length()==(datalen+14)){
            for(int i=1;i<(cmd.length()-2);i++)
                crc += static_cast<quint8>(cmd.at(i)&0xff);

            if(static_cast<quint8>(cmd.at(cmd.length()-2)&0xff)==static_cast<quint8>(crc)){
                if(datalen>0){
                    switch (cmd.at(12)&0xff) {
                    case 0x01:
                        return chkversion(cmd.mid(12,datalen),so);
                    case 0x02:
                        return getversion(cmd.mid(12,datalen),so);
                    }
                }else
                    emit datalog(QString("datalen err %1").arg(datalen,4,16,QChar('0')));
            }else
                emit datalog(QString("crc err %1:%2").arg(crc,2,16,QChar('0')).arg(cmd.at(cmd.length()-2)&0xff,2,16,QChar('0')));
        }else
            emit datalog(QString("len err %1:%2").arg(datalen+14).arg(cmd.length()));
    }else{
        emit datalog(QString("frame err"));
    }
    return false;
}

void ClientThread::run()
{
    QTcpSocket *so = new QTcpSocket;
    if(!so->setSocketDescriptor(this->SocketDescriptor))
    {
        so->abort();
        return;
    }
    keepcomm = true;
    while (keepcomm) {
        if(so->state()!=QTcpSocket::ConnectedState){
            close_self(so);
            return;
        }
        if(so->waitForReadyRead()){
            if(!readData(so)){
                close_self(so);
                return;
            }
        }
    }
    so->abort();
}
