//
// Created by Иван_Архипов on 30.10.2017.
//
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <ctime>
#include <algorithm>

#ifdef WIN32
#include <direct.h>
#define mkdir(dir, mode) _mkdir(dir)
#endif

#include "../LotroDatPatcher.h"
using namespace LOTRO_DAT;


// Change these 2 variables to your path and name of .dat file
const std::string path = "";//"E:\\SteamLibrary\\steamapps\\common\\";//Lord Of The Rings Online\\";
const std::string filename = "client_local_English.dat";

// Change these variables to true if you want export catecory to files.
const bool exportImagesToFiles = false;
const bool exportFontsToFiles = false;
const bool exportSoundsToFiles = false;
const bool exportTexturesToFiles = false;
const bool exportUnknownToFiles = false;

// Change these variables to true if you want export catecory to databases.
const bool exportTextsToDb = true;
const bool exportImagesToDb = true;
const bool exportFontsToDb = true;
const bool exportSoundsToDb = true;
const bool exportTexturesToDb = true;
const bool exportUnknownToDb = false;
// There is no need to change anything else

int main() {

    const clock_t begin_time = clock();

    mkdir("Extracted data", 744);

    std::time_t result = std::time(nullptr);
    char *ttime = std::asctime(std::localtime(&result));
    auto *out_time = new char[25];
    memcpy(out_time, ttime, 24);
    out_time[24] = '\0';

    std::string output_dir = std::string("Extracted data\\") + filename + " " + std::string(out_time) + "\\";
    std::replace(output_dir.begin(), output_dir.end(), ':', '-');

    mkdir(output_dir.c_str(), 744);
    freopen((output_dir + std::string("errors.log")).c_str(), "w", stderr);
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
    setvbuf (stdout, NULL, _IONBF, BUFSIZ);
    setvbuf (stderr, NULL, _IONBF, BUFSIZ);
    try {
        std::cout << "Starting search...\n" << std::flush;
        DatFile a((path + filename).c_str(), 0);
        std::cout << "Total files found: " << a.files_number() << std::endl << std::flush;
        a.WriteUnorderedDictionary(output_dir);
        std::cout << "Beginning unpacking... Please, wait for some minutes."
        "\nMaybe it's a good idea to have a cup of tea, while unpacker is working...\n" << std::flush;

        Database *out = new Database("out.db");
        if (exportImagesToDb) {
            //Database *images = out;//new Database(output_dir + std::string("Images.db"));
            Database *images = new Database(output_dir + std::string("Images.db"));
            std::cout << "Extracted " << a.ExtractAllFilesByType(JPG, images) << " .jpg files to Images.db" << std::endl << std::flush;
            delete images;
        }

        if (exportSoundsToDb) {
//            Database *sounds = out;//new Database(output_dir + std::string("Sounds.db"));
            Database *sounds = new Database(output_dir + std::string("Sounds.db"));
            std::cout << "Extracted " << a.ExtractAllFilesByType(WAV, sounds) << " .wav files to Sounds.db" << std::endl << std::flush;
            std::cout << "Extracted " << a.ExtractAllFilesByType(OGG, sounds) << " .ogg files to Sounds.db" << std::endl << std::flush;
            delete sounds;
        }

        if (exportTextsToDb) {
//            Database *texts = out;//new Database(output_dir + std::string("Texts.db"));
            Database *texts = new Database(output_dir + std::string("Texts.db"));
            std::cout << "Extracted " << a.ExtractAllFilesByType(TEXT, texts) << " text files to Texts.db" << std::endl << std::flush;
            delete texts;
        }

        if (exportFontsToDb) {
//            Database *fonts = out;//new Database(output_dir + std::string("Fonts.db"));
            Database *fonts = new Database(output_dir + std::string("Fonts.db"));
            std::cout << "Extracted " << a.ExtractAllFilesByType(FONT, fonts) << " font files to Fonts.db" << std::endl << std::flush;
            delete fonts;
        }

        if (exportTexturesToDb) {
//            Database *textures = out;//new Database(output_dir + std::string("Textures.db"));
            Database *textures = new Database(output_dir + std::string("Textures.db"));
            std::cout << "Extracted " << a.ExtractAllFilesByType(DDS, textures) << " .dds files to Textures.db" << std::endl << std::flush;
            delete textures;
        }
        delete out;

        if (exportUnknownToDb) {
            Database *unknown = new Database(output_dir + std::string("Unknown.db"));
            std::cout << "Extracted " << a.ExtractAllFilesByType(UNKNOWN, unknown) << " unknown files to Unknown.db" << std::endl << std::flush;
        }

        if (exportImagesToFiles) {
            mkdir((output_dir + "jpg").c_str(), 744);
            std::cout << "Extracted " << a.ExtractAllFilesByType(JPG, output_dir + "jpg\\") << " .jpg files to directory" << std::endl << std::flush;
        }

        if (exportTexturesToFiles) {
            mkdir((output_dir + "dds").c_str(), 744);
            std::cout << "Extracted " << a.ExtractAllFilesByType(DDS, output_dir + "dds\\") << " .dds files to directory" << std::endl << std::flush;
        }

        if (exportSoundsToFiles) {
            mkdir((output_dir + "wav").c_str(), 744);
            std::cout << "Extracted " << a.ExtractAllFilesByType(WAV, output_dir + "wav\\") << " .wav files to directory" << std::endl << std::flush;
            mkdir((output_dir + "ogg").c_str(), 744);
            std::cout << "Extracted " << a.ExtractAllFilesByType(OGG, output_dir + "ogg\\") << " .ogg files to directory" << std::endl << std::flush;
        }

        if (exportFontsToFiles) {
            mkdir((output_dir + "fonts").c_str(), 744);
            std::cout << "Extracted " << a.ExtractAllFilesByType(FONT, output_dir + "fonts\\") << " font files to directory" << std::endl << std::flush;
        }

        if (exportUnknownToFiles) {
            mkdir((output_dir + "unknown").c_str(), 744);
            std::cout << "Extracted " << a.ExtractAllFilesByType(FONT, output_dir + "unknown\\") << " unknown files to directory" << std::endl << std::flush;
        }
    } catch (std::exception &e) {
        fprintf(stderr, "Caught %s exception.", e.what());
        printf("Some critical errors occured. Need to stop execution. See information in errors.log file\n");
        fprintf(stderr, "Some critical errors occured. Need to stop execution now...\n");
    }
    fprintf(stdout, "Spent %f seconds on running unpacker! Thank you for your patience!\n",
            float(clock() - begin_time) / CLOCKS_PER_SEC);
    system("pause");
    return 0;
}

