///////////////////////////////////////////////////////////////////////////////////////////////////
// OpenGL Mathematics Copyright (c) 2005 - 2008 G-Truc Creation (www.g-truc.net)
///////////////////////////////////////////////////////////////////////////////////////////////////
// Created : 2008-03-10
// Updated : 2008-03-15
// Licence : This source is under MIT License
// File    : gtx_associated_min_max.h
///////////////////////////////////////////////////////////////////////////////////////////////////
// Dependency:
// - GLM core
// - GLM_GTX_extented_min_max
///////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef glm_gtx_associated_min_max
#define glm_gtx_associated_min_max

// Dependency:
#include "../../glm.h"

namespace glm
{
	namespace test{
		void main_ext_gtx_associated_min_max();
	}//namespace test

	template<typename T, typename U> 
	U associatedMinGTX(
		T x, U a, 
		T y, U b);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMinGTX(
		const detail::tvec2<T>& x, const detail::tvec2<U>& a, 
		const detail::tvec2<T>& y, const detail::tvec2<U>& b);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMinGTX(
		const detail::tvec3<T>& x, const detail::tvec3<U>& a, 
		const detail::tvec3<T>& y, const detail::tvec3<U>& b);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMinGTX(
		const detail::tvec4<T>& x, const detail::tvec4<U>& a, 
		const detail::tvec4<T>& y, const detail::tvec4<U>& b);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMinGTX(
		T x, const detail::tvec2<U>& a, 
		T y, const detail::tvec2<U>& b);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMinGTX(
		T x, const detail::tvec3<U>& a, 
		T y, const detail::tvec3<U>& b);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMinGTX(
		T x, const detail::tvec4<U>& a, 
		T y, const detail::tvec4<U>& b);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMinGTX(
		const detail::tvec2<T>& x, U a, 
		const detail::tvec2<T>& y, U b);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMinGTX(
		const detail::tvec3<T>& x, U a, 
		const detail::tvec3<T>& y, U b);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMinGTX(
		const detail::tvec4<T>& x, U a, 
		const detail::tvec4<T>& y, U b);

	template<typename T, typename U> 
	U associatedMinGTX(
		T x, U a, 
		T y, U b,
		T z, U c);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMinGTX(
		const detail::tvec2<T>& x, const detail::tvec2<U>& a, 
		const detail::tvec2<T>& y, const detail::tvec2<U>& b,
		const detail::tvec2<T>& z, const detail::tvec2<U>& c);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMinGTX(
		const detail::tvec3<T>& x, const detail::tvec3<U>& a, 
		const detail::tvec3<T>& y, const detail::tvec3<U>& b,
		const detail::tvec3<T>& z, const detail::tvec3<U>& c);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMinGTX(
		const detail::tvec4<T>& x, const detail::tvec4<U>& a, 
		const detail::tvec4<T>& y, const detail::tvec4<U>& b,
		const detail::tvec4<T>& z, const detail::tvec4<U>& c);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMinGTX(
		T x, const detail::tvec2<U>& a, 
		T y, const detail::tvec2<U>& b,
		T z, const detail::tvec2<U>& c);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMinGTX(
		T x, const detail::tvec3<U>& a, 
		T y, const detail::tvec3<U>& b,
		T z, const detail::tvec3<U>& c);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMinGTX(
		T x, const detail::tvec4<U>& a, 
		T y, const detail::tvec4<U>& b,
		T z, const detail::tvec4<U>& c);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMinGTX(
		const detail::tvec2<T>& x, U a, 
		const detail::tvec2<T>& y, U b,
		const detail::tvec2<T>& z, U c);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMinGTX(
		const detail::tvec3<T>& x, U a, 
		const detail::tvec3<T>& y, U b,
		const detail::tvec3<T>& z, U c);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMinGTX(
		const detail::tvec4<T>& x, U a, 
		const detail::tvec4<T>& y, U b,
		const detail::tvec4<T>& z, U c);

	template<typename T, typename U> 
	U associatedMinGTX(
		T x, U a, 
		T y, U b,
		T z, U c,
		T w, U d);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMinGTX(
		const detail::tvec2<T>& x, const detail::tvec2<U>& a, 
		const detail::tvec2<T>& y, const detail::tvec2<U>& b,
		const detail::tvec2<T>& z, const detail::tvec2<U>& c,
		const detail::tvec2<T>& w, const detail::tvec2<U>& d);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMinGTX(
		const detail::tvec3<T>& x, const detail::tvec3<U>& a, 
		const detail::tvec3<T>& y, const detail::tvec3<U>& b,
		const detail::tvec3<T>& z, const detail::tvec3<U>& c,
		const detail::tvec3<T>& w, const detail::tvec3<U>& d);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMinGTX(
		const detail::tvec4<T>& x, const detail::tvec4<U>& a, 
		const detail::tvec4<T>& y, const detail::tvec4<U>& b,
		const detail::tvec4<T>& z, const detail::tvec4<U>& c,
		const detail::tvec4<T>& w, const detail::tvec4<U>& d);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMinGTX(
		T x, const detail::tvec2<U>& a, 
		T y, const detail::tvec2<U>& b,
		T z, const detail::tvec2<U>& c,
		T w, const detail::tvec2<U>& d);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMinGTX(
		T x, const detail::tvec3<U>& a, 
		T y, const detail::tvec3<U>& b,
		T z, const detail::tvec3<U>& c,
		T w, const detail::tvec3<U>& d);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMinGTX(
		T x, const detail::tvec4<U>& a, 
		T y, const detail::tvec4<U>& b,
		T z, const detail::tvec4<U>& c,
		T w, const detail::tvec4<U>& d);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMinGTX(
		const detail::tvec2<T>& x, U a, 
		const detail::tvec2<T>& y, U b,
		const detail::tvec2<T>& z, U c,
		const detail::tvec2<T>& w, U d);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMinGTX(
		const detail::tvec3<T>& x, U a, 
		const detail::tvec3<T>& y, U b,
		const detail::tvec3<T>& z, U c,
		const detail::tvec3<T>& w, U d);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMinGTX(
		const detail::tvec4<T>& x, U a, 
		const detail::tvec4<T>& y, U b,
		const detail::tvec4<T>& z, U c,
		const detail::tvec4<T>& w, U d);

	template<typename T, typename U> 
	U associatedMaxGTX(
		T x, U a, 
		T y, U b);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMaxGTX(
		const detail::tvec2<T>& x, const detail::tvec2<U>& a, 
		const detail::tvec2<T>& y, const detail::tvec2<U>& b);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMaxGTX(
		const detail::tvec3<T>& x, const detail::tvec3<U>& a, 
		const detail::tvec3<T>& y, const detail::tvec3<U>& b);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMaxGTX(
		const detail::tvec4<T>& x, const detail::tvec4<U>& a, 
		const detail::tvec4<T>& y, const detail::tvec4<U>& b);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMaxGTX(
		T x, const detail::tvec2<U>& a, 
		T y, const detail::tvec2<U>& b);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMaxGTX(
		T x, const detail::tvec3<U>& a, 
		T y, const detail::tvec3<U>& b);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMaxGTX(
		T x, const detail::tvec4<U>& a, 
		T y, const detail::tvec4<U>& b);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMaxGTX(
		const detail::tvec2<T>& x, U a, 
		const detail::tvec2<T>& y, U b);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMaxGTX(
		const detail::tvec3<T>& x, U a, 
		const detail::tvec3<T>& y, U b);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMaxGTX(
		const detail::tvec4<T>& x, U a, 
		const detail::tvec4<T>& y, U b);

	template<typename T, typename U> 
	U associatedMaxGTX(
		T x, U a, 
		T y, U b,
		T z, U c);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMaxGTX(
		const detail::tvec2<T>& x, const detail::tvec2<U>& a, 
		const detail::tvec2<T>& y, const detail::tvec2<U>& b,
		const detail::tvec2<T>& z, const detail::tvec2<U>& c);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMaxGTX(
		const detail::tvec3<T>& x, const detail::tvec3<U>& a, 
		const detail::tvec3<T>& y, const detail::tvec3<U>& b,
		const detail::tvec3<T>& z, const detail::tvec3<U>& c);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMaxGTX(
		const detail::tvec4<T>& x, const detail::tvec4<U>& a, 
		const detail::tvec4<T>& y, const detail::tvec4<U>& b,
		const detail::tvec4<T>& z, const detail::tvec4<U>& c);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMaxGTX(
		T x, const detail::tvec2<U>& a, 
		T y, const detail::tvec2<U>& b,
		T z, const detail::tvec2<U>& c);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMaxGTX(
		T x, const detail::tvec3<U>& a, 
		T y, const detail::tvec3<U>& b,
		T z, const detail::tvec3<U>& c);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMaxGTX(
		T x, const detail::tvec4<U>& a, 
		T y, const detail::tvec4<U>& b,
		T z, const detail::tvec4<U>& c);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMaxGTX(
		const detail::tvec2<T>& x, U a, 
		const detail::tvec2<T>& y, U b,
		const detail::tvec2<T>& z, U c);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMaxGTX(
		const detail::tvec3<T>& x, U a, 
		const detail::tvec3<T>& y, U b,
		const detail::tvec3<T>& z, U c);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMaxGTX(
		const detail::tvec4<T>& x, U a, 
		const detail::tvec4<T>& y, U b,
		const detail::tvec4<T>& z, U c);

	template<typename T, typename U> 
	U associatedMaxGTX(
		T x, U a, 
		T y, U b,
		T z, U c,
		T w, U d);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMaxGTX(
		const detail::tvec2<T>& x, const detail::tvec2<U>& a, 
		const detail::tvec2<T>& y, const detail::tvec2<U>& b,
		const detail::tvec2<T>& z, const detail::tvec2<U>& c,
		const detail::tvec2<T>& w, const detail::tvec2<U>& d);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMaxGTX(
		const detail::tvec3<T>& x, const detail::tvec3<U>& a, 
		const detail::tvec3<T>& y, const detail::tvec3<U>& b,
		const detail::tvec3<T>& z, const detail::tvec3<U>& c,
		const detail::tvec3<T>& w, const detail::tvec3<U>& d);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMaxGTX(
		const detail::tvec4<T>& x, const detail::tvec4<U>& a, 
		const detail::tvec4<T>& y, const detail::tvec4<U>& b,
		const detail::tvec4<T>& z, const detail::tvec4<U>& c,
		const detail::tvec4<T>& w, const detail::tvec4<U>& d);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMaxGTX(
		T x, const detail::tvec2<U>& a, 
		T y, const detail::tvec2<U>& b,
		T z, const detail::tvec2<U>& c,
		T w, const detail::tvec2<U>& d);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMaxGTX(
		T x, const detail::tvec3<U>& a, 
		T y, const detail::tvec3<U>& b,
		T z, const detail::tvec3<U>& c,
		T w, const detail::tvec3<U>& d);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMaxGTX(
		T x, const detail::tvec4<U>& a, 
		T y, const detail::tvec4<U>& b,
		T z, const detail::tvec4<U>& c,
		T w, const detail::tvec4<U>& d);

	template<typename T, typename U> 
	detail::tvec2<U> associatedMaxGTX(
		const detail::tvec2<T>& x, U a, 
		const detail::tvec2<T>& y, U b,
		const detail::tvec2<T>& z, U c,
		const detail::tvec2<T>& w, U d);

	template<typename T, typename U> 
	detail::tvec3<U> associatedMaxGTX(
		const detail::tvec3<T>& x, U a, 
		const detail::tvec3<T>& y, U b,
		const detail::tvec3<T>& z, U c,
		const detail::tvec3<T>& w, U d);

	template<typename T, typename U> 
	detail::tvec4<U> associatedMaxGTX(
		const detail::tvec4<T>& x, U a, 
		const detail::tvec4<T>& y, U b,
		const detail::tvec4<T>& z, U c,
		const detail::tvec4<T>& w, U d);

	namespace gtx
	{
		//! GLM_GTX_associated_min_max extension: Min and max functions that return associated values not the compared onces.
		namespace associated_min_max
		{
			//! \brief Min comparison between 2 variables
			template<typename genTypeT, typename genTypeU>
			inline genTypeU associatedMin(
				const genTypeT& x, const genTypeU& a, 
				const genTypeT& y, const genTypeU& b)
			{
				return associatedMinGTX(x, a, y, b);
			}

			//! \brief Min comparison between 3 variables
			template<typename genTypeT, typename genTypeU>
			inline genTypeU associatedMin(
				const genTypeT& x, const genTypeU& a, 
				const genTypeT& y, const genTypeU& b, 
				const genTypeT& z, const genTypeU& c)
			{
				return associatedMinGTX(x, a, y, b, z, c);
			}

			//! \brief Min comparison between 4 variables
			template<typename genTypeT, typename genTypeU>
			inline genTypeU associatedMin(
				const genTypeT& x, const genTypeU& a, 
				const genTypeT& y, const genTypeU& b, 
				const genTypeT& z, const genTypeU& c, 
				const genTypeT& w, const genTypeU& d)
			{
				return associatedMinGTX(x, a, y, b, z, c, w, d);
			}

			//! \brief Max comparison between 2 variables
			template<typename genTypeT, typename genTypeU>
			inline genTypeU associatedMax(
				const genTypeT& x, const genTypeU& a, 
				const genTypeT& y, const genTypeU& b)
			{
				return associatedMaxGTX(x, a, y, b);
			}

			//! \brief Max comparison between 3 variables
			template<typename genTypeT, typename genTypeU>
			inline genTypeU associatedMax(
				const genTypeT& x, const genTypeU& a, 
				const genTypeT& y, const genTypeU& b, 
				const genTypeT& z, const genTypeU& c)
			{
				return associatedMaxGTX(x, a, y, b, z, c);
			}

			//! \brief Max comparison between 4 variables
			template<typename genTypeT, typename genTypeU>
			inline genTypeU associatedMax(
				const genTypeT& x, const genTypeU& a, 
				const genTypeT& y, const genTypeU& b, 
				const genTypeT& z, const genTypeU& c, 
				const genTypeT& w, const genTypeU& d)
			{
				return associatedMaxGTX(x, a, y, b, z, c, w, d);
			}
		}

		bool test();
	}
}

#define GLM_GTX_associated_min_max namespace gtx::associated_min_max

#include "associated_min_max.inl"

#endif//glm_gtx_associated_min_max
