//
// Created by Иван_Архипов on 31.10.2017.
//
#define NOMINMAX

#include <DatFile.h>
#include <DatOperationResult.h>
#include <EasyLogging++/easylogging++.h>

#ifdef WIN32
#define fseek _fseeki64
#define ftell _ftelli64
#endif

#define VERSION "7.0.0"

INITIALIZE_EASYLOGGINGPP

extern "C++"
{
namespace LOTRO_DAT {

    //------------------------------------------------//
    // INIT SECTION
    //------------------------------------------------//

    DatFile::DatFile() {
        el::Configurations defaultConf;
        el::Loggers::addFlag(el::LoggingFlag::LogDetailedCrashReason);
        el::Loggers::addFlag(el::LoggingFlag::ImmediateFlush);
        el::Loggers::addFlag(el::LoggingFlag::StrictLogFileSizeCheck);

        defaultConf.setToDefault();
        defaultConf.setGlobally(el::ConfigurationType::Format, "%datetime %level : %msg (function: %func)");


        defaultConf.setGlobally(el::ConfigurationType::ToFile, "true");
        defaultConf.setGlobally(el::ConfigurationType::Filename, "dat_library.log");
        defaultConf.setGlobally(el::ConfigurationType::ToStandardOutput, "false");
        defaultConf.setGlobally(el::ConfigurationType::PerformanceTracking, "true");
        defaultConf.setGlobally(el::ConfigurationType::MaxLogFileSize, "5242880"); // 5MB

        defaultConf.set(el::Level::Debug, el::ConfigurationType::Enabled, "false");
        defaultConf.set(el::Level::Debug, el::ConfigurationType::Filename, "dat_library_debug.log");

        el::Loggers::reconfigureAllLoggers(defaultConf);

        LOG(INFO) << "==================================================================";
        LOG(INFO) << "Starting new DatFile class instance";

        io_ = std::make_unique<DatIO>(this);
        fileSystem_ = std::make_unique<DatFileSystem>(this);
        localeManager_ = std::make_unique<DatLocaleManager>(this);
        exporter_ = std::make_unique<DatExporter>(this);
        patcher_ = std::make_unique<DatPatcher>(this);
//        backupManager_ = std::make_unique<DatBackupManager>(this);
    }

    LOTRO_DAT::DatLocaleManager &DatFile::getLocaleManager() {
        return *localeManager_;
    }

    DatExporter &DatFile::getExporter() {
        return *exporter_;
    }

    LOTRO_DAT::DatPatcher &DatFile::getPatcher() {
        return *patcher_;
    }

//    DatBackupManager &DatFile::getBackupManager() {
//        return *backupManager_;
//    }

    DatIO &DatFile::getIO() {
        return *io_;
    }

    DatFileSystem &DatFile::getFileSystem() {
        return *fileSystem_;
    }

    DatOperationResult<> DatFile::Initialise(const std::string &filename, long long dat_id) {
        dat_id_ = dat_id;

        if (initialized_ && io_->GetFilename().result == SUCCESS && io_->GetFilename().value == filename)
            return DatOperationResult<>();


        auto operation = io_->Init(filename);
        if (operation.result != SUCCESS)
            return DatOperationResult<>(ERROR, "DATINIT: Error, cannot initialize dat");

        operation = fileSystem_->Init();
        if (operation.result != SUCCESS)
            return DatOperationResult<>(ERROR, "DATINIT: Error, cannot initialize dat");

        operation = localeManager_->Init();
        if (operation.result != SUCCESS)
            return DatOperationResult<>(ERROR, "DATINIT: Error, cannot initialize dat");

        initialized_ = true;
        return DatOperationResult<>();
    }

    DatOperationResult<> DatFile::GatherInformation(const std::string &output_filename) {
        FILE *out = fopen(output_filename.c_str(), "w");
        if (!out)
            return DatOperationResult<>(ERROR, "GATHERDATINFO: Cannot open file " + output_filename);

        fprintf(out, "########################################################################################\n"
                     "# LOTRO Dat library version: %8s                                                  #\n"
                     "# Author: Gi1dor (e1.gildor@gmail.com)                                                 #\n"
                     "# Is part of LOTRO Legacy project (http://translate.lotros.ru/)                        #\n"
                     "# Last version is available on http://git.gi1dor.ru/LotRO_Legacy/Universal_dat_library #\n"
                     "########################################################################################\n\n\n",
                VERSION);

        io_->PrintInformaion(out);
        fileSystem_->PrintInformaion(out);
        localeManager_->PrintInformaion(out);

        fclose(out);
        return DatOperationResult<>(SUCCESS);
    }

    DatOperationResult<> DatFile::Deinitialize() {
        if (!initialized_)
            return DatOperationResult<>();

        auto operation = localeManager_->DeInit();
        if (operation.result != SUCCESS)
            return DatOperationResult<>(ERROR, "DATDEINIT: Error, cannot deinitialize. msg: " + operation.msg);

        operation = fileSystem_->DeInit();
        if (operation.result != SUCCESS)
            return DatOperationResult<>(ERROR, "DATDEINIT: Error, cannot deinitialize. msg: " + operation.msg);

        operation = io_->DeInit();
        if (operation.result != SUCCESS)
            return DatOperationResult<>(ERROR, "DATDEINIT: Error, cannot deinitialize. msg: " + operation.msg);

        initialized_ = false;

        return DatOperationResult<>();
    }


    bool DatFile::Initialized() {
        return initialized_;
    }

}
}