#include "dmpcommthread.h"
#include "datashm.h"

union FC {
    float f;
    unsigned char c[4];
};

DMPCommThread::DMPCommThread(qintptr socketDescriptor,QObject *parent) : QThread(parent)
{
    DeviceID = "";
    keepcomm = false;
    this->SocketDescriptor = socketDescriptor;
}

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

quint16 DMPCommThread::chk_crcc(QByteArray buff, quint16 len)
{
    quint16 default_data = 0xa001;
    quint16 crc = 0xffff;
    for(quint16 j=0;j<(len-2);j++)
    {
        crc ^= static_cast<quint8>(buff[j]&0xff);
        for(int i=0;i<8;i++)
        {
            if(crc&0x01)
            {
                crc >>= 1;
                crc ^= default_data;
            }else
                crc >>= 1;
        }
    }
    return crc;
}

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

        if(so->waitForReadyRead(1000)){
            readData(so);
        }else if(day!=QDate::currentDate().day()){
            day=QDate::currentDate().day();
            QByteArray cmd = mk_settime();
            so->write(cmd);
        }
        usleep(200000);
    }
    so->abort();
}


QByteArray DMPCommThread::mk_settime()
{
    int i, cur=0, crc=0;
    QDateTime t = QDateTime::currentDateTime();
    QByteArray DevId = DeviceID.toUtf8();
    int year = t.date().year();
    int mon = t.date().month();
    int day = t.date().day();
    int hour = t.time().hour();
    int min = t.time().minute();
    int sec = t.time().second();
    int devLen = DevId.length();
    int bodyLen = devLen+11;
    QByteArray cmd = QByteArray(14+bodyLen,0x00);
    cmd[cur++] = static_cast<char>(0x7e);
    cmd[cur++] = static_cast<char>(0x01);
    cmd[cur++] = static_cast<char>((bodyLen>>8)&0xff);
    cmd[cur++] = static_cast<char>(bodyLen&0xff);
    cmd[cur++] = static_cast<char>(0x83);
    cmd[cur++] = static_cast<char>(0x85);
    cmd[cur++] = static_cast<char>(0x83);
    cmd[cur++] = static_cast<char>(0x75);
    cmd[cur++] = static_cast<char>(0x89);
    cmd[cur++] = static_cast<char>(0x73);
    cmd[cur++] = static_cast<char>(0x79);
    cmd[cur++] = static_cast<char>(0x84);
    cmd[cur++] = static_cast<char>(0x0b);
    cmd[cur++] = static_cast<char>((devLen>>8)&0xff);
    cmd[cur++] = static_cast<char>(devLen&0xff);
    for(i=0;i<devLen;i++)
        cmd[cur++] = DevId.at(i);
    cmd[cur++] = 0x00;
    cmd[cur++] = static_cast<char>((((year/1000)&0x0f)<<4)|(((year%1000)/100)&0x0f));
    cmd[cur++] = static_cast<char>(((((year%100)/10)&0x0f)<<4)|((year%10)&0x0f));
    cmd[cur++] = static_cast<char>((((mon/10)&0x0f)<<4)|((mon%10)&0x0f));
    cmd[cur++] = static_cast<char>((((day/10)&0x0f)<<4)|((day%10)&0x0f));
    cmd[cur++] = static_cast<char>((((hour/10)&0x0f)<<4)|((hour%10)&0x0f));
    cmd[cur++] = static_cast<char>((((min/10)&0x0f)<<4)|((min%10)&0x0f));
    cmd[cur++] = static_cast<char>((((sec/10)&0x0f)<<4)|((sec%10)&0x0f));
    for(i=1;i<cur;i++)
        crc += cmd[i]&0xff;
    cmd[cur++] = static_cast<char>(crc&0xff);
    cmd[cur] = static_cast<char>(0xe7);
    return cmd;
}

QByteArray DMPCommThread::mk_rtn(quint8 type, quint16 sn){
    int i,cur=0,crc=0;
    QByteArray rtn = QByteArray(17,0x00);
    rtn[cur++] = static_cast<char>(0x7e);
    rtn[cur++] = static_cast<char>(0x01);
    rtn[cur++] = static_cast<char>(0x00);
    rtn[cur++] = static_cast<char>(0x03);
    rtn[cur++] = static_cast<char>(0x83);
    rtn[cur++] = static_cast<char>(0x85);
    rtn[cur++] = static_cast<char>(0x83);
    rtn[cur++] = static_cast<char>(0x75);
    rtn[cur++] = static_cast<char>(0x89);
    rtn[cur++] = static_cast<char>(0x73);
    rtn[cur++] = static_cast<char>(0x79);
    rtn[cur++] = static_cast<char>(0x84);
    rtn[cur++] = static_cast<char>(type);
    rtn[cur++] = static_cast<char>((sn>>8)&0xff);
    rtn[cur++] = static_cast<char>(sn&0xff);
    for(i=1;i<cur;i++)
        crc += rtn[i]&0xff;
    rtn[cur++] = static_cast<char>(crc&0xff);
    rtn[cur] = static_cast<char>(0xe7);
    return rtn;
}

QByteArray DMPCommThread::mk_rtn(quint8 type){
    int i,cur=0,crc=0;
    QByteArray rtn = QByteArray(15,0x00);
    rtn[cur++] = static_cast<char>(0x7e);
    rtn[cur++] = static_cast<char>(0x01);
    rtn[cur++] = static_cast<char>(0x00);
    rtn[cur++] = static_cast<char>(0x01);
    rtn[cur++] = static_cast<char>(0x83);
    rtn[cur++] = static_cast<char>(0x85);
    rtn[cur++] = static_cast<char>(0x83);
    rtn[cur++] = static_cast<char>(0x75);
    rtn[cur++] = static_cast<char>(0x89);
    rtn[cur++] = static_cast<char>(0x73);
    rtn[cur++] = static_cast<char>(0x79);
    rtn[cur++] = static_cast<char>(0x84);
    rtn[cur++] = static_cast<char>(type);
    for(i=1;i<cur;i++)
        crc += rtn[i]&0xff;
    rtn[cur++] = static_cast<char>(crc&0xff);
    rtn[cur] = static_cast<char>(0xe7);
    return rtn;
}

QByteArray DMPCommThread::mk_heartbeat_rtn()
{
    int i,cur=0,crc=0;
    QByteArray rtn = QByteArray(14,0x00);
    rtn[cur++] = static_cast<char>(0x7e);
    rtn[cur++] = static_cast<char>(0x01);
    rtn[cur++] = static_cast<char>(0x00);
    rtn[cur++] = static_cast<char>(0x00);
    rtn[cur++] = static_cast<char>(0x81);
    rtn[cur++] = static_cast<char>(0x85);
    rtn[cur++] = static_cast<char>(0x83);
    rtn[cur++] = static_cast<char>(0x75);
    rtn[cur++] = static_cast<char>(0x89);
    rtn[cur++] = static_cast<char>(0x73);
    rtn[cur++] = static_cast<char>(0x79);
    rtn[cur++] = static_cast<char>(0x84);
    for(i=1;i<cur;i++)
        crc += rtn[i]&0xff;
    rtn[cur++] = static_cast<char>(crc&0xff);
    rtn[cur] = static_cast<char>(0xe7);
    return rtn;
}

QByteArray DMPCommThread::mk_login_rtn()
{
    int i,cur=0,crc=0;
    QByteArray rtn = QByteArray(15,0x00);
    rtn[cur++] = static_cast<char>(0x7e);
    rtn[cur++] = static_cast<char>(0x01);
    rtn[cur++] = static_cast<char>(0x00);
    rtn[cur++] = static_cast<char>(0x01);
    rtn[cur++] = static_cast<char>(0x83);
    rtn[cur++] = static_cast<char>(0x85);
    rtn[cur++] = static_cast<char>(0x83);
    rtn[cur++] = static_cast<char>(0x75);
    rtn[cur++] = static_cast<char>(0x89);
    rtn[cur++] = static_cast<char>(0x73);
    rtn[cur++] = static_cast<char>(0x79);
    rtn[cur++] = static_cast<char>(0x84);
    rtn[cur++] = static_cast<char>(0x40);
    for(i=1;i<cur;i++)
        crc += rtn[i]&0xff;
    rtn[cur++] = static_cast<char>(crc&0xff);
    rtn[cur] = static_cast<char>(0xe7);
    return rtn;
}


int DMPCommThread::getserviceidx(QString sn)
{
    int ret = -1;

    for(int i=0;i<1024;i++){
        if((datashm->devinfo[i].Enabled&0x01)==0x01){
            if(QString::compare(sn.toLower(),QString(datashm->devinfo[i].DeviceCode).toLower())==0)
            {
                emit CommData(QString("51211 devicecode:%1").arg(sn));
                ret = i;
                emit DatabaseData(QString("update dmp_device_status set device_status=1,last_online_time='%1' where device_code = '%2'").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss")).arg(sn));
                break;
            }
        }
    }
    if(ret<0){
        emit CommData(QString("51211 %1 no found").arg(sn));
    }
    return ret;
}

void DMPCommThread::readData(QTcpSocket *so)
{
    int crc = 0;
    union FC fc;
    QByteArray data = so->readAll();
    QString temp = "";
    for(int i=0;i<data.length();i++){
        temp.append(QString("%1").arg(data.at(i)&0xff,2,16,QChar('0')));
    }
    emit CommData(QString("readALL data: [%1]").arg(temp));

    QByteArray rtn;
    if(((data[0]&0xff)==0x7e)&&((data[1]&0xff)==0x01)&&((data[data.length()-1]&0xff)==0xe7)){
        int dLen = ((data[2]&0x00ff)<<8)|(data[3]&0x00ff);
        if(data.length()==(dLen+14)){
            for(int i=1;i<(data.length()-2);i++)
                crc += data[i]&0xff;
            if((data[data.length()-2]&0xff)==(crc&0xff)){
                if((data[4]&0xff)==0x01){
                    rtn = mk_heartbeat_rtn();
                    so->write(rtn);
                }else if((data[4]&0xff)==0x03){
                    if((data[12]&0xff)==0x40){
                        int IEMILen = ((data[13]&0x00ff)<<8)|(data[14]&0x00ff);
                        int IMSILen = ((data[IEMILen+16]&0x00ff)<<8)|(data[IEMILen+17]&0x00ff);
                        int DevLen = ((data[IEMILen+IMSILen+19]&0x00ff)<<8)|(data[IEMILen+IMSILen+20]&0x00ff);
                        DeviceID = QString(data.mid(IEMILen+IMSILen+21,DevLen));
                        printf("DeviceID: %s\n",DeviceID.toUtf8().data());
                        rtn = mk_login_rtn();
                        so->write(rtn);
                    }else if((data[12]&0xff)==0x44){
                        int IdLen = ((data[13]&0x00ff)<<8)|(data[14]&0x00ff);
                        QString deviceID = QString(data.mid(15,IdLen));
                        int idx = getserviceidx(deviceID);
                        if(idx>=0){
                            QString bstr="";
                            QString pointstr="";
                            bstr.append(QString("sp_d%1").arg(DeviceID)).append(",").append(QString("dev_type=%1").arg(datashm->devinfo[idx].DeviceType)).append(" ");
                            QString tmp="";
                            for(int i=0;i<data.length();i++){
                                tmp.append(QString("%1").arg(data.at(i)&0xff,2,16,QChar('0')));
                            }
                            bstr.append(QString("byte_array=\"%1\"").arg(tmp));

                            for(int j=0;j<32;j++){
                                for(int i=0;i<4;i++)
                                    fc.c[3-i] = data[IdLen+16+4*j+i]&0xff;
                                float RealVal = fc.f;
                                pointstr.append(QString("\"point%1\":%2").arg(j).arg(RealVal)).append(",");
                            }
                            pointstr=pointstr.left(pointstr.size()-1);
                            QString jsonStr = QString("{\"device_id\":\"%1\",\"product_id\":\"%2\",\"timestamp\":\"%3\",\"tags\":{\"conn_type\":\"%4\",\"type\":\"%5\"},\"metrics\":{%6},\"device_type\":\"%7\"}").arg(DeviceID).arg("").arg(QDateTime::currentDateTime().toTime_t()).arg("").arg("").arg(pointstr).arg(QString("%1").arg(datashm->devinfo[idx].DeviceType));

                            int year = ((data[IdLen+23]>>4)&0x0f)*1000+(data[IdLen+23]&0x0f)*100+((data[IdLen+24]>>4)&0x0f)*10+(data[IdLen+24]&0x0f);
                            int mon = ((data[IdLen+25]>>4)&0x0f)*10+(data[IdLen+25]&0x0f);
                            int day = ((data[IdLen+26]>>4)&0x0f)*10+(data[IdLen+26]&0x0f);
                            int hour = ((data[IdLen+27]>>4)&0x0f)*10+(data[IdLen+27]&0x0f);
                            int min = ((data[IdLen+28]>>4)&0x0f)*10+(data[IdLen+28]&0x0f);
                            int sec = ((data[IdLen+29]>>4)&0x0f)*10+(data[IdLen+29]&0x0f);
                            QDateTime ut = QDateTime(QDate(year,mon,day),QTime(hour,min,sec));
                            emit getERealtimeValue(DeviceID,bstr,jsonStr,ut);
                        }
                        rtn = mk_rtn(data[12]&0xff);
                        so->write(rtn);
                    }
                }
            }
        }
    }
}

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


void DMPCommThread::stop()
{
    keepcomm = false;
}



