///////////////////////////////////////////////////////////////////////////////////////////////////
// OpenGL Mathematics Copyright (c) 2005 - 2008 G-Truc Creation (www.g-truc.net)
///////////////////////////////////////////////////////////////////////////////////////////////////
// Created : 2007-03-14
// Updated : 2008-11-14
// Licence : This source is under MIT License
// File    : glm/gtx/bit.inl
///////////////////////////////////////////////////////////////////////////////////////////////////

#include "../../core/_detail.h"

namespace glm{
namespace gtx{
namespace bit{

template <typename genIType>
inline genIType mask
(
	genIType const & count
)
{
	return ((genIType(1) << (count)) - genIType(1));
}

template <typename valIType>
inline detail::tvec2<valIType> mask
(
	detail::tvec2<valIType> const & count
)
{
	return detail::tvec2<valIType>(
		mask(count[0]),
		mask(count[1]));
}

template <typename valIType>
inline detail::tvec3<valIType> mask
(
	detail::tvec3<valIType> const & count
)
{
	return detail::tvec3<valIType>(
		mask(count[0]),
		mask(count[1]),
		mask(count[2]));
}

template <typename valIType>
inline detail::tvec4<valIType> mask
(
	detail::tvec4<valIType> const & count
)
{
	return detail::tvec4<valIType>(
		mask(count[0]),
		mask(count[1]),
		mask(count[2]),
		mask(count[3]));
}

// extractField
template <typename genIType>
inline genIType extractField
(
	half_float::half const & value, 
	genIType const & first, 
	genIType const & count
)
{
	assert(first + count < sizeof(half_float::half));
	return (value._data() << first) >> ((sizeof(half_float::half) << 3) - count);
}

template <typename genIType>
inline genIType extractField
(
	float const & value, 
	genIType const & first, 
	genIType const & count
)
{
	assert(first + count < sizeof(float));
	return (detail::uif32(value).i << first) >> ((sizeof(float) << 3) - count);
}

template <typename genIType>
inline genIType extractField
(
	double const & value, 
	genIType const & first, 
	genIType const & count
)
{
	assert(first + count < sizeof(double));
	return (detail::uif64(value).i << first) >> ((sizeof(double) << 3) - count);
}

template <typename genType, typename genIType>
inline genIType extractField
(
	genType const & value, 
	genIType const & first, 
	genIType const & count
)
{
	assert(first + count < sizeof(genType));
	return (value << first) >> ((sizeof(genType) << 3) - count);
}

template <typename valType, typename valIType>
inline detail::tvec2<valIType> extractField
(
	detail::tvec2<valType> const & value, 
	valIType const & first, 
	valIType const & count
)
{
	return detail::tvec2<valIType>(
		extractField(value[0], first, count),
		extractField(value[1], first, count));
}

template <typename valType, typename valIType>
inline detail::tvec3<valIType> extractField
(
	detail::tvec3<valType> const & value, 
	valIType const & first, 
	valIType const & count
)
{
	return detail::tvec3<valIType>(
		extractField(value[0], first, count),
		extractField(value[1], first, count),
		extractField(value[2], first, count));
}

template <typename valType, typename valIType>
inline detail::tvec4<valIType> extractField
(
	detail::tvec4<valType> const & value, 
	valIType const & first, 
	valIType const & count
)
{
	return detail::tvec4<valIType>(
		extractField(value[0], first, count),
		extractField(value[1], first, count),
		extractField(value[2], first, count),
		extractField(value[3], first, count));
}

template <typename valType, typename valIType>
inline detail::tvec2<valIType> extractField
(
	detail::tvec2<valType> const & value, 
	detail::tvec2<valIType> const & first, 
	detail::tvec2<valIType> const & count
)
{
	return detail::tvec2<valIType>(
		extractField(value[0], first[0], count[0]),
		extractField(value[1], first[1], count[1]));
}

template <typename valType, typename valIType>
inline detail::tvec3<valIType> extractField
(
	detail::tvec3<valType> const & value, 
	detail::tvec3<valIType> const & first, 
	detail::tvec3<valIType> const & count
)
{
	return detail::tvec3<valIType>(
		extractField(value[0], first[0], count[0]),
		extractField(value[1], first[1], count[1]),
		extractField(value[2], first[2], count[2]));
}

template <typename valType, typename valIType>
inline detail::tvec4<valIType> extractField
(
	detail::tvec4<valType> const & value, 
	detail::tvec4<valIType> const & first, 
	detail::tvec4<valIType> const & count
)
{
	return detail::tvec4<valIType>(
		extractField(value[0], first[0], count[0]),
		extractField(value[1], first[1], count[1]),
		extractField(value[2], first[2], count[2]),
		extractField(value[3], first[3], count[3]));
}

template <typename valType, typename valIType>
inline detail::tvec2<valIType> extractField
(
	valType const & value, 
	detail::tvec2<valIType> const & first, 
	detail::tvec2<valIType> const & count
)
{
	return detail::tvec2<valIType>(
		extractField(value, first[0], count[0]),
		extractField(value, first[1], count[1]));
}

template <typename valType, typename valIType>
inline detail::tvec3<valIType> extractField
(
	valType const & value, 
	detail::tvec3<valIType> const & first, 
	detail::tvec3<valIType> const & count
)
{
	return detail::tvec3<valIType>(
		extractField(value, first[0], count[0]),
		extractField(value, first[1], count[1]),
		extractField(value, first[2], count[2]));
}

template <typename valType, typename valIType>
inline detail::tvec4<valIType> extractField
(
	valType const & value, 
	detail::tvec4<valIType> const & first, 
	detail::tvec4<valIType> const & count
)
{
	return detail::tvec4<valIType>(
		extractField(value, first[0], count[0]),
		extractField(value, first[1], count[1]),
		extractField(value, first[2], count[2]),
		extractField(value, first[3], count[3]));
}

// highestBit
template <typename genType>
inline int highestBit
(
	genType const & value
)
{
	genType bit = genType(-1);
	for(genType tmp = value; tmp; tmp >>= 1, ++bit)
	{}
	return bit;
}

//template <>
//inline int highestBit<int>
//(
//	int value
//)
//{
//	int bit = -1;
//	for(int tmp = value; tmp; tmp >>= 1, ++bit);
//	return bit;
//}

template <typename valType>
inline detail::tvec2<int> highestBit
(
	detail::tvec2<valType> const & value
)
{
	return detail::tvec2<int>(
		highestBit(value[0]),
		highestBit(value[1]));
}

template <typename valType>
inline detail::tvec3<int> highestBit
(
	detail::tvec3<valType> const & value
)
{
	return detail::tvec3<int>(
		highestBit(value[0]),
		highestBit(value[1]),
		highestBit(value[2]));
}

template <typename valType>
inline detail::tvec4<int> highestBit
(
	detail::tvec4<valType> const & value
)
{
	return detail::tvec4<int>(
		highestBit(value[0]),
		highestBit(value[1]),
		highestBit(value[2]),
		highestBit(value[3]));
}

// highestBitValue
template <typename genType>
inline genType highestBitValue
(
	genType const & value
)
{
	genType tmp = value;
	genType result = genType(0);
	while(tmp)
	{
		result = (tmp & (~tmp + 1)); // grab lowest bit
		tmp &= ~result; // clear lowest bit
	}
	return result;
}

template <typename valType>
inline detail::tvec2<int> highestBitValue
(
	detail::tvec2<valType> const & value
)
{
	return detail::tvec2<int>(
		highestBitValue(value[0]),
		highestBitValue(value[1]));
}

template <typename valType>
inline detail::tvec3<int> highestBitValue
(
	detail::tvec3<valType> const & value
)
{
	return detail::tvec3<int>(
		highestBitValue(value[0]),
		highestBitValue(value[1]),
		highestBitValue(value[2]));
}

template <typename valType>
inline detail::tvec4<int> highestBitValue
(
	detail::tvec4<valType> const & value
)
{
	return detail::tvec4<int>(
		highestBitValue(value[0]),
		highestBitValue(value[1]),
		highestBitValue(value[2]),
		highestBitValue(value[3]));
}

// isPowerOfTwo
template <typename genType>
inline bool isPowerOfTwo(genType value)
{
	//detail::If<std::numeric_limits<genType>::is_signed>::apply(abs, value);
	//return !(value & (value - 1));

    // For old complier?
	if(std::numeric_limits<genType>::is_signed)
		value = abs(value);
	return !(value & (value - 1));
}

template <typename valType>
inline detail::tvec2<bool> isPowerOfTwo
(
	detail::tvec2<valType> const & value
)
{
	return detail::tvec2<bool>(
		isPowerOfTwo(value[0]),
		isPowerOfTwo(value[1]));
}

template <typename valType>
inline detail::tvec3<bool> isPowerOfTwo
(
	detail::tvec3<valType> const & value
)
{
	return detail::tvec3<bool>(
		isPowerOfTwo(value[0]),
		isPowerOfTwo(value[1]),
		isPowerOfTwo(value[2]));
}

template <typename valType>
inline detail::tvec4<bool> isPowerOfTwo
(
	detail::tvec4<valType> const & value
)
{
	return detail::tvec4<bool>(
		isPowerOfTwo(value[0]),
		isPowerOfTwo(value[1]),
		isPowerOfTwo(value[2]),
		isPowerOfTwo(value[3]));
}

// powerOfTwoAbove
template <typename genType>
inline genType powerOfTwoAbove(genType const & value)
{
	return isPowerOfTwo(value) ? value : highestBitValue(value) << 1;
}

template <typename valType>
inline detail::tvec2<valType> powerOfTwoAbove
(
	detail::tvec2<valType> const & value
)
{
	return detail::tvec2<valType>(
		powerOfTwoAbove(value[0]),
		powerOfTwoAbove(value[1]));
}

template <typename valType>
inline detail::tvec3<valType> powerOfTwoAbove
(
	detail::tvec3<valType> const & value
)
{
	return detail::tvec3<valType>(
		powerOfTwoAbove(value[0]),
		powerOfTwoAbove(value[1]),
		powerOfTwoAbove(value[2]));
}

template <typename valType>
inline detail::tvec4<valType> powerOfTwoAbove
(
	detail::tvec4<valType> const & value
)
{
	return detail::tvec4<valType>(
		powerOfTwoAboveGTX(value[0]),
		powerOfTwoAboveGTX(value[1]),
		powerOfTwoAboveGTX(value[2]),
		powerOfTwoAboveGTX(value[3]));
}

// powerOfTwoBelow
template <typename genType>
inline genType powerOfTwoBelow
(
	genType const & value
)
{
	return isPowerOfTwo(value) ? value : highestBitValue(value);
}

template <typename valType>
inline detail::tvec2<valType> powerOfTwoBelow
(
	detail::tvec2<valType> const & value
)
{
	return detail::tvec2<valType>(
		powerOfTwoBelow(value[0]),
		powerOfTwoBelow(value[1]));
}

template <typename valType>
inline detail::tvec3<valType> powerOfTwoBelow
(
	detail::tvec3<valType> const & value
)
{
	return detail::tvec3<valType>(
		powerOfTwoBelow(value[0]),
		powerOfTwoBelow(value[1]),
		powerOfTwoBelow(value[2]));
}

template <typename valType>
inline detail::tvec4<valType> powerOfTwoBelow
(
	detail::tvec4<valType> const & value
)
{
	return detail::tvec4<valType>(
		powerOfTwoBelow(value[0]),
		powerOfTwoBelow(value[1]),
		powerOfTwoBelow(value[2]),
		powerOfTwoBelow(value[3]));
}

// powerOfTwoNearest
template <typename genType>
inline genType powerOfTwoNearest
(
	genType const & value
)
{
	if(isPowerOfTwo(value))
		return value;

	genType prev = highestBitValue(value);
	genType next = prev << 1;
	return (next - value) < (value - prev) ? next : prev;
}

template <typename valType>
inline detail::tvec2<valType> powerOfTwoNearest
(
	detail::tvec2<valType> const & value
)
{
	return detail::tvec2<valType>(
		powerOfTwoNearest(value[0]),
		powerOfTwoNearest(value[1]));
}

template <typename valType>
inline detail::tvec3<valType> powerOfTwoNearest
(
	detail::tvec3<valType> const & value
)
{
	return detail::tvec3<valType>(
		powerOfTwoNearest(value[0]),
		powerOfTwoNearest(value[1]),
		powerOfTwoNearest(value[2]));
}

template <typename valType>
inline detail::tvec4<valType> powerOfTwoNearest
(
	detail::tvec4<valType> const & value
)
{
	return detail::tvec4<valType>(
		powerOfTwoNearest(value[0]),
		powerOfTwoNearest(value[1]),
		powerOfTwoNearest(value[2]),
		powerOfTwoNearest(value[3]));
}

}//namespace bit
}//namespace gtx
}//namespace glm
