#include "recognizesystem.h"

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

}

void RecognizeSystem::initialize(UpdateController *updateController,DataParser* dataParser,
    ServerLMSWidget *server,SendSystem *sendSystem, ClientHandler *handler)
{
    this->updateController = updateController;
    this->dataParser = dataParser;
    this->server = server;
    this->clientHandler = handler;
    this->sendSystem = sendSystem;
    socket = handler->getSocket();

    connect(this,&RecognizeSystem::sigCalculateHash,updateController,&UpdateController::calculateFullHash,Qt::AutoConnection);
    connect(this,&RecognizeSystem::sigCalculateHash,updateController,&UpdateController::setUpCurrentServerHash,Qt::AutoConnection);
    connect(this,&RecognizeSystem::sigChangeVersion,updateController,&UpdateController::changeAssetVersion,Qt::AutoConnection);
    connect(this,&RecognizeSystem::sigDeleteVersion,updateController,&UpdateController::deleteAssetVersion,Qt::AutoConnection);
    connect(this,&RecognizeSystem::sigCopyVersion,updateController,&UpdateController::createCopyVersion,Qt::AutoConnection);
    connect(this,&RecognizeSystem::sigXmlParser,dataParser->getProcessParser(),&ProcessParser::read,Qt::DirectConnection);

    qDebug() << "Recognize init thread ID " << QThread::currentThreadId();
}

void RecognizeSystem::recognize()
{
    mutex->lock();
    qDebug() << "Recognize thread ID " << QThread::currentThreadId();
    QDataStream stream(socket);
    stream.setVersion(QDataStream::Qt_DefaultCompiledVersion);
    QByteArray data;
    Client *client = clientHandler->getClient();

    while (socket->bytesAvailable() > 0)
    {

        if (packetType == PacketType::TYPE_NONE)
        {
            stream.startTransaction();

            if(!isPackageTypeInited)        //первичная инициализация для типа клиента
            {
                char *read = new char[0];
                stream.readRawData(read,1);
                packetType = static_cast<PacketType>(QString(read[0]).toInt());

                packetTypeInit(packetType,client);

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

            if(client->getIsUnity())
            {
                char *read = new char[0];
                stream.readRawData(read,1);
                packetType = static_cast<PacketType>(QString(read[0]).toInt());

                if(!stream.commitTransaction()) continue;
                continue;
            }
            else
            {
                stream >> packetType;

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

        }

        if (packetType == PacketType::TYPE_COMMAND) //TODO: надо переделать под какой то нормальный тип, который уже существует
        {
            stream.startTransaction();
            stream >> command;

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

        if (packetType == PacketType::TYPE_UPDATE)
        {

            sendSystem->updateFiles(updateController->getFileSendList(),
                                    updateController->getFileDeleteList());

            qDebug()<< "Call update";
            packetType = PacketType::TYPE_NONE;
        }

        if(packetType == PacketType::TYPE_CHECK_VERSION)
        {
            QFile checkFile(clientHash);
            checkFile.open(QIODevice::ReadOnly);
            updateController->compareFiles(clientHandler,checkFile.readAll());
            checkFile.close();
        }

        if (packetType == PacketType::TYPE_XMLANSWER)
        {

            if(clientHandler->getClient()->getIsUnity())
            {
                data = socket->readAll();
            }
            else
            {
                stream.startTransaction();
                stream >> data;

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

            qDebug() << data;
            emit sigXmlParser(clientHandler,data);
            packetType = PacketType::TYPE_NONE;
            continue;
        }

        if(packetType == PacketType::TYPE_FOLDER)   //создание папок
        {
            if(client->getIsUnity())
            {
                filePath = socket->readAll();
                filePath = Tools::createSharedPath(filePath);
            }
            else
            {
                stream.startTransaction();
                stream >> filePath;

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

                filePath = 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)  //выгрузка одного файла
        {

            if(client->getIsUnity())
            {
                DataInfo *currentFileData = updateController->getCurrentDataInfo();
                filePath = currentFileData->path;
                filePath = Tools::createSharedPath(filePath);

                QFile file(filePath);

//                //ПРОВЕРКА НА ИЗМЕНЕНИЕ БАЗОВОЙ ВЕРСИИ
//                bool check = checkIsChangeable();
//                bool check2 = checkNonStaticData(filePath);
//                if(!check && check2)
//                {
//                    packetType = PacketType::TYPE_NONE;
//                    sendSystem->sendNotify(commandTryBaseChange);
//                    mutex->unlock();
//                    return;
//                }

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

                if (!file.open(QFile::Append))
                {
                    QString folderPath = Tools::createFolderPath(filePath);
                    qDebug() << "FULL PATH: " << folderPath;
                    QDir dir(folderPath);
                    if (!dir.exists()){
                        dir.mkpath(".");
                    }

                    file.open(QFile::Append);
                }

                //socket->waitForReadyRead(1000);

                fileSize = currentFileData->size;

                qint64 readSize = 65535;
                forever
                {
                    if(fileSize < readSize)
                    {
                        readSize = fileSize;
                        qDebug() << "LastPackage: " << readSize;
                    }

                    socket->waitForReadyRead(20);
                    tmpBlock = socket->read(readSize);

                    quint64 toFile = file.write(tmpBlock);
                    fileSize -= toFile;
                    sizeReceiveData += toFile;
                    countSend++;

                    tmpBlock.clear();
                    qDebug() << "Loading progress: " << fileSize << "/" << currentFileData->size;

                    if(fileSize == 0) break;

                }

                file.close();
                filePath.clear();
                updateController->clearCurrentDataInfo();

                socket->waitForReadyRead(100);

                packetType = PacketType::TYPE_NONE;

            }
            else
            {
                forever
                {
                    stream.startTransaction();
                    stream >> filePath;
                    stream >> fileSize;

                    if(!stream.commitTransaction()) continue;

                    filePath = createFullPath(filePath);
                    socket->waitForReadyRead(100);
                    break;
                }

//                //ПРОВЕРКА НА ИЗМЕНЕНИЕ БАЗОВОЙ ВЕРСИИ
//                bool check = checkIsChangeable();
//                bool check2 = checkNonStaticData(filePath);
//                if(!check && check2)
//                {
//                    sendSystem->sendNotify(commandTryBaseChange);
//                    packetType = PacketType::TYPE_NONE;
//                    mutex->unlock();
//                    return;
//                }

                QFile file(filePath);
                QFileInfo fileInfo(file);

                if(file.exists())
                {
                    file.remove();
                }

                file.open(QFile::Append);

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

                    if(!stream.commitTransaction()){

                        if(socket->state() == QAbstractSocket::UnconnectedState){
                            qDebug() << "UNCONNECT";
                            mutex->unlock();
                            file.close();
                            return;
                        }
                        if(socket->waitForReadyRead(100)){
                            continue;
                        }

                        continue;
                    }

                     quint64 toFile = file.write(tmpBlock);
                     sizeReceiveData += toFile;
                     countSend++;

                     tmpBlock.clear();

                     if(sizeReceiveData == fileSize) break;


                }

                QString logMessage = Tools::getTime() + " ";
                logMessage.append("Load from " + client->getLogin() + " ");
                logMessage.append(fileInfo.fileName());

                emit sigSendToLogger(logMessage);

                file.close();

                filePath.clear();
                fileSize = 0;
                tmpBlock.clear();
                sizeReceiveData = 0;
                countSend = 0;
                packetType = PacketType::TYPE_NONE;
            }

        }

        if (packetType == PacketType::TYPE_FILESIZE)
        {
            fileSize = socket->readAll().toULong();
            qDebug() << fileSize;
            packetType = PacketType::TYPE_NONE;
            continue;
        }

        if (packetType == PacketType::TYPE_FINISH)
        {
            emit sigCalculateHash();
            packetType = PacketType::TYPE_NONE;
        }

        if(packetType == PacketType::CHANGE_DATA_VERSION)
        {
            stream.startTransaction();
            QString versionName;
            stream >> versionName;

            if(!stream.commitTransaction()) continue;

            qDebug() << "For change " + versionName;

            emit sigChangeVersion(versionName);

        }

        if(packetType == PacketType::COPY_VERSION)
        {
            QString source;
            QStringList result;

            stream.startTransaction();
            stream >> source;

            if(!stream.commitTransaction()) continue;

            result = source.split(";");

            if (updateController->checkDuplicate(result[1]))
            {
                sendSystem->sendNotify(commandDuplicateVerName);
                packetType = PacketType::TYPE_NONE;
                break;
            }

            emit sigCopyVersion(result[0],result[1],result[2]);
            sendSystem->sendPacketType(PacketType::BUSY);
        }

        if(packetType == PacketType::DELETE_DATA_VERSION)
        {
            stream.startTransaction();
            QString versionName;
            stream >> versionName;

            if(!stream.commitTransaction()) continue;

            qDebug() << "For delete " + versionName;


            if (versionName == baseNameVersion)
            {
                sendSystem->sendNotify(commandTryBaseDelete);
            }
            else if (versionName == updateController->getCurrentVersionName())
            {
                sendSystem->sendNotify(commandTryActiveDelete);
            }
            else
            {
                emit sigDeleteVersion(versionName);
            }

        }

        packetType = PacketType::TYPE_NONE;
    }

    mutex->unlock();
}

void RecognizeSystem::packetTypeInit(PacketType packet,Client *client)
{
    if(packet == PacketType::TYPE_QT)
    {
        client->setUnity(false);

        qDebug() << "ConnectionType isUnity: " << client->getIsUnity();
    }
    else if (packet == PacketType::TYPE_UNITY)
    {
        client->setUnity(true);
    }

     isPackageTypeInited = true;

    packetType = PacketType::TYPE_NONE;
}

QString RecognizeSystem::createFullPath(QString path)
{
    QString fullPath;
    qint8 pos = path.indexOf("Application");

    QString localPath = path.remove(0,--pos);

    //qDebug() << "CLIENT: localPath" << localPath;
    fullPath = QDir::currentPath() + localPath;

    return fullPath;
}

bool RecognizeSystem::checkIsChangeable()
{
    return updateController->getCurrentVersion()->getIsChangeable();
}

bool RecognizeSystem::checkNonStaticData(QString path)
{
    if(path.contains(sharedDataFolderName)) return true;

    return false;
}

RecognizeSystem::~RecognizeSystem()
{

}
