/**
 * @file topic/formats/commands/FormatsManager.cpp
 * @author Christian Schenk
 * @brief Build TeX format files
 *
 * @copyright Copyright © 2002-2022 Christian Schenk
 *
 * This file is part of One MiKTeX Utility.
 *
 * One MiKTeX Utility is licensed under GNU General Public
 * License version 2 or any later version.
 */

#include <config.h>

#include <string>
#include <vector>

#include <fmt/format.h>
#include <fmt/ostream.h>

#include <miktex/Configuration/ConfigurationProvider>
#include <miktex/Core/Paths>
#include <miktex/Core/Session>
#include <miktex/Util/PathName>

#include "internal.h"

#include "FormatsManager.h"

using namespace std;

using namespace MiKTeX::Configuration;
using namespace MiKTeX::Core;
using namespace MiKTeX::Util;

using namespace OneMiKTeXUtility;

void FormatsManager::Init(ApplicationContext& ctx)
{
    this->ctx = &ctx;
}

void FormatsManager::Build(const string& formatKey)
{
    if (find(this->formatsMade.begin(), this->formatsMade.end(), formatKey) != this->formatsMade.end())
    {
        return;
    }

    auto formatInfo = this->Format(formatKey);

    this->ctx->ui->Verbose(0, fmt::format(T_("Building format '{0}' with engine '{1}'..."), formatInfo.key, formatInfo.compiler));

    string maker;

    vector<string> arguments;

    if (formatInfo.compiler == "mf")
    {
        maker = MIKTEX_MAKEBASE_EXE;
    }
    else
    {
        maker = MIKTEX_MAKEFMT_EXE;
        arguments.push_back("--engine="s + formatInfo.compiler);
    }

    arguments.push_back("--dest-name="s + formatInfo.name);

    if (!formatInfo.preloaded.empty())
    {
        if (PathName::Compare(formatInfo.preloaded, formatKey) == 0)
        {
            this->ctx->ui->FatalError(fmt::format(T_("{0}: rule recursion"), formatKey));
        }
        // RECURSION
        this->Build(formatInfo.preloaded);
        arguments.push_back("--preload="s + formatInfo.preloaded);
    }

    if (PathName(formatInfo.inputFile).HasExtension(".ini"))
    {
        arguments.push_back("--no-dump");
    }

    arguments.push_back(formatInfo.inputFile);

    for (auto a : formatInfo.arguments)
    {
        arguments.push_back("--engine-option="s + a);
    }

    this->RunMakeTeX(maker, arguments);

    this->formatsMade.push_back(formatKey);
}

void FormatsManager::RunMakeTeX(const string& makeProg, const vector<string>& arguments)
{
    PathName exe;

    if (!this->ctx->session->FindFile(makeProg, FileType::EXE, exe))
    {
        this->ctx->ui->FatalError(fmt::format(T_("{0}: not found"), Q_(makeProg)));
    }

    vector<string> xArguments{ makeProg };

    xArguments.insert(xArguments.end(), arguments.begin(), arguments.end());

    if (ctx->ui->VerbosityLevel() > 0)
    {
        xArguments.push_back("--verbose");
    }

    if (this->ctx->ui->BeingQuiet())
    {
        xArguments.push_back("--quiet");
    }

    if (this->ctx->session->IsAdminMode())
    {
        xArguments.push_back("--admin");
    }

    if (this->ctx->installer->IsInstallerEnabled())
    {
        xArguments.push_back("--enable-installer");
    }
    else if (this->ctx->installer->IsInstallerDisabled())
    {
        xArguments.push_back("--disable-installer");
    }

    xArguments.push_back("--miktex-disable-maintenance");
    xArguments.push_back("--miktex-disable-diagnose");

    this->ctx->processRunner->RunProcess(exe, xArguments);
}

vector<FormatInfo> FormatsManager::Formats()
{
    return this->ctx->session->GetFormats();
}

FormatInfo FormatsManager::Format(const string& formatKey)
{
    FormatInfo formatInfo;
    if (!this->ctx->session->TryGetFormatInfo(formatKey, formatInfo))
    {
        this->ctx->ui->FatalError(fmt::format(T_("{0}: unknown format"), Q_(formatKey)));
    }
    return formatInfo;
}
