#include <language/modules/MathModule.hpp>

#include <language/utils/BuiltinFunctionEmbedder.hpp>

MathModule::MathModule()
{
  this->_addBuiltinFunction("sqrt", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
                                      [](double x) -> double { return std::sqrt(x); }));

  this->_addBuiltinFunction("abs", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
                                     [](double x) -> double { return std::abs(x); }));

  this->_addBuiltinFunction("sin", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
                                     [](double x) -> double { return std::sin(x); }));

  this->_addBuiltinFunction("cos", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
                                     [](double x) -> double { return std::cos(x); }));

  this->_addBuiltinFunction("tan", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
                                     [](double x) -> double { return std::tan(x); }));

  this->_addBuiltinFunction("asin", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
                                      [](double x) -> double { return std::asin(x); }));

  this->_addBuiltinFunction("acos", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
                                      [](double x) -> double { return std::acos(x); }));

  this->_addBuiltinFunction("atan", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
                                      [](double x) -> double { return std::atan(x); }));

  this->_addBuiltinFunction("atan2", std::make_shared<BuiltinFunctionEmbedder<double(double, double)>>(
                                       [](double x, double y) -> double { return std::atan2(x, y); }));

  this->_addBuiltinFunction("sinh", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
                                      [](double x) -> double { return std::sinh(x); }));

  this->_addBuiltinFunction("cosh", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
                                      [](double x) -> double { return std::cosh(x); }));

  this->_addBuiltinFunction("tanh", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
                                      [](double x) -> double { return std::tanh(x); }));

  this->_addBuiltinFunction("asinh", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
                                       [](double x) -> double { return std::asinh(x); }));

  this->_addBuiltinFunction("acosh", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
                                       [](double x) -> double { return std::acosh(x); }));

  this->_addBuiltinFunction("atanh", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
                                       [](double x) -> double { return std::atanh(x); }));

  this->_addBuiltinFunction("exp", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
                                     [](double x) -> double { return std::exp(x); }));

  this->_addBuiltinFunction("log", std::make_shared<BuiltinFunctionEmbedder<double(double)>>(
                                     [](double x) -> double { return std::log(x); }));

  this->_addBuiltinFunction("pow", std::make_shared<BuiltinFunctionEmbedder<double(double, double)>>(
                                     [](double x, double y) -> double { return std::pow(x, y); }));

  this->_addBuiltinFunction("ceil", std::make_shared<BuiltinFunctionEmbedder<int64_t(double)>>(
                                      [](double x) -> int64_t { return std::ceil(x); }));

  this->_addBuiltinFunction("floor", std::make_shared<BuiltinFunctionEmbedder<int64_t(double)>>(
                                       [](double x) -> int64_t { return std::floor(x); }));

  this->_addBuiltinFunction("trunc", std::make_shared<BuiltinFunctionEmbedder<int64_t(double)>>(
                                       [](double x) -> int64_t { return std::trunc(x); }));

  this->_addBuiltinFunction("round", std::make_shared<BuiltinFunctionEmbedder<int64_t(double)>>(
                                       [](double x) -> int64_t { return std::lround(x); }));

  this->_addBuiltinFunction("min", std::make_shared<BuiltinFunctionEmbedder<double(double, double)>>(
                                     [](double x, double y) -> double { return std::min(x, y); }));

  this->_addBuiltinFunction("min", std::make_shared<BuiltinFunctionEmbedder<int64_t(int64_t, int64_t)>>(
                                     [](int64_t x, int64_t y) -> int64_t { return std::min(x, y); }));

  this->_addBuiltinFunction("max", std::make_shared<BuiltinFunctionEmbedder<double(double, double)>>(
                                     [](double x, double y) -> double { return std::max(x, y); }));

  this->_addBuiltinFunction("max", std::make_shared<BuiltinFunctionEmbedder<int64_t(int64_t, int64_t)>>(
                                     [](int64_t x, int64_t y) -> int64_t { return std::max(x, y); }));

  this->_addBuiltinFunction("dot",
                            std::make_shared<BuiltinFunctionEmbedder<double(const TinyVector<1>, const TinyVector<1>)>>(
                              [](const TinyVector<1> x, const TinyVector<1> y) -> double { return dot(x, y); }));

  this->_addBuiltinFunction("dot",
                            std::make_shared<BuiltinFunctionEmbedder<double(const TinyVector<2>, const TinyVector<2>)>>(
                              [](const TinyVector<2> x, const TinyVector<2> y) -> double { return dot(x, y); }));

  this
    ->_addBuiltinFunction("dot",
                          std::make_shared<BuiltinFunctionEmbedder<double(const TinyVector<3>&, const TinyVector<3>&)>>(
                            [](const TinyVector<3>& x, const TinyVector<3>& y) -> double { return dot(x, y); }));
}

void
MathModule::registerOperators() const
{}