#include "UpdateController.h"


#include <QElapsedTimer>
#include <QThread>

UpdateController::UpdateController(QObject *parent) :
    QObject(parent),
    versionContainer(nullptr)
{
    applicationFolderPath = QDir::currentPath() + applicationFolderName;
    hashCalculator = new FastHashCalculator;
}

void UpdateController::initialize(VersionContainer *versionContainer,DataParserOutput *dataParserOut, SendSystem *sendSystem)
{
    this->versionContainer = versionContainer;
    this->sendSystem = sendSystem;
    this->dataParserOut = dataParserOut;
}

void UpdateController::calculateCommonHash()
{
    appDataList.clear();
    QElapsedTimer timer;
    timer.start();
    qDebug() << "Start calculate... ";
    //appDataList = calculateHash(applicationFolderPath,"StreamingAssets");
    hashCalculator->calculateHashes(applicationFolderPath,"StreamingAssets");
    appDataList = *hashCalculator->getHashList();
    calculateStreamingHash();
    appDataList.append(streamingDataList);
    qDebug() << "Hash count: " << appDataList.count() ;
    dataParserOut->createFileDataList(appDataList,fullStaticDataFolderName + hashFilename);
    qDebug() << "UpdateController threadID " << QThread::currentThreadId();
    qDebug() <<"Calculate time " << timer.elapsed();
}

void UpdateController::calculateStreamingHash()
{
    streamingDataList.clear();
    //streamingDataList = calculateHash(QDir::currentPath() + streamingAssetsPath,"");
    hashCalculator->calculateHashes(QDir::currentPath() + streamingAssetsPath,"");
    streamingDataList = *hashCalculator->getHashList();
    //std::sort(streamingDataList.begin(),streamingDataList.end());
    dataParserOut->createFileDataList(streamingDataList,streamingHashFilename);
}

QList<FileData> UpdateController::calculateHash(const QString& path,const QString& ignoreName)
{
    qDebug() << "Try calculate";

   if(!QDir(path).exists())
   {
        QDir().mkdir(path);
   }

    QList<FileData> *hashes = new QList<FileData>;
    quint64 currentSize = 0;

    QStringList filter;
    filter << "*";
    QString hashString;

    QDirIterator dirIterator(path,filter, QDir::AllEntries | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);

    while (dirIterator.hasNext())
    {
        QFileInfo fileInfo(dirIterator.next());
        FileData currentFile;
        QString fileName = fileInfo.fileName();
        if(fileInfo.isDir() && !fileName.startsWith(".") && fileName != "RRJLoader")
        {
            currentFile.path = Tools::createLocalPath(fileInfo.absoluteFilePath());
            currentFile.hash = "FOLDER";

            if(!hashes->contains(currentFile))
            {
                hashes->push_back(currentFile);
            }
        }
    }

    QDirIterator fileIterator(path,filter,QDir::Files | QDir::NoDotAndDotDot,QDirIterator::Subdirectories);

    while (fileIterator.hasNext())
        {
            fileIterator.next();
            QFileInfo fileInfo = fileIterator.fileInfo();
            FileData currentFile;
            QFile file(fileInfo.absoluteFilePath());

            currentSize += fileInfo.size();


            quint64 fileSize = file.size();     //буффер для хэширования крупных файлов
            const quint64 bufferSize = 1024;

            if(fileInfo.isHidden()) continue;
            if(ignoreName != "" && fileInfo.path().contains(ignoreName)) continue;

            if(fileInfo.isFile() && file.open(QIODevice::ReadOnly))
            {
                char buffer[bufferSize];
                int bytesRead;
                int readSize = qMin(fileSize,bufferSize);

                QCryptographicHash hash(QCryptographicHash::Md5);

                while(readSize > 0 && (bytesRead = file.read(buffer,readSize)) > 0)
                {
                    fileSize -= bytesRead;
                    hash.addData(buffer,bytesRead);
                    readSize = qMin(fileSize,bufferSize);
                }

                hashString = QString(hash.result().toHex());
                currentFile.path = Tools::createLocalPath(fileInfo.absoluteFilePath());
                currentFile.hash = hashString;
                hashes->push_back(currentFile);
                file.close();
            }
    }

    return *hashes;
}

void UpdateController::updateFilesOnServer(QList<FileData> *fileSendList){

    QListIterator<FileData> serverIterator(*fileSendList);
    try {

        while(serverIterator.hasNext())
        {
            FileData data = serverIterator.next();

            if (data.hash == "FOLDER")
            {
                sendSystem->sendFolderBlock(data.path);
            }
            else
            {
                QString fullPath = Tools::createReceiveFullPath(data.path,versionContainer->getServerVersionData());
                sendSystem->sendFileBlockWithVersion(fullPath,data.path);
            }

        }

        calculateCommonHash();
        sendSystem->sendFinish();

        emit sigUpdateComplete(true);
    }
    catch (...)
    {
        emit sigUpdateComplete(false);
    }

}

FastHashCalculator *UpdateController::getHashCalculator() const
{
    return hashCalculator;
}


UpdateController::~UpdateController()
{

}
