/**
@brief circuler stream

@note

*/
#ifndef DKUTIL_MEMORY_CIRCULER_STREAM_HPP
#define DKUTIL_MEMORY_CIRCULER_STREAM_HPP

#include <dkutil_c/dkc.h>
#include <dkutil/policy/allocate.hpp>
#include <dkutil/memory/interface.hpp>


namespace dkutil{

class CCirculerMemoryStream : public IMemoryStream
{
public:
	typedef size_t size_type;
	typedef CCirculerMemoryStream self_type;
protected:
	DKC_CIRCULAR_MEMORYSTREAM *mp;
public:
	CCirculerMemoryStream(size_t init_size = 1024 * 32){
		mp = NULL;
		reset(init_size);
	}
	CCirculerMemoryStream(const self_type &x)
	{
		operator=(x);
	}
	seek_arg_type limit()const{
		return mp->mSize;
	}
	self_type &operator=(const self_type &x){
		clear();
		mp = dkcAllocCircularMemoryStreamCopy(x.mp);
		if(!mp) DKUTIL_THROW_OR_NOTICE(stream_error("CMemoryStreamAdapter::operator=() error"));
		return *this;
	}
	virtual ~CCirculerMemoryStream(){
		clear();
	}
	bool reset(size_type size){
		clear();
		mp = dkcAllocCircularMemoryStream(size);
		if(!mp) return false;
		return true;
	}
	virtual bool write(const void *pd,size_t size,size_t *write_size)
	{
		
		int r = dkcCircularMemoryStreamWrite(mp,pd,size);
	
		if(DKUTIL_FAILED(r)){
			*write_size = 0;
			return false;
		}
		*write_size = size;
		return true;
	}
	virtual bool read(void *pd,size_t size,size_t *read_size)
	{
	
		int r = dkcCircularMemoryStreamRead(mp,pd,size,read_size);
		
		if(DKUTIL_FAILED(r)){
			//*read_size = 0;
			return false;
		}
		//*read_size = 0;
		return true;
	}
	virtual bool ref(void *pd,size_t size,size_t *read_size)
	{
		int r = dkcCircularMemoryStreamReference(mp,pd,size,read_size);
		
		if(DKUTIL_FAILED(r)){
			return false;
		}
		return true;
	}
	/*!
	@param offset[in] origin指定から何バイト、シークするか。
	@param origin[in] 
	@note
	動作はfseekと同じです。（爆）
	originも実はfseekと同じ指定子をぶち込んでも動いちゃったりします＾＾；
	*/
	///シークする。
	virtual bool seek(seek_arg_type offset,int origin)
	{
		if(INT_MAX < offset) return false;
		int r = dkcCirculerMemoryStreamSeek(mp,(int)offset,origin);
		return DKUTIL_SUCCEEDED_BOOL(r);
	}
	///今のバッファの最初からのオフセットを返す。
	virtual seek_arg_type tell()const{

		return dkcCirculerMemoryStreamTell(mp);
	}
	/*!
	@note
	serialize_interfaceのポインタをぶち込めば、
	シリアライズしたり、デシリアライズしたりしてくれます。
	*/
	///シリアライズする。
	//virtual bool serialize(serialize_interface *) = 0;
	///内部バッファへのポインタを頂く（無効領域を含む。危険。
	///type()での戻り値がmemory_stream_typeの時のみに御使用ください。
	virtual const void *data()const{
		return mp->mBuffer + dkcCirculerMemoryStreamTell(mp);
		}
	///内部バッファのサイズ。
	virtual size_type size()const{
		return dkcCirculerMemoryStreamSize(mp);
		}
	///内部バッファをリサイズする。
	virtual void resize(size_type size){
		
		reset(size);

	}
	///内部バッファをクリアする。
	virtual void clear(){
		
		dkcFreeCircularMemoryStream(&mp);
	}
	///ストリームのタイプを取得
	virtual int type()const
	{
		return memory_stream_type;
	}
	virtual bool eof()const{
		return size() <= tell();
	}
	virtual bool good()const{
		return NULL != mp;
	}
};


}//end of namespace




#endif