#ifndef CoreFlagSet_included
#define CoreFlagSet_included

//=============================================================================
// Includes
//=============================================================================
#include <bitset>
#include <assert.h>

//=============================================================================
// Typedefs
//=============================================================================
typedef unsigned long UInt32;

#define CORE_FLAGS_FIFTH
#if defined(CORE_FLAGS_FIRST)

//=============================================================================
// CoreFlagSet - enum dependent, fixed max size
//=============================================================================
template <class EnumT>
class CoreFlagSet
{
	public:
		CoreFlagSet() : m_flagSet(0)						{ }
		CoreFlagSet(EnumT val) : m_flagSet(0x1 << val)		{ }
		
		CoreFlagSet& Raise(EnumT val)						{ assert(val < 32); m_flagSet |= (0x1 << val); return *this; }
		CoreFlagSet& Lower(EnumT val)						{ assert(val < 32); m_flagSet &= ~(0x1 << val); return *this; }
		bool Test(EnumT val) const							{ assert(val < 32); return (m_flagSet & (0x1 << val)) != 0; }
		
		CoreFlagSet& Merge(CoreFlagSet& rhs)				{ m_flagSet |= rhs.m_flagSet; return *this; }
		bool Any() const									{ return m_flagSet != 0; }
		bool None() const									{ return m_flagSet == 0; }
			
	private:
		UInt32 m_flagSet;
};

#elif defined(CORE_FLAGS_SECOND)

//=============================================================================
// CoreFlagSet - class dependent, fixed max size - DOESN'T WORK!
//=============================================================================
template <class DerivT>
class CoreFlagSet
{
	typedef typename DerivT::FlagEnum EnumT;

	public:
		CoreFlagSet() : m_flagSet(0)						{ }
		CoreFlagSet(EnumT val) : m_flagSet(0x1 << val)		{ }
		
		CoreFlagSet& Raise(EnumT val)						{ assert(val < 32); m_flagSet |= (0x1 << val); return *this; }
		CoreFlagSet& Lower(EnumT val)						{ assert(val < 32); m_flagSet &= ~(0x1 << val); return *this; }
		bool Test(EnumT val) const							{ assert(val < 32); return (m_flagSet & (0x1 << val)) != 0; }
		
		CoreFlagSet& Merge(CoreFlagSet& rhs)				{ m_flagSet |= rhs.m_flagSet; return *this; }
		bool Any() const									{ return m_flagSet != 0; }
		bool None() const									{ return m_flagSet == 0; }
		
	private:
		UInt32 m_flagSet;
};


#elif defined(CORE_FLAGS_THIRD)

//=============================================================================
// CoreFlagSet - enum dependent, no fixed max size
//=============================================================================
template <class EnumT, UInt32 MaxFlag>
class CoreFlagSet
{
	public:
		CoreFlagSet() 										{ }
		CoreFlagSet(EnumT val)								{ m_flagSet.set(val, true); }
															
		CoreFlagSet& Raise(EnumT val)						{ m_flagSet.set(val, true); return *this; }
		CoreFlagSet& Lower(EnumT val)						{ m_flagSet.set(val, false); return *this; }
		bool Test(EnumT val) const							{ return m_flagSet.test(val); }
																
		CoreFlagSet& Merge(CoreFlagSet& rhs)				{ m_flagSet |= rhs.m_flagSet; return *this; }
		bool Any() const									{ return m_flagSet.any(); }
		bool None() const									{ return m_flagSet.none(); }
		
	private:
		std::bitset<MaxFlag> m_flagSet;
};

#elif defined(CORE_FLAGS_FOURTH)

//=============================================================================
// CoreFlagSet - enum dependent, no fixed max size, partial template specialization -
//    Standard compliant, doesn't work under MSVC...
//=============================================================================
template <class EnumT, UInt32 MaxFlag, bool UseBitset>
class CoreFlagSetImpl
{
	public:
		CoreFlagSetImpl() : m_flagSet(0)						{ }
		CoreFlagSetImpl(EnumT val) : m_flagSet(0x1 << val)	{ }
		
		CoreFlagSetImpl& Raise(EnumT val)					{ assert(val < 32); m_flagSet |= (0x1 << val); return *this; }
		CoreFlagSetImpl& Lower(EnumT val)					{ assert(val < 32); m_flagSet &= ~(0x1 << val); return *this; }
		bool Test(EnumT val) const							{ assert(val < 32); return (m_flagSet & (0x1 << val)) != 0; }
		
		CoreFlagSetImpl& Merge(CoreFlagSetImpl& rhs)		{ m_flagSet |= rhs.m_flagSet; return *this; }
		bool Any() const									{ return m_flagSet != 0; }
		bool None() const									{ return m_flagSet == 0; }
			
	private:
		UInt32 m_flagSet;
};

template <class EnumT, UInt32 MaxFlag>
class CoreFlagSetImpl<EnumT, MaxFlag, true>
{
	public:
		CoreFlagSetImpl() 									{ }
		CoreFlagSetImpl(EnumT val)							{ m_flagSet.set(val, true); }
															
		CoreFlagSetImpl& Raise(EnumT val)					{ m_flagSet.set(val, true); return *this; }
		CoreFlagSetImpl& Lower(EnumT val)					{ m_flagSet.set(val, false); return *this; }
		bool Test(EnumT val) const							{ return m_flagSet.test(val); }
																
		CoreFlagSetImpl& Merge(CoreFlagSetImpl& rhs)		{ m_flagSet |= rhs.m_flagSet; return *this; }
		bool Any() const									{ return m_flagSet.any(); }
		bool None() const									{ return m_flagSet.none(); }
		
	private:
		std::bitset<MaxFlag> m_flagSet;
};

template <class EnumT, UInt32 MaxFlag>
class CoreFlagSet : public CoreFlagSetImpl<EnumT, MaxFlag, (MaxFlag > 32)>
{
	public:
		CoreFlagSet() 										{ }
		CoreFlagSet(EnumT val) : CoreFlagSetImpl<EnumT, MaxFlag, (MaxFlag <= 32)>(val)		{ }
};

#elif defined(CORE_FLAGS_FIFTH)

//=============================================================================
// CoreFlagSet - enum dependent, no fixed max size, partial template specialization workaround -
//    May or may not be standard compliant, works under MSVC, Codewarrior, Borland
//=============================================================================
template <class EnumT, UInt32 MaxFlag>
struct CoreFlagSetWrapper
{
	template <bool UseBitset>
		class Impl
	{
	public:
		Impl() : m_flagSet(0)						{ }
		Impl(EnumT val) : m_flagSet(0x1 << val)		{ }
		
		Impl& Raise(EnumT val)						{ assert(val < 32); m_flagSet |= (0x1 << val); return *this; }
		Impl& Lower(EnumT val)						{ assert(val < 32); m_flagSet &= ~(0x1 << val); return *this; }
		bool Test(EnumT val) const					{ assert(val < 32); return (m_flagSet & (0x1 << val)) != 0; }
		
		Impl& Merge(Impl& rhs)						{ m_flagSet |= rhs.m_flagSet; return *this; }
		bool Any() const							{ return m_flagSet != 0; }
		bool None() const							{ return m_flagSet == 0; }
		
	private:
		UInt32 m_flagSet;
	};

	template <>
		class Impl<true>
	{
	public:
		Impl<true>() 								{ }
		Impl<true>(EnumT val)						{ m_flagSet.set(val, true); }

		Impl<true>& Raise(EnumT val)				{ m_flagSet.set(val, true); return *this; }
		Impl<true>& Lower(EnumT val)				{ m_flagSet.set(val, false); return *this; }
		bool Test(EnumT val) const					{ return m_flagSet.test(val); }
		
		Impl<true>& Merge(Impl<true>& rhs)			{ m_flagSet |= rhs.m_flagSet; return *this; }
		bool Any() const							{ return m_flagSet.any(); }
		bool None() const							{ return m_flagSet.none(); }
		
	private:
		std::bitset<MaxFlag> m_flagSet;
	};
};

template <class EnumT, UInt32 MaxFlag>
class CoreFlagSet : public CoreFlagSetWrapper<EnumT, MaxFlag>::Impl<(MaxFlag > 32)>
{
	public:
		CoreFlagSet() 										{ }
		CoreFlagSet(EnumT val) : CoreFlagSetWrapper<EnumT, MaxFlag>::Impl<(MaxFlag > 32)>(val)		{ }
};

#elif defined(CORE_FLAGS_SIXTH)

//=============================================================================
// CoreFlagSet - enum dependent, no fixed max size, partial template specialization workaround -
//    Definitely not standard compliant, doesn't work under MSVC
//=============================================================================
template <class EnumT, UInt32 MaxFlag>
struct CoreFlagSetWrapper
{
	template <bool UseBitset>
		class Impl
	{
	public:
		Impl() : m_flagSet(0)						{ }
		Impl(EnumT val) : m_flagSet(0x1 << val)		{ }
		
		Impl& Raise(EnumT val)						{ assert(val < 32); m_flagSet |= (0x1 << val); return *this; }
		Impl& Lower(EnumT val)						{ assert(val < 32); m_flagSet &= ~(0x1 << val); return *this; }
		bool Test(EnumT val) const					{ assert(val < 32); return (m_flagSet & (0x1 << val)) != 0; }
		
		Impl& Merge(Impl& rhs)						{ m_flagSet |= rhs.m_flagSet; return *this; }
		bool Any() const							{ return m_flagSet != 0; }
		bool None() const							{ return m_flagSet == 0; }
		
	private:
		UInt32 m_flagSet;
	};
};

template<class EnumT, UInt32 MaxFlag> template<>
class CoreFlagSetWrapper<EnumT, MaxFlag>::Impl<true>
{
	public:
		Impl<true>() 								{ }
		Impl<true>(EnumT val)						{ m_flagSet.set(val, true); }
		
		Impl<true>& Raise(EnumT val)				{ m_flagSet.set(val, true); return *this; }
		Impl<true>& Lower(EnumT val)				{ m_flagSet.set(val, false); return *this; }
		bool Test(EnumT val) const					{ return m_flagSet.test(val); }
		
		Impl<true>& Merge(Impl<true>& rhs)			{ m_flagSet |= rhs.m_flagSet; return *this; }
		bool Any() const							{ return m_flagSet.any(); }
		bool None() const							{ return m_flagSet.none(); }
		
	private:
		std::bitset<MaxFlag> m_flagSet;
};

template <class EnumT, UInt32 MaxFlag>
class CoreFlagSet : public CoreFlagSetWrapper<EnumT, MaxFlag>::Impl<(MaxFlag > 32)>
{
	public:
		CoreFlagSet() 										{ }
		CoreFlagSet(EnumT val) : CoreFlagSetWrapper<EnumT, MaxFlag>::Impl<(MaxFlag > 32)>(val)		{ }
};

#endif

#endif // CoreFlagSet_included