#include "doctest/parts/private/prelude.h"

DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH

namespace doctest {

Approx::Approx(double value)
    : m_epsilon(static_cast<double>(std::numeric_limits<float>::epsilon()) * 100), m_scale(1.0), m_value(value) {}

Approx Approx::operator()(double value) const {
    Approx approx(value);
    approx.epsilon(m_epsilon);
    approx.scale(m_scale);
    return approx;
}

Approx &Approx::epsilon(double newEpsilon) {
    m_epsilon = newEpsilon;
    return *this;
}
Approx &Approx::scale(double newScale) {
    m_scale = newScale;
    return *this;
}

bool operator==(double lhs, const Approx &rhs) {
    // Thanks to Richard Harris for his help refining this formula
    return std::fabs(lhs - rhs.m_value) <
           rhs.m_epsilon * (rhs.m_scale + std::max<double>(std::fabs(lhs), std::fabs(rhs.m_value)));
}

bool operator==(const Approx &lhs, double rhs) {
    return operator==(rhs, lhs);
}

bool operator!=(double lhs, const Approx &rhs) {
    return !operator==(lhs, rhs);
}

bool operator!=(const Approx &lhs, double rhs) {
    return !operator==(rhs, lhs);
}

bool operator<=(double lhs, const Approx &rhs) {
    return lhs < rhs.m_value || lhs == rhs;
}

bool operator<=(const Approx &lhs, double rhs) {
    return lhs.m_value < rhs || lhs == rhs;
}

bool operator>=(double lhs, const Approx &rhs) {
    return lhs > rhs.m_value || lhs == rhs;
}

bool operator>=(const Approx &lhs, double rhs) {
    return lhs.m_value > rhs || lhs == rhs;
}

bool operator<(double lhs, const Approx &rhs) {
    return lhs < rhs.m_value && lhs != rhs;
}

bool operator<(const Approx &lhs, double rhs) {
    return lhs.m_value < rhs && lhs != rhs;
}

bool operator>(double lhs, const Approx &rhs) {
    return lhs > rhs.m_value && lhs != rhs;
}

bool operator>(const Approx &lhs, double rhs) {
    return lhs.m_value > rhs && lhs != rhs;
}

String toString(const Approx &in) {
    return "Approx( " + doctest::toString(in.m_value) + " )";
}

} // namespace doctest

DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP
