// =====================================================================================================================
//  fennec, a free and open source game engine
//  Copyright © 2025 - 2026  Medusa Slockbower
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================

#ifndef FENNEC_LANG_COMPARE_H
#define FENNEC_LANG_COMPARE_H

#include <fennec/lang/type_operators.h>

namespace fennec
{

// equality ============================================================================================================

///
/// \brief Struct to test equality of two values
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0> struct equality;

///
/// \brief Implementations for two types that have a common equality operator \math{=}
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1> requires has_equals_v<T0, T1>
struct equality<T0, T1> {
	///
	/// \brief operator to test the two values
	/// \param x the value of type \emph{T0}
	/// \param y the value of type \emph{T1}
	/// \returns \emph{true} if equal, \emph{false} otherwise
	constexpr bool operator()(const T0& x, const T1& y) const {
		return x == y;
	}
};

///
/// \brief Implementations for two types that have a common less operator \math{<}
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1> requires(not has_equals_v<T0, T1>
	                                        and has_less_v<T0, T1> and has_less_v<T1, T0>)
struct equality<T0, T1> {
	///
	/// \brief operator to test the two values
	/// \param x the value of type \emph{T0}
	/// \param y the value of type \emph{T1}
	/// \returns \emph{true} if equal, \emph{false} otherwise
	constexpr bool operator()(const T0& x, const T1& y) const {
		return not(x < y) and not(y < x);
	}
};

///
/// \brief Implementations for two types that have a common greater operator \math{>}
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1> requires(not(has_equals_v<T0, T1>)
	                                        and(not has_less_v<T0, T1> or not has_less_v<T1, T0>)
	                                        and(has_greater_v<T0, T1> and has_greater_v<T1, T0>))
struct equality<T0, T1> {
	///
	/// \brief operator to test the two values
	/// \param x the value of type \emph{T0}
	/// \param y the value of type \emph{T1}
	/// \returns \emph{true} if equal, \emph{false} otherwise
	constexpr bool operator()(const T0& x, const T1& y) const {
		return not(x > y) and not(y > x);
	}
};


// inequality ==========================================================================================================

///
/// \brief Struct to test inequality of two values
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0> struct inequality;

///
/// \brief Implementations for two types that have a common inequality operator \math{\neq}
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1> requires has_nequals_v<T0, T1>
struct inequality<T0, T1> {
	///
	/// \brief operator to test the two values
	/// \param x the value of type \emph{T0}
	/// \param y the value of type \emph{T1}
	/// \returns \emph{true} if not equal, \emph{false} otherwise
	constexpr bool operator()(const T0& x, const T1& y) const {
		return x != y;
	}
};


///
/// \brief Implementations for two types that have a common equality operator \math{=}
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1> requires has_equals_v<T0, T1>
struct inequality<T0, T1> {
	///
	/// \brief operator to test the two values
	/// \param x the value of type \emph{T0}
	/// \param y the value of type \emph{T1}
	/// \returns \emph{true} if not equal, \emph{false} otherwise
	constexpr bool operator()(const T0& x, const T1& y) const {
		return not (x == y);
	}
};

///
/// \brief Implementations for two types that have a common less operator \math{<}
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1> requires has_less_v<T0, T1> and has_less_v<T1, T0>
struct inequality<T0, T1> {
	///
	/// \brief operator to test the two values
	/// \param x the value of type \emph{T0}
	/// \param y the value of type \emph{T1}
	/// \returns \emph{true} if not equal, \emph{false} otherwise
	constexpr bool operator()(const T0& x, const T1& y) const {
		return (x < y) or (y < x);
	}
};

///
/// \brief Implementations for two types that have a common greater operator \math{>}
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1> requires has_greater_v<T0, T1> and has_greater_v<T1, T0>
struct inequality<T0, T1> {
	///
	/// \brief operator to test the two values
	/// \param x the value of type \emph{T0}
	/// \param y the value of type \emph{T1}
	/// \returns \emph{true} if not equal, \emph{false} otherwise
	constexpr bool operator()(const T0& x, const T1& y) const {
		return (x > y) or (y > x);
	}
};


// less ================================================================================================================

///
/// \brief Struct to test if a value of type \emph{T0} is less than a value of type \emph{T1}
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0> requires has_less_v<T0, T1>
struct less {
	///
	/// \brief operator to test the two values
	/// \param x the value of type \emph{T0}
	/// \param y the value of type \emph{T1}
	/// \returns \emph{true} if less, \emph{false} otherwise
	constexpr bool operator()(const T0& x, const T1& y) const {
		return x < y;
	}
};


// less_equal ==========================================================================================================

///
/// \brief Struct to test if a value of type \emph{T0} is less than or equal to a value of type \emph{T1}
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0> requires has_less_equals_v<T0, T1>
struct less_equals {
	///
	/// \brief operator to test the two values
	/// \param x the value of type \emph{T0}
	/// \param y the value of type \emph{T1}
	/// \returns \emph{true} if less than or equal, \emph{false} otherwise
	constexpr bool operator()(const T0& x, const T1& y) const {
		return x <= y;
	}
};


// greater =============================================================================================================

///
/// \brief Struct to test if a value of type \emph{T0} is greater than a value of type \emph{T1}
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0> requires has_greater_v<T0, T1>
struct greater {
	///
	/// \brief operator to test the two values
	/// \param x the value of type \emph{T0}
	/// \param y the value of type \emph{T1}
	/// \returns \emph{true} if greater, \emph{false} otherwise
	constexpr bool operator()(const T0& x, const T1& y) const {
		return x > y;
	}
};


// less_equal ==========================================================================================================

///
/// \brief Struct to test if a value of type \emph{T0} is greater than or equal to a value of type \emph{T1}
/// \tparam T0 The first type
/// \tparam T1 The second type
template<typename T0, typename T1 = T0> requires has_greater_equals_v<T0, T1>
struct greater_equals {
	///
	/// \brief operator to test the two values
	/// \param x the value of type \emph{T0}
	/// \param y the value of type \emph{T1}
	/// \returns \emph{true} if greater than or equal, \emph{false} otherwise
	constexpr bool operator()(const T0& x, const T1& y) const {
		return x >= y;
	}
};

}

#endif // FENNEC_LANG_COMPARE_H
