
#ifndef DKUTIL_FLAG_HPP
#define DKUTIL_FLAG_HPP


#include <dkutil/macro.hpp>
#include <dkutil/bit.hpp>
#include <dkutil/scoped_buffer.hpp>

namespace dkutil{




#define DKUTIL_FLAGMANAGER_UP
#define DKUTIL_FLAGMANAGER_DOWN


/*!
@todo 
- x / element_offsetとなっている所は >> 4でもOKな筈が｡｡｡あれ？違ったっけ？
- それから、バグチェックやっていない･･･get_size_type_value合っているっけ？
*/
class FlagManager{
public:
	typedef size_t size_type;
	//BOOST_STATIC_CONSTANT(int,compare_bit_mask = 32);
	BOOST_STATIC_CONSTANT(UINT,element_offset = 8);
	BOOST_STATIC_CONSTANT(UINT,bit_mask = 8);
private:
	UINT size_type_size;
	size_type mSize;
	scoped_buffer_byte mBuffer;
	inline BYTE calc_bit_offset(size_type index)const{
#	if 1
		BYTE t = index % bit_mask;
		return (1 << t);
#	else
		BYTE t = index & bit_mask;
		return (1 << (t));
#	endif
	}
	size_type get_size_type_value(size_type index)const{
		size_type *s = (size_type *)mBuffer.get();
		size_type offset = index / (element_offset * sizeof(size_type));
		return s[offset];
	}
public:
	FlagManager(size_type byte_size = 50){

		resize(byte_size);
	}
	void resize(size_type byte_size){
		std::numeric_limits<scoped_buffer_byte::size_type> lim;
		
		size_type t = lim.max();
		size_type_size = t;

		if(t / element_offset < byte_size)
		{
			DKUTIL_THROW_OR_NOTICE(
				std::invalid_argument(FlagManager constructor byte_size is too big)
			);
		}

		mBuffer.resize(byte_size);
		memset(mBuffer.get(),0,mBuffer.size());

		//if(false==mBuffer.resize(byte_size)){
			//return false;
		//}
		mSize = byte_size;
		//return true;
	}
	///@return byte単位の確保しているメモリ領域のサイズを返す
	size_type size()const{
		return mBuffer.size();
	}
	///ビット単位の確保しているメモリ領域のサイズを返す
	size_type bit_size()const{
		return size() * element_offset;
	}
	///@return bit単位のindex値からその値が入っているsize_type型の変数を返す。
	size_type at(size_type index)const{
		if(index / 8 >= mBuffer.size()){
			DKUTIL_THROW_OR_NOTICE(std::out_of_range("FlagManager at() out of range"));
			return 0;
		}
		//return referenceFlag(index);
		return get_size_type_value(index);
	}
	///@see at()
	size_type operator[](size_type x)const{
#	ifdef NDEBUG
		//referenceFlag(x);
		return get_size_type_value(x);
#	else
		return at(x);
#	endif
	}
	inline void upFlag(size_type index){
#ifdef NDEBUG
		DKUTIL_FLAG_UP(
			mBuffer[index / element_offset] ,
			 calc_bit_offset(index)
		);
#else
		BYTE offset = index / element_offset;
		BYTE t = calc_bit_offset(index);

		DKUTIL_FLAG_UP(
			mBuffer[offset],
			t
		);

#endif
	}
	inline void downFlag(size_type index){
#ifdef NDEBUG
		DKUTIL_FLAG_DOWN(
			mBuffer[index / element_offset] ,
			 calc_bit_offset(index)
		);
#else
		BYTE offset = index / element_offset;
		BYTE t = calc_bit_offset(index);

		DKUTIL_FLAG_DOWN(
			mBuffer[offset],
			t
		);

#endif
	}
	inline bool referenceFlag(size_type index)const{
		BYTE t = mBuffer[index / element_offset];
		BYTE shift = calc_bit_offset(index);
		//shift = (1 << shift);
		return (0 != (t & shift) );
	}
			
	

	
	
};


}//end of dkutil namespace



#endif