#ifndef __BITWISE_ENUMS_H__
#define __BITWISE_ENUMS_H__

#include "types.h"

template <typename Enum>
class bitwise_enum
{
	public:
		typedef uint32_t Bits;

		// CONSTRUCTORS:
		bitwise_enum(Enum init_value)
			: _value(init_value)
		{}

		bitwise_enum()
			: _value(0)
		{}

		bitwise_enum(const bitwise_enum<Enum>& other)
			: _value(other._value)
		{}

		// UNARY OPERATIONS:
		bitwise_enum<Enum> operator ~() const
		{
			return bitwise_enum<Enum>(~_value);
		}


		uint32_t value() const
		{
			return _value;
		}

		bitwise_enum<Enum>& self_revert()
		{
			_value = ~_value;
			return *this;
		}

		bitwise_enum<Enum>& clear()
		{
			_value = 0;
			return *this;
		}

		// OPERATIONS with integrals:

		uint32_t operator >> (Bits bits) const
		{
			return _value >> bits;
		}

		uint32_t operator << (Bits bits) const
		{
			return _value << bits;
		}

		// OPERATIONS BETWEEN bitwise_enums:
		bitwise_enum<Enum>& operator |= (const bitwise_enum<Enum>& other)
		{
			_value |= other._value;
			return *this;
		}

		bitwise_enum<Enum>& operator &= (const bitwise_enum<Enum>& other)
		{
			_value &= other._value;
			return *this;
		}

		bitwise_enum<Enum>& operator ^= (const bitwise_enum<Enum>& other)
		{
			_value ^= other._value;
			return *this;
		}

		bitwise_enum<Enum> operator | (const bitwise_enum<Enum>& other) const
		{
			bitwise_enum<Enum> ret(*this);
			return (ret |= other);
		}

		bitwise_enum<Enum> operator & (const bitwise_enum<Enum>& other) const
		{
			bitwise_enum<Enum> ret(*this);
			return (ret &= other);
		}

		bitwise_enum<Enum> operator ^ (const bitwise_enum<Enum>& other) const
		{
			bitwise_enum<Enum> ret(*this);
			return (ret ^= other);
		}

		bitwise_enum<Enum>& operator = (const bitwise_enum<Enum>& other)
		{
			_value = other._value;
			return *this;
		}

		bool operator == (const bitwise_enum<Enum>& other) const
		{
			return _value == other._value;
		}

		bool operator != (const bitwise_enum<Enum>& other) const
		{
			return ! operator==(other);
		}

		// utilities
		bool has_bits() const
		{
			return _value != 0;
		}

		bool has_bits(const bitwise_enum<Enum>& other) const
		{
			return (operator&(other)).has_bits();
		}

		unsigned int bits_count() const
		{
			uint32_t v(_value);
			uint32_t result(0);

			while( v>0 )
			{
				result++;
				v &= v - 1;
			}

			return result;
		}

	private:
	    uint32_t _value;
};

template <typename Enum>
inline bitwise_enum<Enum> operator | (Enum value, const bitwise_enum<Enum>& e)
{
    return e | value;
}

template <typename Enum>
inline bitwise_enum<Enum> operator & (Enum value, const bitwise_enum<Enum>& e)
{
    return e & value;
}

template <typename Enum>
inline bitwise_enum<Enum> operator ^ (Enum value, const bitwise_enum<Enum>& e)
{
    return e ^ value;
}

template <typename Enum>
inline bitwise_enum<Enum> operator | (Enum a, Enum b)
{
    return bitwise_enum<Enum>(a) | bitwise_enum<Enum>(b);
}

template <typename Enum>
inline bitwise_enum<Enum> operator & (Enum a, Enum b)
{
    return bitwise_enum<Enum>(a) & bitwise_enum<Enum>(b);
}

template <typename Enum>
inline bitwise_enum<Enum> operator ^ (Enum a, Enum b)
{
    return bitwise_enum<Enum>(a) ^ bitwise_enum<Enum>(b);
}

#endif // __BITWISE_ENUMS_H__
