#include "Core/recognizesystem.h"

RecognizeSystem::RecognizeSystem(QObject *parent):
    QObject(parent)
{
    packetType = PacketType::TYPE_NONE;
    filePath.clear();
    fileSize = 0;
    message.clear();
    sizeReceiveData = 0;
    tmpBlock.clear();
    countSend = 0;
}

RecognizeSystem::~RecognizeSystem()
{

}

void RecognizeSystem::Initialize(UpdateController *updateController,DataParser *dataParser)
{
    this->updateController = updateController;
    this->dataParser = dataParser;
    connect(this,&RecognizeSystem::SaveLoginData,dataParser,&DataParser::CreateAuthData);
}

void RecognizeSystem::Recognize(QTcpSocket *socket)
{
    QDataStream stream(socket);
    stream.setVersion(QDataStream::Qt_DefaultCompiledVersion);

    while(socket->bytesAvailable())
    {

        if(!stream.commitTransaction()){
            qDebug() << "BUSY, WAIT";
        }

        if(packetType == PacketType::TYPE_NONE){    //определение первичного пакета

            stream.startTransaction();
            stream >> packetType;

            if(!stream.commitTransaction()){
                emit onSendDebugLog(Tools::GetTime() + " CLIENT: packetType - FAIL commitTransaction");

                if(socket->waitForReadyRead(TCP_READ_TIMEOUT)){
                    emit onSendDebugLog("ERROR: PACKET TYPE READ TIMEOUT");
                    return;
                }
                continue;

            }

            //qDebug() << Tools::GetTime() << "CLIENT: type: " << packetType;
        }

        if(packetType == PacketType::TYPE_MSG){     //поведение на тип пакета с сообщением

            stream.startTransaction();
            stream >> message;

            if(!stream.commitTransaction()){
                emit onSendDebugLog(Tools::GetTime() + "CLIENT: Message - FAIL commitTransaction");
                if(socket->waitForReadyRead(TCP_READ_TIMEOUT)){
                    emit onSendDebugLog(Tools::GetTime() + "ERROR: MESSAGE READ TIMEOUT");
                    return;
                }
                continue;
            }

            emit onSendDebugLog(Tools::GetTime() + " CLIENT: Message from server " + message);    //результат обрабатывать тут?
            packetType = PacketType::TYPE_NONE;
            continue;
        }

        if(packetType == PacketType::TYPE_FOLDER){  //создание папок
            stream.startTransaction();
            stream >> filePath;

            if(!stream.commitTransaction()){
                continue;
            }

            filePath = Tools::CreateFullPath(filePath);

            QDir dir(filePath);
            if(!dir.exists()){
                if(dir.mkpath(filePath)){
                    qDebug() << "Dir Created";
                }
            }

            packetType = PacketType::TYPE_NONE;
            continue;
        }

        if(packetType == PacketType::TYPE_FILE)     //загрузка файлов
        {

            //ПОЛУЧЕНИЕ ПУТИ
            //ПОЛУЧЕНИЕ РАЗМЕРА ФАЙЛА
            forever
            {
                stream.startTransaction();
                stream >> filePath;
                stream >> fileSize;

                if(!stream.commitTransaction()){
                    emit onSendDebugLog(Tools::GetTime() + "CLIENT: filePath, fileSize - FAIL commitTransaction");

                    if (!socket->waitForReadyRead(TCP_READ_TIMEOUT)) {
                        emit onSendDebugLog(Tools::GetTime() + "CLIENT: ERROR! readyRead timeout - filePath, fileSize!!!");
                        return;
                    }
                    continue;

                }

                filePath = Tools::CreateFullPath(filePath);

                emit onSendDebugLog("CLIENT: filesize: " + QString::number(fileSize));
                emit onSendDebugLog("CLIENT: filePath: " + filePath);

                emit SocketWaitForReadyRead(100);
                break;
            }


            //ПОЛУЧЕНИЕ САМОГО ФАЙЛА
            emit onSendDebugLog(Tools::GetTime() + "AfterRead size and path BytesAvailable: " + socket->bytesAvailable());

            //УКАЗАНИЕ ПУТИ ФАЙЛА
            QFile file(filePath);

            if (file.exists())
            {
                file.remove();  //удаление файла, если он уже есть, но необходимо обновить
                emit onSendDebugLog(Tools::GetTime() + "Delete exist file: " + filePath);
            }



            file.open(QFile::Append);

            forever
            {
                stream.startTransaction();
                stream >> tmpBlock;

                if(!stream.commitTransaction()){

                    if(socket->state() == QAbstractSocket::UnconnectedState){
                        emit SockedDisabled();
                        return;
                    }
                    if(socket->waitForReadyRead(TCP_READ_TIMEOUT)){
                        continue;
                    }

                    continue;
                }

                quint64 toFile = file.write(tmpBlock);
                emit onSendDebugLog(Tools::GetTime() + "CLIENT: toFile :" + toFile);

                sizeReceiveData += toFile;
                countSend++;

                tmpBlock.clear();

                if(sizeReceiveData == fileSize){
                    emit onSendDebugLog(Tools::GetTime() + "FINAL Count send: " + QString::number(countSend));
                    emit onSendDebugLog(Tools::GetTime() + "FINAL Size received: " + QString::number(sizeReceiveData));
                    emit onSendDebugLog(Tools::GetTime() + "FINAL File size" + QString::number(fileSize));
                    emit UpdateBytesAvailable(fileSize,sizeReceiveData);
                    break;
                }
            }

            file.close();
            emit onSendDebugLog(Tools::GetTime() + "File loaded");

            //ОЧИСТКА ПОСЛЕ ПЕРЕДАЧИ

            filePath.clear();
            fileSize = 0;
            tmpBlock.clear();
            sizeReceiveData = 0;
            countSend = 0;
        }

        if(packetType == PacketType::TYPE_DELETE)   //удаление лишних файлов (рекурсивно удаляет все содежимое)
        {
            stream.startTransaction();
            stream >> filePath;

            if(!stream.commitTransaction()){
                continue;
            }

            filePath = Tools::CreateFullPath(filePath);

            QFileInfo fileInfo(filePath);


            if(fileInfo.exists())
            {
                if(fileInfo.isFile()){
                    QFile file(filePath);
                    file.remove();
                }

                if(fileInfo.isDir()){
                    QDir dir(filePath);
                    dir.removeRecursively();
                }

                qDebug() << Tools::GetTime() << "Deleted: " << filePath;
            }

            packetType = PacketType::TYPE_NONE;
            continue;

        }

        if(packetType ==PacketType::TYPE_FINISH){   //для повторного создания хэша после загрузки
            updateController->CalculateHash();
            emit LoadComplete();
            packetType = PacketType::TYPE_NONE;
        }

        if(packetType == PacketType::TYPE_NEEDUPDATE){  //нужно обновление

            bool flag;
            quint64 size;

            stream.startTransaction();
            stream >> flag;
            stream >> size;

            emit onNeedUpdate(flag,size);
            packetType = PacketType::TYPE_NONE;
        }

        if(packetType == PacketType::TYPE_XMLANSWER){   //ответы формата XML
            QByteArray array;
            stream.startTransaction();
            stream >> array;

            if(!stream.commitTransaction()){
                continue;
            }

            XMLParser(array);

            packetType = PacketType::TYPE_NONE;
        }

        packetType = PacketType::TYPE_NONE;
    }
}

void RecognizeSystem::XMLParser(QByteArray array)
{
    QXmlStreamReader xmlReader(array);

    xmlReader.readNext();

    while(!xmlReader.atEnd())
    {
        if(!xmlReader.isStartElement()) {
            xmlReader.readNext();
            continue;
        }

        if(xmlReader.name() == "ServerNotify")
        {
            foreach(const QXmlStreamAttribute &attr, xmlReader.attributes())
            {
                QString name = attr.name().toString();
                QString value = attr.value().toString();

                if(name == "Code"){
                    if (value == "END"){

                        emit SockedDisabled();

                    }
                }
            }
        }

        if(xmlReader.name() == "ServerAuthorization"){

            ServerAuthorization *serverAuth = new ServerAuthorization;

            foreach(const QXmlStreamAttribute &attr, xmlReader.attributes())
            {
                QString name = attr.name().toString();
                QString value = attr.value().toString();

                if (name == "Result"){
                    serverAuth->Result = value == "true" ? true : false;
                }

                if (name == "InstructorName"){
                    serverAuth->InstructorName = value;
                }

                if (name == "ClientName"){
                    serverAuth->ClientName = value;
                }

                if (name == "AccessType"){
                    serverAuth->AccessType = value;
                }
            }

            emit SaveLoginData(serverAuth);
        }

        xmlReader.readNext();
    }

}
