#include "document_class.h"
#include "latex_util.h"
#include "machine.h"
#include "show.h"
#include "log.h"

// extern "C" is needed for dlsym name lookup. Returning std::string from
// C-linkage functions is technically non-standard but works correctly on
// Linux (Itanium ABI) where C and C++ calling conventions are identical.
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
#endif

extern "C"
std::string document(Machine& machine)
{
    (void)K::log(3);
    try {
        Document_class D(machine);
        return D.result();
    }
    catch (Error& err) {
        err.print_message();
        std::cout << "\n";
        exit(1);
    }
}

extern "C"
std::string tex_to_pdf(Machine& machine)
{
    (void)K::log(3);
    try {
        check_for_xelatex();
        std::string outbase = machine.m_state.value("K_output_dir")
            + "/" + machine.m_state.value("K_output_basename");
        std::string tex_filename = outbase + ".tex";
        for (auto ext : {"aux", "log", "out", "toc"}) {
            fs::remove(outbase + "." + ext);
        }
        std::string command = "xelatex -interaction=batchmode -halt-on-error " + tex_filename;
        string_to_file(tex_filename, machine.m_result);
        std::string xelatex_output = exec(command.c_str());
        std::string xelatex_log = string_from_file(outbase + ".log");
        std::vector<std::string> error_lines = find_latex_error_lines(xelatex_log);
        if (!error_lines.empty()) {
            std::stringstream ss {};
            ss << "Errors reported in xelatex log file:\n";
            for (auto line : error_lines) {
                ss << "  " << line << "\n";
            }
            ss << "Check log file: " << outbase << ".log";
            throw Definition_error(ss.str(), Locator(), false);
        }
        if (std::regex_search(xelatex_log, std::regex("Package rerunfilecheck Warning:"))) {
            (void)K::log(1, "Rerunning xelatex because document structure has changed");
            xelatex_output = exec(command.c_str());
            xelatex_log = string_from_file(outbase + ".log");
            error_lines = find_latex_error_lines(xelatex_log);
            if (!error_lines.empty()) {
                std::stringstream ss {};
                ss << "Errors reported in xelatex log file:\n";
                for (auto line : error_lines) {
                    ss << "  " << line << "\n";
                }
                ss << "Check log file: " << outbase << ".log";
                throw Definition_error(ss.str(), Locator(), false);
            }
        }
        /*
        if (std::stoi(machine.m_state.value("K_verbose_level")) < 2) {
            for (auto ext : word_split("tex out aux log toc")) {
                fs::remove(outbase + "." + ext);
            }
        }
        */
        return "";
    }
    catch (Error& err) {
        std::cout << red;
        err.print_message();
        std::cout << black << "\n";
        exit(1);
    }
}

