
#ifndef DKUTIL_FILESYSTEM_LITTLEENDIAN_FILESTREAM_HPP
#define DKUTIL_FILESYSTEM_LITTLEENDIAN_FILESTREAM_HPP

//#include <dkutil_c/dkc.h>
#include <dkutil/filesystem/interface.hpp>
#include <dkutil/synchronized.hpp>
#include <dkutil/macro.hpp>
#include <dkutil/filesystem/utility.hpp>
#include <dkutil/filesystem/big_filestream.hpp>


namespace dkutil{

class CLittleEndianFileStream : public IFileStream{
	big_filestream mS;
	//ファイル名
	//std::string mfilename;


public:
	typedef IFileStream base_type;
	typedef base_type::size_type size_type;
	typedef base_type::size_type64 size_type64;
	typedef CLittleEndianFileStream self_type;

	/*///邪道
	big_filestream &getBase(){
		return mS;
		}
	*/
	CLittleEndianFileStream() : base_type(read_mode | binary_mode){
		

	}
	CLittleEndianFileStream(const char *filename,UINT flag) : base_type(flag){
		

		reset(filename,flag);

	}
	virtual ~CLittleEndianFileStream(){
		//clear();なんかバグるのでmSのデストラクタに任せる。
	}
	///内部バッファをクリアする。
	virtual void clear(){
		mS.close();
	}
	virtual bool reset(const char *filename,UINT flag){
		clear();
		char f[4]="";
		if(false==mS.reset(filename,flag)){
			return false;
		}
		base_type::setOpenModeFlag(flag);
		return mS.open();
	}
	/*virtual ISerializeStream& operator << (ISerializeStream &c){
		*this << 

	}*/
	
	//ファイルのサイズ
	/*virtual size_type64 filesize()const{
		
		//return mS.filesize();
		//return mS.size();
	}*/
	///バッファをフラッシュ((ファイルに完全に書きこむ))する。
	virtual bool flush(){
		return mS.flush();
	}
	virtual bool good()const{
		int tmp = big_filestream::invalid_handle;
		return mS.handle() != (big_filestream::handle_type)tmp;
	}
	/*!
	@param buff[out] バッファー
	@param size[in] バッファのサイズ
	@param readsize[in] 実際に読み込んだサイズ
	@return falseならエラー。（バッファが足りない等）
	*/
	///読み込む
	virtual bool read(void *buff,size_t size,size_t *readsize){

		bool r = false;
		//sizeのテンポラリ
		size_t tsize = size;
		//読み込んだサイズのテンポラリ
		size_t t;
		//既に終わったサイズのテンポラリ
		size_t tf = 0;
		char *buf = (char *)buff;
		while(1){
			t = mS.read(buf,tsize);
			tf += t;

			if(t == size){
				break;
			}else if(tf == size){
				break;
			}
			if(eof()){
				goto End;
			}
			if(error()){
				goto End;
			}
			tsize = tsize - t;
			buf = (char *)buf + t;

		}
#	ifdef DEBUG
		/*if(redsize > ULONG_MAX){
			DKUTIL_THROW_OR_NOTICE(filesysytem_error("んなアホがあるか！"));
		}*/
#	endif
		r = (error()==false);
	End:
		if(readsize){//読みこんだ分
			*readsize = tf;
		}
		return r;
	}

	///書き込む(エンディアンチェンジは無し) @see IStream::write()
	virtual size_t write(const void *buff,size_t size){
		mS.responsible_write(buff,size);
		return size;

	}

	///責任を持ってすべてを書き込まないタイプ
	virtual bool write(const void *buff,size_t size,size_t *write_size)
	{
		dkcmASSERT(write_size);
		*write_size = mS.write(buff,size);
		return error()==false;
	}
	/*!
	@param buff[out] バッファー
	@param size[in] バッファのサイズ
	@param readsize[in] 実際に読み込んだサイズ
	@return falseならエラー。
	@note
	read()との違い：
	ref()は内部のオフセットカウントを変更しない。
	*/
	///中身を見る。
	virtual bool ref(void *buff,size_t size,size_t *readsize){
		size_type redsize = mS.ref(buff,size);
#	ifdef DEBUG
		if(redsize > ULONG_MAX){
			DKUTIL_THROW_OR_NOTICE(filesystem_error("んなアホがあるか！"));
		}
#	endif
		if(readsize){
			*readsize = (size_t)redsize;
		}
		return error()==false;
	}
	/*!
	@param offset[in] origin指定から何バイト、シークするか。
	@param origin[in] 
	@note
	動作はfseekと同じです。（爆）
	originも実はfseekと同じ指定子をぶち込んでも動いちゃったりします＾＾；
	*/
	///シークする。
	virtual bool seek(seek_arg_type offset,int origin){
		return mS.seek(offset,origin);
	}
	///今のバッファの最初からのオフセットを返す。
	virtual seek_arg_type tell()const{
		return mS.tell();
	}
	virtual bool eof()const{
		return mS.eof();
	}
	virtual bool error()const{
		return mS.error();
	}
	/*!
	@note
	serialize_interfaceのポインタをぶち込めば、
	シリアライズしたり、デシリアライズしたりしてくれます。
	*/
	///シリアライズする。
	//virtual bool serialize(serialize_interface *) = 0;
	///@see IStream::data()
	virtual const void *data()const{
		return NULL;
	}
	///内部バッファのサイズ。
	virtual size_type size()const{
		return 0;
	}
	///内部バッファをリサイズする。
	virtual void resize(size_type size){
		return;
	}

	virtual int type()const{
		return file_stream_type;
	}
	virtual const char *filename()const{
		return mS.filename();
	}
	virtual seek_arg_type limit()const{
		return mS.limit();
	}
/*
	virtual ISerializeStream& operator << (char &c){
		serialize_helper(c);
		return *this;
	}
	virtual ISerializeStream& operator << (short &s){
		serialize_helper(s);
		return *this;
	}
	virtual ISerializeStream& operator << (int &n){
		serialize_helper(n);
		return *this;
	}
	virtual ISerializeStream& operator << (long &l){
		serialize_helper(l);
		return *this;
	}
	virtual ISerializeStream& operator << (LONGLONG &ll){
		serialize_helper(ll);
		return *this;
	}
	virtual ISerializeStream& operator << (BYTE &uc){
		serialize_helper(uc);
		return *this;
	}
	virtual ISerializeStream& operator << (USHORT &us){
		serialize_helper(us);
		return *this;
	}
	virtual ISerializeStream& operator << (UINT &n){
		serialize_helper(n);
		return *this;
	}
	virtual ISerializeStream& operator << (ULONG &n){
		serialize_helper(n);
		return *this;
	}
	virtual ISerializeStream& operator << (ULONGLONG &ll){
		serialize_helper(ll);
		return *this;
	}
	virtual ISerializeStream& operator << (bool &b){
		serialize_helper(b);
		return *this;
	}
*/
};


}//end of dkutil namespace



#endif
