#include <language/modules/UtilsModule.hpp>

#include <language/utils/ASTDotPrinter.hpp>
#include <language/utils/ASTExecutionInfo.hpp>
#include <language/utils/ASTPrinter.hpp>
#include <language/utils/BuiltinFunctionEmbedder.hpp>
#include <language/utils/SymbolTable.hpp>

#include <fstream>

UtilsModule::UtilsModule()
{
  this->_addBuiltinFunction("getAST", std::make_shared<BuiltinFunctionEmbedder<std::string(void)>>(

                                        []() -> std::string {
                                          const auto& root_node = ASTExecutionInfo::current().rootNode();

                                          std::ostringstream os;
                                          os << ASTPrinter{root_node};

                                          return os.str();
                                        }

                                        ));

  this->_addBuiltinFunction("saveASTDot", std::make_shared<BuiltinFunctionEmbedder<void(const std::string&)>>(

                                            [](const std::string& dot_filename) -> void {
                                              const auto& root_node = ASTExecutionInfo::current().rootNode();

                                              std::ofstream fout(dot_filename);

                                              if (not fout) {
                                                std::ostringstream os;
                                                os << "could not create file '" << dot_filename << "'\n";
                                                throw NormalError(os.str());
                                              }

                                              ASTDotPrinter dot_printer{root_node};
                                              fout << dot_printer;

                                              if (not fout) {
                                                std::ostringstream os;
                                                os << "could not write AST to '" << dot_filename << "'\n";
                                                throw NormalError(os.str());
                                              }
                                            }

                                            ));

  this->_addBuiltinFunction("getFunctionAST",
                            std::make_shared<BuiltinFunctionEmbedder<std::string(const FunctionSymbolId&)>>(

                              [](const FunctionSymbolId& function_symbol_id) -> std::string {
                                auto& function_table = function_symbol_id.symbolTable().functionTable();

                                const auto& function_descriptor = function_table[function_symbol_id.id()];

                                std::ostringstream os;
                                os << function_descriptor.name() << ": domain mapping\n";
                                os << ASTPrinter(function_descriptor.domainMappingNode());
                                os << function_descriptor.name() << ": definition\n";
                                os << ASTPrinter(function_descriptor.definitionNode());

                                return os.str();
                              }

                              ));
}