#include <Algorithm/Registry.hpp>

#include <registry/AlgorithmRegistry.hpp>

void Registry::initialize() {
    auto& in = Registry::getInstance();

    in.algorithms.clear();

    for (const auto& group: {"automaton", "grammar", "regexp"}) {
        for (const auto& item: abstraction::AlgorithmRegistry::listGroup(group)) {
            const auto& name = item.first;
            auto algorithm = std::make_unique<Algorithm>(name);

            for (const auto& overload: abstraction::AlgorithmRegistry::listOverloads(name, item.second)) {
                std::string resultType ( std::get<0>(overload).getResult().first );

                std::vector<std::string> paramNames;
                for (const auto& param: std::get<0>(overload).getParams()) {
                    paramNames.push_back ( std::string ( std::get<0> ( param ) ) );
                }

                Algorithm::Overload _overload { resultType, paramNames };

                if (!algorithm->canAddOverload(_overload)) {
                    continue;
                }

                algorithm->addOverload(_overload);
            }

            if (algorithm->overloads.empty())
                continue;

            in.algorithms[name] = std::move(algorithm);
        }
    }
}

void Registry::deinitialize() {
    Registry::getInstance().algorithms.clear();
}

Registry& Registry::getInstance() {
    static Registry instance;
    return instance;
}

Algorithm* Registry::getAlgorithm(const std::string& name) {
    auto& in = Registry::getInstance();
    auto it = in.algorithms.find(name);
    if (it == in.algorithms.end())
        return nullptr;
    return it->second.get();
}

const std::map<std::string, std::unique_ptr<Algorithm>>& Registry::getAlgorithms() {
    return Registry::getInstance().algorithms;
}