#include "userverthread.h"
#include <time.h>
#include <sys/time.h>
#include "yt_unit_shm.h"

extern YT_UNIT_SHM *ytShm;

UServerThread::UServerThread(QObject *parent, QString ip, quint16 port) :
    QThread(parent)
{
    ServerIP = ip;
    ServerPort = port;
    CmdList.clear();
}

void UServerThread::mkCommCmd(unsigned char *cmd, unsigned char *data, unsigned char cmdCode, int dataLen)
{
    int cur=0,crc=0;
    int i;
    cmd[cur++] = 0x7e;
    cmd[cur++] = 0x01;
    cmd[cur++] = ((dataLen>>8)&0xff);
    cmd[cur++] = dataLen&0xff;
    cmd[cur++] = cmdCode;
    cmd[cur++] = 0x85;
    cmd[cur++] = 0x83;
    cmd[cur++] = 0x75;
    cmd[cur++] = 0x89;
    cmd[cur++] = 0x73;
    cmd[cur++] = 0x79;
    cmd[cur++] = 0x84;
    for(i=0;i<dataLen;i++)
        cmd[cur++] = data[i];
    cmd[cur] = 0x00;
    cmd[cur+1] = 0xe7;
    for(i=1;i<cur;i++)
        crc += cmd[i];
    cmd[cur] = crc&0xff;
}

int UServerThread::mkHeartBeatCmd(unsigned char *cmd)
{
    int datalen = 0;
    unsigned char data[256];
    unsigned char CMD = 0x01;
    mkCommCmd(cmd,data,CMD,datalen);
    return datalen+14;
}

int UServerThread::mkDeviceRegistCmd(unsigned char *cmd)
{
    int i=0, cur=0;
    unsigned char data[256];
    unsigned char CMD = 0x03;
    int datalen = 0;
    int IEMILen = strlen(ytShm->sysShm.USKYID);
    int IMSILen = strlen(ytShm->sysShm.USKYID);
    int DevLen = strlen(ytShm->sysShm.USKYID);
    datalen = IEMILen+IMSILen+DevLen+11;
    data[cur++] = 0x40;
    data[cur++] = (IEMILen>>8)&0xff;
    data[cur++] = (IEMILen&0xff);
    for(i=0;i<IEMILen;i++)
        data[cur++] = ytShm->sysShm.USKYID[i]&0xff;
    data[cur++] = 0x00;
    data[cur++] = (IMSILen>>8)&0xff;
    data[cur++] = (IMSILen&0xff);
    for(i=0;i<IMSILen;i++)
        data[cur++] = ytShm->sysShm.USKYID[i]&0xff;
    data[cur++] = 0x00;
    data[cur++] = (DevLen>>8)&0xff;
    data[cur++] = (DevLen&0xff);
    for(i=0;i<DevLen;i++)
        data[cur++] = ytShm->sysShm.USKYID[i]&0xff;
    data[cur++] = 0x00;
    data[cur++] = 0x00;
    mkCommCmd(cmd,data,CMD,datalen);
    return datalen+14;
}

bool UServerThread::chk_frame(QByteArray rtn)
{
    int i,crc = 0;
    unsigned short dataLen;
    if((rtn.length()>=14)&&((rtn[0]&0xff)==0x7e)&&((rtn[1]&0xff)==0x10)
            &&((rtn[rtn.length()-1]&0xff)==0xe7)){
        for(i=1;i<(rtn.length()-2);i++)
            crc += (rtn[i]&0xff);
        if((rtn[rtn.length()-2]&0xff)==(crc&0xff)){
            dataLen = ((rtn[2]&0x00ff)<<8)|(rtn[3]&0x00ff);
            if(rtn.length()==(dataLen+14))
                return true;
        }
    }
    return false;
}

bool UServerThread::set_systime(int year, int mon, int day, int hour, int min, int sec)
{
    int i;
    time_t t;
    struct tm _tm;
    struct timeval tv;
    _tm.tm_year = year-1900;
    _tm.tm_mon = mon-1;
    _tm.tm_mday = day;
    _tm.tm_hour = hour;
    _tm.tm_min = min;
    _tm.tm_sec = sec;
    t = mktime(&_tm);
    tv.tv_sec = t;
    tv.tv_usec = 0;
    if(settimeofday(&tv,(struct timezone *)0)<0){
        return false;
    }
    system("hwclock -w");
    QDateTime  curDatetime = QDateTime::currentDateTime();
    uint chkTime = curDatetime.toTime_t();
    ytShm->currentTime.YEAR = curDatetime.date().year()&0xffff;
    ytShm->currentTime.MONTH = curDatetime.date().month()&0xff;
    ytShm->currentTime.DAY = curDatetime.date().day()&0xff;
    ytShm->currentTime.HOUR = curDatetime.time().hour()&0xff;
    ytShm->currentTime.MINUTE = curDatetime.time().minute()&0xff;
    ytShm->currentTime.SECOND = curDatetime.time().second()&0xff;
    ytShm->currentTime.TIMESTAMP = chkTime;
    for(i=0;i<60;i++){
        if(ytShm->dogTimeList.dogTime[i].ENABLED==0x01)
            ytShm->dogTimeList.dogTime[i].LASTFEED = ytShm->currentTime.TIMESTAMP;
    }
    return true;
}

int UServerThread::mkTimeSetRtn(QByteArray rtn, unsigned char *cmd)
{
    int i=0, cur=0;
    unsigned char data[256];
    unsigned char CMD = 0x83;
    int datalen = 0;
    bool idchk = true;
    unsigned short devidLen = ((rtn[13]&0x00ff)<<8)|(rtn[14]&0x00ff);
    if((rtn.length()==(devidLen+25))&&(devidLen>0)&&(devidLen<=32)){
        for(i=0;i<devidLen;i++){
            if(ytShm->sysShm.USKYID[i]!=(rtn[15+i]&0xff)){
                idchk = false;
                break;
            }
        }
        if(idchk){
            int year = ((rtn[16+devidLen]>>4)&0x0f)*1000
                    +(rtn[16+devidLen]&0x0f)*100
                    +((rtn[17+devidLen]>>4)&0x0f)*10
                    +(rtn[17+devidLen]&0x0f);
            int mon = ((rtn[18+devidLen]>>4)&0x0f)*10
                    +(rtn[18+devidLen]&0x0f);
            int day = ((rtn[19+devidLen]>>4)&0x0f)*10
                    +(rtn[19+devidLen]&0x0f);
            int hour = ((rtn[20+devidLen]>>4)&0x0f)*10
                    +(rtn[20+devidLen]&0x0f);
            int min = ((rtn[21+devidLen]>>4)&0x0f)*10
                    +(rtn[21+devidLen]&0x0f);
            int sec = ((rtn[22+devidLen]>>4)&0x0f)*10
                    +(rtn[22+devidLen]&0x0f);
            if(set_systime(year,mon,day,hour,min,sec)){
                datalen = devidLen+4;
                data[cur++] = 0x0b;
                data[cur++] = rtn[13]&0xff;
                data[cur++] = rtn[14]&0xff;
                for(i=0;i<devidLen;i++)
                    data[cur++] = rtn[15+i]&0xff;
                data[cur] = 0x00;
                mkCommCmd(cmd,data,CMD,datalen);
                return datalen+14;
            }
        }
    }
    return 0;
}

int UServerThread::chk_protocol(QByteArray rtn, unsigned char *outData)
{
    if(chk_frame(rtn)){
        if((rtn[4]&0xff)==0x81)
            return 0;
        else if((rtn.length()>=14)&&((rtn[4]&0xff)==0x83)){
            switch(rtn[12]&0xff){
            case 0x0b:
                return mkTimeSetRtn(rtn,outData);
            }
        }
    }
    return 0;
}


void UServerThread::appendAllRealdata()
{
    FC fc;
    int i=0, cur=0;
    unsigned char data[256],cmd[1024];
    unsigned char CMD = 0x03;
    int year,mon,day,hour,min,sec;
    int datalen = 0;
    int devidLen = 0;
    QDateTime dt;
    QByteArray PnoId = QString("%1").arg(ytShm->sysShm.USKYID).toUtf8();
    devidLen = PnoId.length();
    if(devidLen==0)
        return;
    datalen = devidLen+139;
    data[cur++] = 0x44;
    data[cur++] = (devidLen>>8)&0xff;
    data[cur++] = devidLen&0xff;
    for(i=0;i<devidLen;i++)
        data[cur++] = PnoId.at(i)&0xff;
    data[cur++] = 0x00;
    for(int pid=0;pid<32;pid++){
        fc.f = ytShm->spStatusList.spStatus[0][pid].REALTIME_VALUE;
        data[cur++] = fc.c[3];
        data[cur++] = fc.c[2];
        data[cur++] = fc.c[1];
        data[cur++] = fc.c[0];
    }

    dt = QDateTime::currentDateTime();
    year = dt.date().year();
    mon = dt.date().month();
    day = dt.date().day();
    hour = dt.time().hour();
    min = dt.time().minute();
    sec = dt.time().second();
    data[cur++] = (((year/1000)&0x0f)<<4)|(((year%1000)/100)&0x0f);
    data[cur++] = ((((year%100)/10)&0x0f)<<4)|((year%10)&0x0f);
    data[cur++] = (((mon/10)&0x0f)<<4)|((mon%10)&0x0f);
    data[cur++] = (((day/10)&0x0f)<<4)|((day%10)&0x0f);
    data[cur++] = (((hour/10)&0x0f)<<4)|((hour%10)&0x0f);
    data[cur++] = (((min/10)&0x0f)<<4)|((min%10)&0x0f);
    data[cur++] = (((sec/10)&0x0f)<<4)|((sec%10)&0x0f);
    mkCommCmd(cmd,data,CMD,datalen);
    QByteArray rep = QByteArray((const char *)cmd,datalen+14);
    CmdList.append(rep);
}


void UServerThread::run(){
    bool soSta=false;
    unsigned char cmd[1024];
    int len;
    CommTime = 0;
    so = new QTcpSocket;
    while(1){
        if(!soSta){
            printf("connected to %s:%d\n",ServerIP.toUtf8().data(),ServerPort);
            so->connectToHost(QHostAddress(ServerIP),ServerPort);
            if(so->waitForConnected(3000)){
                printf("so open pass\n");
                soSta = true;
                len = mkDeviceRegistCmd(cmd);
                if(len>0){
                    QByteArray Cmd = QByteArray((const char *)cmd,len);
                    so->write(Cmd);
                    if(!so->waitForBytesWritten(3000)){
                        so->abort();
                        soSta = false;
                    }else
                        CommTime = ytShm->currentTime.TIMESTAMP;
                }
            }else{
                printf("so open failed\n");
                so->abort();
            }
        }else{
            if(so->waitForReadyRead(3000)){
                QByteArray Rtn = so->readAll();
                len = chk_protocol(Rtn,cmd);
                if(len>0){
                    QByteArray Cmd = QByteArray((const char *)cmd,len);
                    so->write(Cmd);
                    if(!so->waitForBytesWritten(3000)){
                        so->abort();
                        soSta = false;
                    }
                }
            }else if(CmdList.length()>0){
                while(CmdList.length()>1000)
                    CmdList.removeFirst();
                if(CmdList.length()>0){
                    QByteArray Cmd = CmdList.first();
                    so->write(Cmd);
                    if(!so->waitForBytesWritten(3000)){
                        so->abort();
                        soSta = false;
                    }else{
                        CmdList.removeFirst();
                        CommTime = ytShm->currentTime.TIMESTAMP;
                    }
                }
            }else if((ytShm->currentTime.TIMESTAMP-CommTime)>30){
                len = mkHeartBeatCmd(cmd);
                if(len>0){
                    QByteArray Cmd = QByteArray((const char *)cmd,len);
                    so->write(Cmd);
                    if(!so->waitForBytesWritten(3000))
                    {
                        so->abort();
                        soSta = false;
                    }else
                        CommTime = ytShm->currentTime.TIMESTAMP;
                }
            }
        }
        usleep(100000);
    }

}
