#include "Core/recognizesystem.h"

#include "streamingversiondata.h"

#include <updatenotifywidget.h>

RecognizeSystem::RecognizeSystem(QObject *parent):
    QObject(parent)
{
    packetType = PacketType::TYPE_NONE;
    filePath.clear();
    fileSize = 0;
    message.clear();
    sizeReceiveData = 0;
    tmpBlock.clear();
    countSend = 0;
    folderList = new QList<QString>;
}

RecognizeSystem::~RecognizeSystem()
{

}

void RecognizeSystem::initialize(UpdateController *updateController,
                                 DataParser *dataParser,
                                 MainWindow *mainWindow,
                                 HashComparer *hashComparer,
                                 TCPClient *client)
{
    this->updateController = updateController;
    this->dataParser = dataParser;
    this->mainWindow = mainWindow;

    connect(this,&RecognizeSystem::sigSaveLoginData,dataParser,&DataParser::createAuthData);
    connect(this,&RecognizeSystem::sigStartCompare,hashComparer,&HashComparer::CompareDeltas);
    connect(this,&RecognizeSystem::sigUpdateBytesAvailable,mainWindow,&MainWindow::updateProgress,Qt::QueuedConnection);
    connect(this,&RecognizeSystem::sigLoadComplete,mainWindow,&MainWindow::loadComplete);
    connect(this,&RecognizeSystem::sigNeedUpdate,mainWindow,&MainWindow::setNeedUpdate);
    connect(this,&RecognizeSystem::sigSocketDisabled,mainWindow,&MainWindow::lostConnection);
    connect(this,&RecognizeSystem::sigSaveLoginData,mainWindow,&MainWindow::checkLoginResult); //TODO: прибратся! 2 бинда на 1 сигнал
    connect(this,&RecognizeSystem::sigSocketWaitForReadyRead,client,&TCPClient::waitRead,Qt::DirectConnection);
    connect(this,&RecognizeSystem::sigServerBlocked,mainWindow,&MainWindow::serverBlocked);
    connect(this,&RecognizeSystem::sigShowServerList,mainWindow,&MainWindow::showServerListWidget);
}

void RecognizeSystem::recognize(QTcpSocket *socket)
{
    qDebug() << "RecognizeThreadId " << QThread::currentThreadId();

    QDataStream stream(socket);
    stream.setVersion(QDataStream::Qt_DefaultCompiledVersion);

    while(socket->bytesAvailable())
    {

      if (socket->state() != QTcpSocket::ConnectedState) return;

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

            stream.startTransaction();
            stream >> packetType;

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

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

            }

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

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

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

            filePath = Tools::createReceiveFullPath(filePath,updateController->getServerVersion());

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

            packetType = PacketType::TYPE_NONE;
            emit sigUpdateBytesAvailable();
            continue;
        }

        if(packetType == PacketType::TYPE_FILE)     //загрузка файлов
        {
            //ПОЛУЧЕНИЕ ПУТИ
            //ПОЛУЧЕНИЕ РАЗМЕРА ФАЙЛА
            forever
            {
                stream.startTransaction();
                stream >> filePath;
                stream >> fileSize;

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

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

                }

                filePath = Tools::createReceiveFullPath(filePath,updateController->getServerVersion());

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

                socket->waitForReadyRead(100);
                break;
            }


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

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

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



            file.open(QFile::Append);

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

                if(!stream.commitTransaction()){

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

                    continue;
                }

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

                sizeReceiveData += toFile;
                countSend++;

                tmpBlock.clear();

                if(sizeReceiveData == fileSize){
                    emit sigSendDebugLog(Tools::getTime() + "FINAL Count send: " + QString::number(countSend));
                    emit sigSendDebugLog(Tools::getTime() + "FINAL Size received: " + QString::number(sizeReceiveData));
                    emit sigSendDebugLog(Tools::getTime() + "FINAL File size" + QString::number(fileSize));
                    emit sigUpdateBytesAvailable();
                    break;
                }
            }

            file.close();
            emit sigSendDebugLog(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::createReceiveFullPath(filePath,updateController->getServerVersion());

            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->calculateCommonHash();
            emit sigLoadComplete();
            packetType = PacketType::TYPE_NONE;
        }

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

            bool flag = false;
            quint64 size = 0;
            quint64 fileCount = 0;

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

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

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

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

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

            dataParser->xmlParser(array);

            packetType = PacketType::TYPE_NONE;
        }

        if(packetType == PacketType::HASH_READY)
        {
           mainWindow->checkUpdate();
        }
        packetType = PacketType::TYPE_NONE;
    }
}

void RecognizeSystem::checkAccessType(QString type)
{
    if(type == "instructor")
    {
        mainWindow->callUpdateList();
    }
}

void RecognizeSystem::setServerVersion(StreamingVersionData *serverVersion)
{
    dataParser->changeVersion(serverVersion->getViewName());
    updateController->setServerVersion(serverVersion);
    mainWindow->setCurrentVersionName(serverVersion->getViewName());
}

void RecognizeSystem::showServerDataList(QList<StreamingVersionData*> *showServerDataList)
{
    emit sigShowServerList(showServerDataList);
}
