

#ifndef DKUTIL_DETAIL_BUFFERED_SERIALIZE_HPP
#define DKUTIL_DETAIL_BUFFERED_SERIALIZE_HPP

#include <dkutil/macro.hpp>
#include <dkutil/config.hpp>
#include <dkutil/shared_buffer.hpp>
#include <dkutil/detail/serialize_interface.hpp>

namespace dkutil{

template<size_t InnerBufferSize = 1024 * 64>
class CBufferedSeiralizeStreamBase : public ISerializeStream{
public:
	BOOST_STATIC_CONSTANT(size_t,inner_buffer_size = InnerBufferSize);
	typedef typename CBufferedSeiralizeStreamBase<InnerBufferSize> self_type;
protected:
	DKC_BUFFER *mIB;
public:
	/*CBufferedSeiralizeStreamBase(size_t ibs = inner_buffer_size)
	{
		reserve(ibs);
	}*/
	CBufferedSeiralizeStreamBase(bool is_LittleEndian,size_t ibs = inner_buffer_size) :
		ISerializeStream(is_LittleEndian,ibs)
		{
			mIB = NULL;	
			reserve(ibs);
		}
	
	void clear(){
		dkcFreeBuffer(&mIB);
	}
		///内部メモリバッファのサイズを取得、変更する
	bool reserve(size_t ibs){
		clear();
		mIB = dkcAllocBuffer(NULL,ibs);
		if(NULL==mIB) return false;
		if(0==ibs){
			ibs = inner_buffer_size;
		}
		if(ibs & 64){//64byteで割り切れなかったら。
			ibs += (ibs & 64);
		}
		return dkcBufferResize(mIB,ibs);
	}

	
	template<class SELF_T,typename POD_T>
	struct buffered_serialize{
		
		void operator()(SELF_T *tp,DKC_BUFFER *px,POD_T *src,size_t num){
			reverse_endian refa;
			POD_T *pt = (POD_T *)px->mBuff;
			size_t byte_size = sizeof(POD_T) * num;
			if(x.size() > byte_size)
			{
				if(tp->is_read_mode())
				{
					if(tp->isSwap())
					{
						tp->store(pt,byte_size);
						refa(src,pt,num);
					}else{
						tp->store(src,byte_size);
					}
				}
				else
				{
					if(tp->isSwap())
					{
						refa(pt,src,num);
						tp->store(pt,byte_size);
					}else{
						tp->store(src,byte_size);
					}
				}
				return;
			}
			//分割
			size_t div_num = px->mSize / sizeof(POD_T);
			size_t loop = byte_size / px->mSize;
			size_t rest = byte_size % px->mSize;
			dkcmASSERT(rest == 0);
			size_t offset = 0,i;

			for(i=0;i<loop;i++)
			{
				if(tp->is_read_mode())
				{
					if(tp->isSwap())
					{
						tp->store(pt,px->mSize);
						refa(&src[offset],pt,div_num);
					}else{
						tp->store(&src[offset],px->mSize);
					}
				}
				else
				{
					if(tp->isSwap())
					{
						refa(pt,&src[offset],div_num);
						tp->store(pt,px->mSize);
					}else{
						tp->store(&src[offset],px->mSize);
					}
				}
				offset += div_num;
			}//eo for

		}
		friend SELF_T;
	};
	friend buffered_serialize<self_type,uint16>;
	friend buffered_serialize<self_type,uint32>;
	friend buffered_serialize<self_type,uint64>;

	virtual void serialize16(void *pd,size_t num)
	{
		buffered_serialize<self_type,uint16> bs;
		bs(this,mIB,pd,num);


	}
	virtual void serialize32(void *,size_t num)	{
		buffered_serialize<self_type,uint32> bs;
		bs(this,mIB,pd,num);


	}

	virtual void serialize64(void *pd,size_t num)	{
		buffered_serialize<self_type,uint64> bs;
		bs(this,mIB,pd,num);
	}
	




};

}//end of dkutil namespace



#endif