#include <language/utils/BinaryOperatorRegisterForRnxn.hpp>

#include <language/utils/BinaryOperatorProcessorBuilder.hpp>
#include <language/utils/OperatorRepository.hpp>

template <size_t Dimension>
void
BinaryOperatorRegisterForRnxn<Dimension>::_register_comparisons()
{
  OperatorRepository& repository = OperatorRepository::instance();

  using Rnxn = TinyMatrix<Dimension>;

  repository.addBinaryOperator<language::eqeq_op>(
    std::make_shared<BinaryOperatorProcessorBuilder<language::eqeq_op, bool, Rnxn, Rnxn>>());

  repository.addBinaryOperator<language::not_eq_op>(
    std::make_shared<BinaryOperatorProcessorBuilder<language::not_eq_op, bool, Rnxn, Rnxn>>());
}

template <size_t Dimension>
void
BinaryOperatorRegisterForRnxn<Dimension>::_register_product_by_a_scalar()
{
  OperatorRepository& repository = OperatorRepository::instance();

  using Rnxn = TinyMatrix<Dimension>;

  repository.addBinaryOperator<language::multiply_op>(
    std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, Rnxn, bool, Rnxn>>());

  repository.addBinaryOperator<language::multiply_op>(
    std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, Rnxn, uint64_t, Rnxn>>());

  repository.addBinaryOperator<language::multiply_op>(
    std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, Rnxn, int64_t, Rnxn>>());

  repository.addBinaryOperator<language::multiply_op>(
    std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, Rnxn, double, Rnxn>>());
}

template <size_t Dimension>
void
BinaryOperatorRegisterForRnxn<Dimension>::_register_product_by_a_vector()
{
  OperatorRepository& repository = OperatorRepository::instance();

  using Rnxn = TinyMatrix<Dimension>;
  using Rn   = TinyVector<Dimension>;

  repository.addBinaryOperator<language::multiply_op>(
    std::make_shared<BinaryOperatorProcessorBuilder<language::multiply_op, Rn, Rnxn, Rn>>());
}

template <size_t Dimension>
template <typename OperatorT>
void
BinaryOperatorRegisterForRnxn<Dimension>::_register_arithmetic()
{
  OperatorRepository& repository = OperatorRepository::instance();

  using Rnxn = TinyMatrix<Dimension>;

  repository.addBinaryOperator<OperatorT>(
    std::make_shared<BinaryOperatorProcessorBuilder<OperatorT, Rnxn, Rnxn, Rnxn>>());
}

template <size_t Dimension>
BinaryOperatorRegisterForRnxn<Dimension>::BinaryOperatorRegisterForRnxn()
{
  this->_register_comparisons();

  this->_register_product_by_a_scalar();
  this->_register_product_by_a_vector();

  this->_register_arithmetic<language::plus_op>();
  this->_register_arithmetic<language::minus_op>();
  this->_register_arithmetic<language::multiply_op>();
}

template class BinaryOperatorRegisterForRnxn<1>;
template class BinaryOperatorRegisterForRnxn<2>;
template class BinaryOperatorRegisterForRnxn<3>;