#include "TCPProtocol.h"
#include <QByteArray>
#include <QDataStream>
#include <QDebug>

CTCPProtocol::CTCPProtocol()
{
    ResetRxStateMachine();
}

unsigned int CTCPProtocol::AnalyzeNewData(QByteArray data)
{
    QDataStream stream(data);
    stream.device()->seek(0);

    switch(mProtocolRxState)
    {
        case TCP_PROTOCOL_GET_HEADER_STATE:
        {
            quint32 header;
            qint32 msg;

            stream >> header;

            if(header != TCP_PROTOCOL_HEADER)
            {
                return RET_ERROR;
            }

            stream >> msg;
            stream >> mCurTransactionDataSize;

            mCurTransactionMsg = (eTCPMessage)msg;

            if(mCurTransactionDataSize != 0)
            {
                mCurTransactionData = stream.device()->readAll();
                if(mCurTransactionData.size() < mCurTransactionDataSize)
                {
                    mProtocolRxState = TCP_PROTOCOL_GET_DATA_STATE;
//                    qDebug() << "Datasize is: " << mCurTransactionDataSize << ". Going in GET_DATA_STATE";
                }
                else if(mCurTransactionData.size() > mCurTransactionDataSize)
                {
                    //error
//                    qDebug("Rx data [%d] > Transaction data [%d].  Aborting transaction",mCurTransactionData.size(),(int)mCurTransactionDataSize);
                    ResetRxStateMachine();
                }
                else
                {
                    DecodeTCPMessage();
                    ResetRxStateMachine();
                }
            }
            else
            {
                DecodeTCPMessage();
                ResetRxStateMachine();
            }

            break;
        }
        case TCP_PROTOCOL_GET_MSG_STATE:
        {
            break;
        }
        case TCP_PROTOCOL_GET_DATASIZE_STATE:
        {
            break;
        }
        case TCP_PROTOCOL_GET_DATA_STATE:
        {
            mCurTransactionData.append(data);
            if(mCurTransactionData.size() == mCurTransactionDataSize)
            {
                //All data received
//                qDebug() << "Data Rx complete...  New data size = " << mCurTransactionData.size();
                DecodeTCPMessage();
                ResetRxStateMachine();
            }
            else if(mCurTransactionData.size() > mCurTransactionDataSize)
            {
                //error
                qDebug("Rx data > Transaction data.  Aborting transaction");
                ResetRxStateMachine();
            }
            else
            {
//                qDebug() << "Chunk received.  New data size = " << mCurTransactionData.size();
            }
            break;
        }
    }

    return RET_OK;
}

QByteArray CTCPProtocol::GetHeartbeatReqPacket()
{
    return BuildSimpleRequestPacket((qint32)TCP_MSG_HEARTBEAT_REQUEST);
}
QByteArray CTCPProtocol::GetStationNameReqPacket()
{
    return BuildSimpleRequestPacket((qint32)TCP_MSG_STATION_NAME_REQUEST);
}
QByteArray CTCPProtocol::GetZTStatusReqPacket()
{
    return BuildSimpleRequestPacket((qint32)TCP_MSG_ZT_STATUS_REQUEST);
}
QByteArray CTCPProtocol::GetZTLogDownloadReqPacket()
{
    return BuildSimpleRequestPacket((qint32)TCP_MSG_ZTLOG_DOWNLOAD_REQUEST);
}

QByteArray CTCPProtocol::BuildSimpleRequestPacket(qint32 RequestID)
{
    QByteArray packet;
    packet.clear();
    QDataStream stream(&packet,QIODevice::WriteOnly);
    stream.device()->seek(0);

    stream << TCP_PROTOCOL_HEADER << RequestID << (qint64)0;

    return packet;
}

QByteArray CTCPProtocol::GetTrainLogsDownloadReqPacket()
{
    return BuildSimpleRequestPacket((qint32)TCP_MSG_TRAINLOGS_DOWNLOAD_REQUEST);
}

QByteArray CTCPProtocol::GetTrainLogsFileDataAckPacket(qint32 Acknowledge)
{
    QByteArray packet;
    packet.clear();
    QDataStream stream(&packet,QIODevice::WriteOnly);
    stream.device()->seek(0);
    qint64 size = 4;

    stream << TCP_PROTOCOL_HEADER << (qint32)TCP_MSG_TRAINLOG_FILE_DATA_ACK << size << Acknowledge;

    return packet;
}

QByteArray CTCPProtocol::GetDeleteZTLogReqPacket()
{
   return BuildSimpleRequestPacket((qint32)TCP_MSG_DELETE_ZTLOG_REQUEST);
}

QByteArray CTCPProtocol::GetSetZTFunctionsPacket(QByteArray &Data)
{
    QByteArray packet;
    packet.clear();
    QDataStream stream(&packet,QIODevice::WriteOnly);
    stream.device()->seek(0);
    qint64 size = Data.size();

    stream << TCP_PROTOCOL_HEADER << (qint32)TCP_MSG_SET_ZT_FUNCTIONS << size;
    packet.append(Data);

    return packet;
}




void CTCPProtocol::TCPTxRequest(const QByteArray &request)
{
    qDebug("No reimplementation of TXRequest in TCPProtocol.c.  Request not sent...");
}

void CTCPProtocol::ResetRxStateMachine()
{
    mCurTransactionData.clear();
    mCurTransactionDataSize = 0;
    mCurTransactionMsg = TCP_MSG_UNKNOWN;
    mProtocolRxState = TCP_PROTOCOL_GET_HEADER_STATE;

}

int CTCPProtocol::DecodeTCPMessage()
{
    switch(mCurTransactionMsg)
    {
        case TCP_MSG_HEARTBEAT_RESPONSE:
        {
            TCPRxHeartbeat();
            break;
        }
        case TCP_MSG_STATION_NAME_RESPONSE:
        {
            TCPRxStationName(QString(mCurTransactionData));
            break;
        }
        case TCP_MSG_ZT_STATUS_RESPONSE:
        {
            TCPRxZTStatus(mCurTransactionData);
            break;
        }
           case TCP_MSG_ZTLOG_DOWNLOAD_RESPONSE:
        {
            TCPRxZTLog(QString(mCurTransactionData));
            break;
        }
        case TCP_MSG_TRAINSLOGS_DOWNLOAD_ACK:
        {
            qint32 NbFiles = 0;
            QDataStream strm(mCurTransactionData);
            strm.device()->seek(0);

            strm >> NbFiles;
            TCPRxTrainLogsDownladAck(NbFiles);
            break;
        }
        case TCP_MSG_TRAINLOG_FILE_DATA:
        {
            TCPRxTrainLogFileData(mCurTransactionData);
            break;
        }
        case TCP_MSG_TRAINLOGS_DOWNLOAD_FINISHED:
        {
            TCPRxTrainLogsDownloadFinished();
            break;
        }
        case TCP_MSG_DELETE_ZTLOG_ACK:
        {
            qint32 ack;
            QDataStream strm(mCurTransactionData);
            strm.device()->seek(0);
            strm >> ack;

            TCPRxDeleteZTLogAck((bool)ack);
            break;
        }
        case TCP_MSG_SET_ZT_FUNCTIONS_ACK:
        {
            qint32 ack;
            QDataStream strm(mCurTransactionData);
            strm.device()->seek(0);
            strm >> ack;

            TCPRxSetZTFunctionsAck(ack);
            break;
        }

        case TCP_MSG_SET_ZT_FUNCTIONS:
        case TCP_MSG_DELETE_ZTLOG_REQUEST:
        case TCP_MSG_HEARTBEAT_REQUEST:
        case TCP_MSG_STATION_NAME_REQUEST:
        case TCP_MSG_ZT_STATUS_REQUEST:
        case TCP_MSG_ZTLOG_DOWNLOAD_REQUEST:
        case TCP_MSG_TRAINLOGS_DOWNLOAD_REQUEST:
        case TCP_MSG_TRAINLOG_FILE_DATA_ACK:
        case TCP_MSG_UNKNOWN:
        {
            qDebug() << "Received invalid msg:" << mCurTransactionMsg;
            break;
        }
    }

    return RET_OK;
}




QDataStream &operator>>(QDataStream &in, CTCPZTStatus &dest)
{

    in >> dest.mZT1Status
       >> dest.mZT2Status
       >> dest.mNbPass
       >> dest.mNbTrigs
       >> dest.mZTStartDateTime
       >> dest.mActualDateTime
       >> dest.mPGTreshold
       >> dest.mModeMaintenanceON
       >> dest.mCalibModeON
       >> dest.mFNTKActive
       >> dest.mFNAnalysisActive
       >> dest.mPGTKActive
       >> dest.mPGAnalysisActive
       >> dest.mPP1TKActive
       >> dest.mPP1AnalysisActive
       >> dest.mPP2TKActive
       >> dest.mPP2AnalysisActive
       >> dest.mZT1TKActive
       >> dest.mZT1AnalysisActive
       >> dest.mZT2TKActive
       >> dest.mZT2AnalysisActive
       >> dest.mUSBKeyConnected;

        return in;
}

QDataStream &operator>>(QDataStream &in, CTCPZTFunctionsStatus &dest)
{
    in  >> dest.mFNTKActive
        >> dest.mFNAnalysisActive
        >> dest.mPGTKActive
        >> dest.mPGAnalysisActive
        >> dest.mPP1TKActive
        >> dest.mPP1AnalysisActive
        >> dest.mPP2TKActive
        >> dest.mPP2AnalysisActive
        >> dest.mZT1TKActive
        >> dest.mZT1AnalysisActive
        >> dest.mZT2TKActive
        >> dest.mZT2AnalysisActive;

    return in;
}

QDataStream &operator<<(QDataStream &out, const CTCPZTFunctionsStatus &source)
{
    out << source.mFNTKActive
        << source.mFNAnalysisActive
        << source.mPGTKActive
        << source.mPGAnalysisActive
        << source.mPP1TKActive
        << source.mPP1AnalysisActive
        << source.mPP2TKActive
        << source.mPP2AnalysisActive
        << source.mZT1TKActive
        << source.mZT1AnalysisActive
        << source.mZT2TKActive
        << source.mZT2AnalysisActive;

    return out;
}
