#include "mathlib.h"
#include <cmath>

namespace mathlib {

/**
 * @brief Implementation of function add
 */
double add(double a, double b) {

    return a + b;
}

/**
 * @brief Implementation of function subtract
 */
double subtract(double a, double b) {

    return a - b;
}

/**
 * @brief Implementation of function multiply
 */
double multiply(double a, double b) {

    return a * b;
}

/**
 * @brief Implementation of function divide
 */
double divide(double a, double b, MathError &err) {

    if(b == 0) {
        err = DIVISION_BY_ZERO;
        return 0;
    }

    err = OK;
    return a / b;
}

/**
 * @brief Implementation of function factorial
 */
double factorial(int a, MathError &err) {

    if(a < 0 ) {
        err = NEGATIVE_FACTORIAL;
        return 0;
    }

    err = OK;

    double result = 1;
    for(int i = 1; i <= a; i++) {
        result = result * i;
    }

    return result;
}

/**
 * @brief Implementation of function power
 */
double power(double base, int exp) {

    if(exp == 0) {
        return 1;
    }

    double result = 1;

    for(int i = 0; i < exp; i++) {
        result = result * base;
    }

    return result;
}

/**
 * @brief Implementation of function root
 */
double root(double base, int n, MathError &err) {

    if(n == 0) {
        err = INVALID_ROOT;
        return 0;
    }
    if(n < 0) {
        err = INVALID_ROOT;
        return 0;
    }
    if(base < 0 && n % 2 == 0) {
        err = INVALID_ARGUMENT;
        return 0;
    }
    if(base < 0 && n % 2 != 0) {
        err = OK;
        return -std::pow(-base, 1.0 / n);
    }

    err = OK;
    return std::pow(base, 1.0 / n);
}

/**
 * @brief Implementation of function modulo
 */
double modulo(double a, double b, MathError &err) {

    if(b == 0) {
        err = DIVISION_BY_ZERO;
        return 0;
    }

    err = OK;

    return std::fmod(a, b);
}
}