
#ifndef DKUTIL_MEMORY_ADAPTERS_HPP
#define DKUTIL_MEMORY_ADAPTERS_HPP


#include <dkutil/memory/interface.hpp>

namespace dkutil{

class outer_memory_to_memorystream_adapter : 
	public memorystream_interface<policy::empty_stream_policy>
{
	unsigned char *mPtr;
	size_t mSize;
	size_t mOffset;
	bool mEOF;
	bool mError;
	BYTE *getNowPtr()const{
		return &mPtr[mOffset];
	}
	inline void check_error__()const{
		if(mOffset > mSize){
			DKUTIL_THROW_OR_NOTICE(std::runtime_error("outer_memory_to_memorystream_adapter offset length error"));
		}
	}
public:



	typedef memorystream_interface<policy::empty_stream_policy> base_type;
	typedef size_t size_type;
	typedef outer_memory_to_memorystream_adapter self_type;


	outer_memory_to_memorystream_adapter(BYTE *ptr,size_t size){
		mError = false;
		mEOF = false;
		mPtr = ptr;
		mSize = size;
		mOffset = 0;
	}

	~outer_memory_to_memorystream_adapter(){
		
	}
		
	size_type tell()const{
		check_error__();
		return mOffset;
	}

	size_type read(void *buf,size_type size){
		if(mOffset > mSize){
			mError = true;
			return 0;
		}
		size_t readed = size;
		
		if(size + mOffset > mSize){//指定されたバッファより少ない
			readed = mSize - mOffset;
			memcpy(buf,getNowPtr(),readed);
			
			mEOF = true;
		}else{
			memcpy(buf,getNowPtr(),size);
		}
		return readed;
	}
	size_type write(const void *buf,size_type size){
		if(mOffset > mSize){
			mError = true;
			return 0;
		}
		size_t readed = size;
		
		if(size + mOffset > mSize){//指定されたバッファより少ない
			readed = mSize - mOffset;
			memcpy(getNowPtr(),buf,readed);

			mEOF = true;

		}else{
			memcpy(getNowPtr(),buf,size);
		}
		return readed;
	}
	bool eof()const{
		return mEOF;
	}
	bool error()const{
		return mError;
	}
	bool seek(long offset, int origin )
	{
		size_t bit = a;
		size_t os = mOffset;
		
		//value filter

		if(mOffset > mSize){//フラグ倒しておく
			mOffset = mSize;
			mError = false;
		}
		if(mOffset >= mSize){//とりあえずフラグ倒しておく
			mEOF = false;
		}


		//seek 
		switch(origin){
		case seek_begin:
			os = offset;
			break;
		case seek_current:
			os += offset;
			break;
		case seek_end:
			if(offset > 0){
				return false;
			}
			os += offset;
			break;
		}
		//error check
		if(os > mSize){//やっぱりエラッタので　フラグ上げておく
			mEOF = true;
			mError = true;
			return false;
		}
		//update
		mOffset = os;

		return true;
	}

	///今使用しているサイズを返す
	size_type size(){
		return mOffset;
	}

	
};


}//end of dkutil namespace



#endif