#include "gameres.h"
#include "config.h"
#include "filesystem.h"

#include <QString>
#include <QDir>
#include <QFile>
#include <QTime>
#include <string>

GameRes::GameRes() {}
GameRes::GameRes(const GameRes&) {}
GameRes& GameRes::operator=(GameRes&) {}

// Public functions

void GameRes::openDatFile(int id) {
    QStringList dat_files;
    dat_files << AConfig::getInstance()->getValue("Local", "file")
              << "client_general.dat"
              << "client_sound.dat"
              << "client_surface.dat"
              << "client_highres.dat";

    if (dat_files[id] == nullptr) {
        emit openDatFileFinished(-100); // -100 = incorrect id
        return;
    }

    std::string filename = (app->config->getValue("Local", "folder") + "/" + dat_files[id]).toStdString();

    qDebug("%s:%i: %s%s", __FILE__, __LINE__, "Инициализация dat-файла. Открываем файл ", filename);
    int dat_state = app->datfiles[id].InitDatFile(file, 0);
    qDebug("%s:%i: %s%d", __FILE__, __LINE__, "Состояние dat-файла: ", dat_state);

    emit openDatFileFinished(dat_state);
}

void GameRes::closeDatFile(int id) {
    int result = datfiles[id].CloseDatFile();
    emit closeDatFileFinished(result);
    return;
}

void GameRes::applyPatch(QString name) {
    emit startedPatching(name);

    qDebug("%s:%i: %s%s", __FILE__, __LINE__, "Начинаем применение патча ", app->helper->stringToChar(name));
    QLabel* label = app->window->findChild<QLabel*>(name + "Status");
    QDir dir(QApplication::applicationDirPath() + "/data");

    if (!dir.exists()) {
        emit applyAllFinished(-100); // -100 - not found data folder
        return;
    }

    QStringList paths = dir.entryList(QStringList(name + "*"));
    qDebug() << ("data/" + paths.first()).toStdString();

    if(!paths.empty()) {
        db_.InitDatabase(("data/" + paths.first()).toStdString());
        int indb = db_.CountRows();
        qInfo("%s:%i: %s%d", __FILE__, __LINE__, "Файлов в обновлении: ", indb);
        int percent = -1;

        for (int i = 0; i <= indb; i++) {
            if (i * 100 / indb > percent) {
                percent = i * 100 / indb;
                qInfo("%s:%i: %s%d%s", __FILE__, __LINE__, "Применение обновления: ", percent, "%");
                emit updatedPatchPercent(percent);
            }
            processFile();
         }

        AConfig::getInstance()->setValue("Applied", name, paths.first());
        db_.CloseDatabase();
    }

    emit applyPatchFinished(0);
}

void GameRes::setGameLocale(QString locale) {
    openDatFile(0);
    locale_ = app->datfiles[0].current_locale();

    if(locale_ == PATCHED) qDebug() << "Starting " + locale + " version. Current locale is PATCHED";
    if(locale_ == ORIGINAL) qDebug() << "Starting " + locale + " version. Current locale is ORIGINAL";
    if(locale_ != ORIGINAL && loc != PATCHED) qDebug() << "Starting " + locale + " version. Current locale is UNKNOWN";

    if(locale == "RU" && loc != PATCHED) {qDebug()<< "Current locale Original"; app->datfiles[0].SetLocale(PATCHED); dat_locale = PATCHED;}
    if(locale == "Original" && loc != ORIGINAL) {qDebug()<< "Current locale RU"; app->datfiles[0].SetLocale(ORIGINAL); dat_locale = ORIGINAL;}
    closeDatFile(0);
    emit setGameLocaleFinished(0);
}

void GameRes::startGame() {
    AConfig::getInstance()->saveAllDatFiles();

    QStringList args;
    args << "-skiprawdownload" << "-nosplash";
    if (locale_ == PATCHED)
        args << "-disablePatch";

    QFile f(app->config->getValue("Local", "folder") + "/TurbineLauncher.exe");
    QProcess process;
    if(fileExists(f.fileName())){
        if (f.fileName().contains(" "))
            f.setFileName("\"" + f.fileName() + "\"");

        process.startDetached(f.fileName(), args);
        process.waitForFinished(-1);
        process.deleteLater();
        QApplication::quit();
        emit startGameFinished(0);
    } else {
        //QString text = "Запуск не удался";
        //QString info = "Не удалось запустить игру. Во время запуска произшла непредвиденная ошибка (возможно, не найден файл TurbineLauncher.exe в папке с игрой. Проверьте в 'Настройках', что у вас указан верный путь к игре, и повторите попытку запуска).";
        //app->helper->myDialogBox(text, info, "OK", "Отмена", "gandalf.png", "", "", 400, 160, true, false);
        emit startGameFinished(-100);
    }
}

void GameRes::installMicroPatch() {
    prepareMicroPatch();
    applyMicroPatch();
    QDir dir("/data/micro");
    FileSystem::clearFolder(dir);
    emit installMicroPatchFinished(0);
}

void GameRes::applyAll() {
    // Применяем патч с заставочными экранами
    if(AConfig::getInstance()->getValue("Editor", "screens") == "true") {
        applyLoadscreens();
    }

    // Применяем остальные патчи
    QStringList names;
    names << "fonts" << "sounds" << "texts" << "images" << "videos" << "textures";

    QDir dir(QApplication::applicationDirPath() + "/data");
    QStringList need;

    foreach(QString name, names){
        QStringList list = dir.entryList(QStringList(name + "*"));
        if(list.size() > 0 && list.first() != ""){
            QString isset = app->config->getValue("Applied", name);
            if(list.first() != isset && app->config->getValue("Editor", name) == "true") {
                need.append(name);
            }
        }
    }

    if(need.size() > 0){
        openDatFile(0);
        foreach(QString name, need) {
            applyPatch(name);
        }
    }

    if(app->config->getValue("Updates", "micro") == "true")
        installMicroPatch();

    emit applyAllFinished(0);
}

void GameRes::checkDatFile() {
    openDatFile(0);
    if(datfiles_[0].CheckIfUpdatedByGame()){
        emit checkDatFileFinished(1);
        return;
    }

    if(datfiles_[0].CheckIfNotPatched() && AConfig::getInstance()->getValue("Local", "runfirst") == "1"){
        emit checkDatFileFinished(2);
        return;
    }

    if(datfiles_[0].CheckIfPatchedByOldLauncher()){
        emit checkDatFileFinished(3);
        return;
    }
}

// Private functions

void GameRes::processFile() {
    SubfileData subfile;
    subfile = app->db->GetNextFile();
    if (subfile.Empty()){
        qInfo("%s:%i: %s", __FILE__, __LINE__, "Достигнут конец файла.");
    } else {
        int dat_id = subfile.options["did"].as<int>();
        int dat_state = datfiles_[dat_id].InitDatFile(AConfig::getInstance()->getDatPath(dat_id), dat_id);
        if(dat_state > 0)
            datfiles_[dat_id].PatchFile(subfile);
    }
}

void GameRes::prepareMicroPatch() {
    QString date = AConfig::getInstance()->getValue("Updates", "update");

    if(date == "false")
        date = QDate::currentDate().toString("yyyy-MM-dd");

    QTime time = QTime::currentTime();
    int seconds = QTime(0, 0, 0).secsTo(time);
    int timestamp = app->helper->dateToTimestamp(date + " " + time.toString("hh:mm:ss"), "yyyy-MM-dd hh:mm:ss") - 2592000;

    qInfo("%s:%i: %s", __FILE__, __LINE__, "Опция активна. Начинаем загрузку обновлений");
    app->network->micropatch = QApplication::applicationDirPath() + "/data/micro/" + QString::number(timestamp + seconds) + ".db";

    if(!app->helper->fileExists(app->network->micropatch)){
        qInfo("%s:%i: %s%s", __FILE__, __LINE__, "Файл патча: ", app->helper->stringToChar(app->network->micropatch));
        app->network->micropatch = app->network->getMicroPath(timestamp);
    }
    qInfo("%s:%i: %s", __FILE__, __LINE__, "Выполнено.");
}

void GameRes::applyMicroPatch() {
    emit startedPatching(" новые переводы");

    db_.InitDatabase(app->helper->stringToChar(app->network->micropatch));
    qInfo("%s:%i: %s%d", __FILE__, __LINE__, "Файлов в обновлении: ", indb);
    int indb = app->db->CountRows();
    int percent = -1;

    for(int i = 0; i <= indb; i++) {
        if (i * 100 / indb > percent) {
            percent = i * 100 / indb;
            qInfo("%s:%i: %s%d%s", __FILE__, __LINE__, "Применение обновления: ", percent, "%");
            emit updatedPatchPercent(percent);
        }
        processFile();
    }

    db_.CloseDatabase();
    qInfo("%s:%i: %s", __FILE__, __LINE__, "Выполнено.");
}

void GameRes::applyLoadscreens() {
    QString datafolder = QApplication::applicationDirPath() + "/data";
    QDir dir(datafolder);
    if (!dir.exists())
        return;

    QStringList paths = dir.entryList(QStringList("loadscreens*"));

    if(!paths.empty()){
        if(paths.first() == AConfig::getInstance()->getValue("Applied", "screens")){
            return;
        }

        QString lang = AConfig::getInstance()->getValue("Local", "lang");
        QString folder = AConfig::getInstance()->getValue("Local", "folder") + "/raw/" + lang + "/logo/";
        SubfileData subfile;
        QStringList filenames;
        QString mainscreen = (lang == "en" ? "lotro_ad_pregame.jpg" : "lotro_ad_pregame_" + lang + ".jpg");
        filenames << mainscreen << "lotro_generic_teleport_screen_01.jpg" << "lotro_generic_teleport_screen_02.jpg"
                  << "lotro_generic_teleport_screen_03.jpg" << "lotro_generic_teleport_screen_04.jpg" << "lotro_generic_teleport_screen_05.jpg"
                  << "lotro_generic_teleport_screen_06.jpg" << "lotro_generic_teleport_screen_07.jpg" << "lotro_generic_teleport_screen_08.jpg"
                  << "lotro_generic_teleport_screen_09.jpg" << "lotro_generic_teleport_screen_10.jpg";

        QString basename = datafolder + "/" + paths.first();
        db_.InitDatabase(basename.toStdString());
        int indb = db_.CountRows();
        qInfo("%s:%i: %s%d", __FILE__, __LINE__, "Файлы загрузочных экранов: ", indb);

        for (int i = 0; i < indb; i++) {
            subfile = db_.GetNextFile();
            qDebug() << i;
            if (!subfile.Empty()){
                qInfo("%s:%i: %s", __FILE__, __LINE__, (folder + filenames[i]).toStdString().c_str());
                QFile::remove(folder + filenames[i]);
                subfile.binary_data.WriteToFile((folder + filenames[i]).toStdString());
            }
        }
        db_.CloseDatabase();
    }
    qInfo("%s:%i: %s", __FILE__, __LINE__, "Выполнено.");
}

bool GameRes::isDatReady() { // Checks if file is ready to write data
    bool free = false;
    QString dir = AConfig::getInstance()->getValue("Local", "folder");
    QString file = AConfig::getInstance()->getValue("Local", "file");
    QFile fl(dir+"/" + file);
    qDebug() << fl.fileName();

    if(FileSystem::fileExists(fl.fileName())){
        QDir game_dir(dir);
        free = game_dir.rename(fl.fileName(), fl.fileName() + "99");
        game_dir.rename(fl.fileName() + "99", fl.fileName());
    } else {
        free = false;
    }

    if (free == true)
        qDebug() << "Dat is FREE"; else qDebug() << "Dat is BUSY";

    return free;
}
