// =====================================================================================================================
//  fennec, a free and open source game engine
//  Copyright © 2025  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 ============================================================================================================

template<typename T0, typename T1 = T0> struct equality;

template<typename T0, typename T1> requires has_equals_v<T0, T1>
struct equality<T0, T1> {
	constexpr bool operator()(const T0& x, const T1& y) const {
		return x == y;
	}
};

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> {
	constexpr bool operator()(const T0& x, const T1& y) const {
		return not(x < y) and not(y < x);
	}
};

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> {
	constexpr bool operator()(const T0& x, const T1& y) const {
		return not(x > y) and not(y > x);
	}
};


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

template<typename T0, typename T1 = T0> struct inequality;

template<typename T0, typename T1> requires has_nequals_v<T0, T1>
struct inequality<T0, T1> {
	constexpr bool operator()(const T0& x, const T1& y) const {
		return x != y;
	}
};

template<typename T0, typename T1> requires has_less_v<T0, T1> and has_less_v<T1, T0>
struct inequality<T0, T1> {
	constexpr bool operator()(const T0& x, const T1& y) const {
		return (x < y) or (y < x);
	}
};

template<typename T0, typename T1> requires has_greater_v<T0, T1> and has_greater_v<T1, T0>
struct inequality<T0, T1> {
	constexpr bool operator()(const T0& x, const T1& y) const {
		return (x > y) or (y > x);
	}
};


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

template<typename T0, typename T1 = T0> requires has_less_v<T0, T1>
struct less {
	constexpr bool operator()(const T0& x, const T1& y) const {
		return x < y;
	}
};


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

template<typename T0, typename T1 = T0> requires has_less_equals_v<T0, T1>
struct less_equals {
	constexpr bool operator()(const T0& x, const T1& y) const {
		return x <= y;
	}
};


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

template<typename T0, typename T1 = T0> requires has_greater_v<T0, T1>
struct greater {
	constexpr bool operator()(const T0& x, const T1& y) const {
		return x < y;
	}
};


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

template<typename T0, typename T1 = T0> requires has_greater_equals_v<T0, T1>
struct greater_equals {
	constexpr bool operator()(const T0& x, const T1& y) const {
		return x <= y;
	}
};

}

#endif // FENNEC_LANG_COMPARE_H
