
/*!
@since 2004/03/17
@author d金魚
*/

#ifndef DKUTIL_FILESYSTEM_OLD_UTILITY_HPP
#define DKUTIL_FILESYSTEM_OLD_UTILITY_HPP

#if defined(WIN32) 
#include "dkutilFSWin32Common.h"
#endif

#	include "include/dkutilBoostPolicy.h"
#	include "dkutilFunction01.h"
#	include "parser/dkutilParser.h"
#	include "dkutil_c/dkcSJISFileSystem.h"


namespace dkutil{

/*
namespace policy{


	/// 読み出しモードで開く。ファイルがないか、見つからない場合は、エラー
	extern const char *f_readonly;
	/// 書き込みモードで空のファイルを開く。指定されたファイルが既にあると、そのファイルは消滅する。 
	extern const char *f_writeonly;
	///  EOF マーカーを削除せずに、ファイルに追記ができます。ファイルがない場合は作成します。
	extern const char *f_postscriptonly;
	/// 読みこみと書き込みの両方のモードで開く。 (対象は既存ファイル)
	extern const char *f_read;  
	///読みこみと書き込みの両方のモードで空のファイルを開く。指定されたファイルが既にあると、そのファイルは消滅する。
	extern const char *f_write;
  ///追記モードで読みこみと書き込みの両方のモードで開く。ファイルがない場合は作成します
  extern const char *f_postscript;
	///バイナリモードで開く。
	extern const char *f_binary;
	///テキストモードで開く。
	extern const char *f_text;

	
}//end of policy namespace

*/

///@return std::stringを返すGetCurrentDirecory()
inline std::string SafeGetCurrentDirectory(){
	char buff[dkcdMAXPATH_BUFFER];
	if(FALSE==dkcGetCurrentDirectory(buff,sizeof(buff))){
		throw std::logic_error("SafeGetCurrentDirectory Error");
	}
	return std::string(buff);
	/*char buff[MAX_PATH * 2]="";
	DWORD r = ::GetCurrentDirectory(sizeof(buff),buff);
	size_t len = strlen(buff);
	if(r != len) throw std::logic_error("SafeGetCurrentDirectory Buffer Was Lost");
	return std::string(buff);
	*/
}
/*!
@param s[in] ディレクトリの文字列が入ったstd::string
@param bForce[in] trueだと、ディレクトリが存在しなくても強制的にディレクトリを作る
@return trueは成功
*/
///デフォルトではディレクトリが無かったとき、強制的にディレクトリを作るように出来ている。
inline bool SafeSetCurrentDirectory(parm_string s,bool bForce=true){
	if(bForce==true){//強制的にDirectoryを作る
		if(false==FileAndFolderExist(s.c_str())){
			DKUTIL_RETURN_FALSE(CreateDirectory(s.c_str()));
		}
	}
	if(FALSE==dkcSetCurrentDirectory(s.c_str()))
	{
		return false;
	}
	return true;
}
#if 0
///@return ワイルドカードだったらTRUE（正常な拡張子が付いていたらTRUE)
inline bool isWildCard(const char *wcard){
	PARSE_STRING_CONTAINER c;
	size_t len = strlen(wcard);
	dkutil::ParseStringDirectoryName(c,wcard,len);
	
	std::string target;
	if(c.empty())
	{
		target = wcard;
	}
	else
	{
		PARSE_STRING_CONTAINER::reverse_iterator rit = c.rbegin();
		target = (*rit);
	}

	bool bR = false;
	std::string::iterator it = target.begin();
	for(;it != target.end();it++)
	{
		if((*it) == '*' || (*it) == '?'){
			bR = true;
			break;
		}

	}
	return bR;
	/*
	char *ptr = dkutil::GetFileExtension(wcard);
	if(ptr == wcard || ptr == NULL){
		return false;
	}
	
	return true;
	*/
}


///ファイルのフルパスからフォルダーパスを得る。
inline bool FileFullPathToFileFolderPath(parm_string src,std::string &dest){
	if(src.empty()) return false;
	if(src.length() <= 3) return false;
	std::string::const_reverse_iterator rit=src.rbegin();
	for(;rit != src.rend();rit++)
	{
		if((*rit) == '\\'){
			std::string::const_reverse_iterator tit = rit;
			dest.clear();
			for(;tit != src.rend();tit++){
				dest.insert(dest.begin(),(*tit));
			}
			return true;
		}
	}
	return false;
}
/*!
@param src[in] ファイルのフルパスが入ったstd::string
@param dest[out] ファイルのパスのみになったものを格納するstring
@return trueなら成功
@note
例：<br>
C:\boot.ini → boot.ini<br>
C:\Windows\winwin.exe → winwin.exe<br>

*/
///ファイルへのフルパスを普通のパスにする。
inline bool FileFullPathToFilePath(parm_string src,std::string &dest){
	if(src.empty()) return false;
	std::string::const_iterator it=src.begin();
	std::string::const_iterator re=src.begin();
	for(;it != src.end();it++)
	{
		if('\\'==(*it)){
			re = it;
		}
			
	}
	if(re==src.begin()) return false;
	//dest.clear();
	for(;re != src.end();re++){
		dest +=(*re);
	}
	//dest.insert(re,src.end());
	return true;
}
#endif
/*!
@param s[in] ファイルの拡張子がついたstd::stringデータ。
@param exe[in] ファイルの拡張子 *. は不要 例："txt"
@return TRUEだったらexeと同じ内容
*/
///ファイルの拡張子がexeと同じかどうか確かめる
inline bool FileExtensionCompare(parm_string s,parm_string exe){
	std::string tmp = dkutil::GetFileExtension(s.c_str());
	
	if(0!=strnicmp(tmp.c_str(),exe.c_str(),strlen(exe.c_str())))
	{
		return false;
	}
	return true;
}

/*!
@param dir[in][out] ディレクトリの名前　かつ、ここにファイルの名前が追記される。
@param filename[in] ファイルの名前
@return trueだと成功
@throw std::string等がエラったらもちろん何かを投げつける。
@todo SJIS問題対策:対策済み
*/
///ディレクトリとファイルの名前を繋げる。
inline bool DirectoryPlusFileName(std::string &dir,parm_string filename){
	size_t len = filename.size();
	const char *fname = filename.c_str();
	if(len >= 2){
		//簡易絶対パス判定
		dkcmNOT_ASSERT((dkutil::isAlpha(fname[0]) && fname[1] == ':'));
		if((dkutil::isAlpha(fname[0]) && fname[1] == ':')){
			return false;
		}
	}
	if(!dir.empty()){
		if(FALSE==dkcIsTailPathSep(dir.c_str(),dir.size())){//SJIS対策済み
			dir.insert(dir.end(),dkcdPATH_SEP);
		}
		/*if(*(dir.end() - 1) != '\\'){//ここ、SJIS問題対策をする。
			dir.insert(dir.end(),'\\');
		}*/
	}
	if(dkcmIS_PATH_SEP(*fname)){//SJIS文字の１文字目に\\や/は無いから大丈夫かな？
		dir += (fname + 1);
	}else{
		dir += fname;
	}
	
	return true;
}
#if 0
inline bool DirectoryPlusFileName(std::string &dir,const char *  parm_string filename){
	size_t len = strlen(filename);
	if(len >= 2){
		//簡易絶対パス判定
		dkcmNOT_ASSERT((dkutil::isAlpha(filename[0]) && filename[1] == ':'));
		if((dkutil::isAlpha(filename[0]) && filename[1] == ':')){
			return false;
		}
	}
	if(!dir.empty()){
		if(FALSE==dkcIsTailPathSep(dir.c_str(),dir.size())){//SJIS対策済み
			dir.insert(dir.end(),dkcdPATH_SEP);
		}
		/*if(*(dir.end() - 1) != '\\'){//ここ、SJIS問題対策をする。
			dir.insert(dir.end(),'\\');
		}*/
	}
	if(dkcmIS_PATH_SEP(*filename)){//SJIS文字の１文字目に\\や/は無いから大丈夫かな？
		dir += (filename + 1);
	}else{
		dir += filename;
	}
	
	return true;
}
#endif

///@return sが相対パスだったらTRUE
inline bool isRelativityPath(const char *s){
	return (TRUE == dkcIsRelativityPath(s));
	/*if(size <= 3){
		if(s[1] == '.'){
			goto LabelSucceeded;
		}
		std::string str = s;
		str += " path is invalid!!" ;
		str += __FILE__;
		str += to_string(__LINE__);
		throw std::invalid_argument(str);
	}
LabelSucceeded:
	if(dkutil::isAlpha(s[0]) && s[1]==':') return false;
	return true;
	*/
}
///@return sが絶対パスだったらTRUE
inline bool isAbsolutelyPath(const char *s){
	return (TRUE == dkcIsAbsolutelyPath(s));
	//return !isRelativityPath(s,size);
}

#if 0
///Z:\dkaftk_test\.\test.cpp となっているのを　Z:\dkaftk_test\test.cppのように訂正します。
///@return 訂正したならTRUE　そのままならFALSE
inline bool LocalPathErrorCorrection(std::string &str){
	std::string::iterator it=str.begin();
	size_t count=0;
	bool r=false;
	for(;it!=str.end();it++,count++){
		if(*it=='\\' && count + 2 < str.size()){
			if(*(it + 1) == '.' && *(it + 2) == '\\')
			{
				it = str.erase(it,it + 2);
				r = true;
			}
		}
	}
	return r;
}
#endif

///fopen,fclose,fread,fwrite,fseek,ferror,feof 等の簡単なラッパー（でも強力！
class file_operator{

	std::string mfilename;
	std::string mmode;
	FILE *mfp;
	void check_fp()const{
		DK_TRUE_ASSERT_OR_THROW(
			!mfp,
			std::runtime_error("file_operator:openしてない。")
		);
	}
public:
	/*
	file_operator(const char *filename=NULL,
		const char *mode=policy::f_readonly,
		const char *type=policy::f_binary)
	{
		mfp=NULL;
		if(filename){mfilename=filename;}
		if(
		mmode = mode;
		mmode += type;
	}*/
	/*file_operator(const char *filename,const char *str="rb"){
		mfp = NULL;
		if(filename){
			mfilename = filename;
		}
		mmode = str;
	}
	*/
	file_operator(parm_string filename,parm_string str="rb"){
		mfp = NULL;
		if(filename.c_str()){
			mfilename = filename.c_str();
		}
		mmode = str.c_str();
	}
	file_operator(){
		mfp = NULL;
	}

	file_operator(const file_operator &c){
		mfp=NULL;
		mfilename = c.filename();//.c_str();
		mmode = c.mode();//.c_str();
		
		
	}

	virtual ~file_operator(){close();}
	bool reset(const char *filename,const char *mode){
		close();
		DK_TRUE_ASSERT_OR_THROW((filename==NULL || mode==NULL),
			std::invalid_argument("file_operator::resetinvalid argument"));

		mfilename=filename;
		mmode = mode;

		return true;
	}
	const char *filename()const{
		return mfilename.c_str();
	}
	const char *mode()const{
		return mmode.c_str();
	}
	bool open(){
		close();
		mfp=::fopen(mfilename.c_str(),mmode.c_str());
		if(mfp==NULL) return false;
		return true;
	}
	const FILE *handle()const{
		return mfp;
	}
	FILE *handle(){
		return mfp;
		}
	long tell()const{
		check_fp();
		return ftell(mfp);
		}
	/*size_t read(const void *buf,size_t size){
		check_fp();
		return fread(const_cast<void *>(buf),1,size,mfp);
	}
	size_t write(const void *buf,size_t size){
		check_fp();
		return fwrite(const_cast<void *>(buf),1,size,mfp);
	}*/
	size_t read(void *buf,size_t size){
		check_fp();
		return fread((buf),1,size,mfp);
	}
	size_t write(const void *buf,size_t size){
		check_fp();
		return fwrite((buf),1,size,mfp);
	}
	bool eof()const{
		check_fp();
		return ( 0 != feof(mfp) );
	}
	bool error()const{
		check_fp();
		return ( 0 != ferror(mfp) );
	}
	bool seek(long offset, int origin ){
		check_fp();
		return (0 == fseek(mfp,offset,origin) );
	}
	
	void close(){
		if(mfp){::fclose(mfp);mfp=NULL;}
	}
	/*!
	@param func_[in] ロードしたデータを処理する為のファンクター
	//@param ope[in] このファイルのメンバ関数(readかwrite)
	@param innerbuffsize[in] 内部で使われるバッファのサイズ
	*/
	template<class FUNCTOR_>
	bool div_read_each(FUNCTOR_ func_,size_t innerbuffsize = 1024 * 512)
	{
		scoped_buffer_byte t(innerbuffsize);
		for(;false==eof();)
		{
			if(true==error() ){
				throw std::runtime_error("ferror error");
			}
			size_t count = read(t.get(),t.size());
			//ありえないエラーチェック
			dkcmNOT_ASSERT(count > t.size());

			func_(t.get(),count);
		}
		return true;
	}
	template<class FUNCTOR_>
	bool div_write_each(FUNCTOR_ func_,size_t innerbuffsize = 1024 * 512)
	{
		scoped_buffer_byte t(innerbuffsize);
		for(;false==eof();)
		{
			if(true==error() ){
				throw std::runtime_error("ferror error");
			}
			size_t count = write(t.get(),t.size());
			//ありえないエラーチェック
			dkcmNOT_ASSERT(count > t.size());

			func_(t.get(),count);
		}
		return true;
	}

};

class throw_file_operator : public file_operator
{
public:
	typedef file_operator base_type;
	typedef throw_file_operator self_type;

	throw_file_operator(const char *filename,const char *str="rb") : base_type(filename,str){
	}
	throw_file_operator(parm_string filename,parm_string str="rb") : base_type(filename,str){
	}
	throw_file_operator(const file_operator &c) : base_type(c){
	}
	throw_file_operator(){}

	size_t read(void *buf,size_t size){
		size_t t = base_type::read(buf,size);
		if(size != t){
			throw std::runtime_error("throw_file_operator::read / readに指定したサイズとreadされたサイズが合いません！");
		}
		return t;
	}
	size_t write(const void *buf,size_t size){
		size_t t = base_type::write(buf,size);
		if(size != t){
			throw std::runtime_error("throw_file_operator::write / writeに指定したサイズとwirteしたサイズが合いません！");
		}
		return t;
	}
};

/*!
@note
read writeの時ファイルの終端に達した場合等の時はthrow std::runtime_errorします。
*/
///責任のあるfile_operator read writeで指定されたサイズをしっかり読んでくれる。
class responsible_file_operator : public file_operator{
public:
	typedef file_operator base_type;
	typedef responsible_file_operator self_type;

	responsible_file_operator(const char *filename,const char *str="rb") : base_type(filename,str){
	}
	responsible_file_operator(parm_string filename,parm_string str="rb") : base_type(filename,str){
	}
	responsible_file_operator(const file_operator &c) : base_type(c){
	}
	responsible_file_operator(){}

	size_t read(void *buf,size_t size){
		size_t t = base_type::read(buf,size);
		if(size > t){
			if(eof()){
				throw std::runtime_error("responsible_file_operator::read eof");
			}
			if(error()){
				throw std::runtime_error("responsible_file_operator::read error");
			}
			if(size - t == read((char *)buf + t,size - t)){
				return size;
			}
		}
		dkcmNOT_ASSERT(size != t);
		return size;
	}
	size_t write(const void *buf,size_t size){
		size_t t = base_type::write(buf,size);
		if(size > t){
			if(eof()){
				throw std::runtime_error("responsible_file_operator::read eof");
			}
			if(error()){
				throw std::runtime_error("responsible_file_operator::read error");
			}
			if(size - t == write((const char *)buf + t,size - t)){
				return size;
			}
		}
		dkcmNOT_ASSERT(size != t);
		return size;
	}


};




/*inline bool isNativeDirectoryPath(const char *s,size_t size){
	size_t i=0;
	for(;i<size;i++){
		

	}


}*/

#if 0
/*!
@todo
friend operator　とか沢山付けて、\\をつけるような感じにする。
日本語文字対策する。SYN氏のHPに書いてある。
*/

/*
class directory_string : public std::string{
private:
	///相対パスだったらTRUE
	bool mIsRelativity;
	///中身がしっかりdirectoryだったらTRUE
	bool mIsNative;
public:
	typedef std::string base_type;
	typedef directory_string self_type;
	
	bool isRelativity()const{return mIsRelativity;}
	bool isNative()const{return 

	directory_string(const char *t) : base_type(t){
		
		//isRelativity()
	}
	directory_string(const std::string &r) : base_type(r){
		//isRelativity()
	}
	const char *directory()const{return base_type::c_str();}
	const std::string &directory()const{
		return (base_type)(*this);
	}

	self_type &operator +=(const self_type &s){
		return base_type::operator+=((base_type)s);
	}
	self_type &operator +(const self_type &s){
		return base_type::operator+((base_type)s);
	}



};
*/
#endif

/*
class file_finder_interface{
public:
	typedef std::string directory_type;
	
	virtual ~file_finder_interface(){}
	virtual bool reset(const char *target,const char *dir,bool bSub) = 0;
	virtual const directory_type &next() = 0;



};
*/



///このクラスは宣言後、isValidでもして確かめておくこと。４Gクラスのファイル読み込めないので^^;
template<class TYPE_T>
class scoped_file_buffer : public 
	scoped_buffer_base<policy::allocate_policy_malloc,TYPE_T>
{
	size_t mFileSize;
public:
	typedef scoped_file_buffer self_type;
	typedef scoped_buffer_base<policy::allocate_policy_malloc,TYPE_T> base_type;
	scoped_file_buffer(const char *filename = NULL){
		mFileSize = 0;
		reset(filename);
	}
	size_t filesize()const{
		return mFileSize;
	}
	bool reset(const char *filename){
		if(!filename) return false;
		DWORD high=0;
		DWORD low = 0;
		GetFileSizeHighLow(filename,&high,&low);
		//こんなものは読めない！
		if(high != 0){return false;}

		bool r = base_type::reset(low );
		
		if(false==r) return false;

		file_operator o(filename);
		if(false==o.open()){
			return false;
		}
		
		if(size() != o.read(get(),size())){
			throw std::logic_error("scoped_file_buffer::reset() file read error!!");
		}

		mFileSize = low;
		
		return true;

	}
};

template<typename TYPE_T>
class file_buffer_base : public scoped_file_buffer<TYPE_T>{
public:
	typedef scoped_file_buffer<TYPE_T> base_type;
	typedef file_buffer_base<TYPE_T> self_type;
private:
	std::string mFileName;
public:
	file_buffer_base(){
	
	}
	const char *filename()const{
		return mFileName.c_str();
		}

	bool reset(const char *filename){
		if(false==base_type::reset(filename)){
			return false;
		}
		mFileName = filename;
	}

};

typedef file_buffer_base<BYTE> file_buffer;



inline bool LoadTextToString(std::string &s,const char *filename){
	file_operator op(filename,"rt");
	if(false==op.open()) return false;
	char buf[4096]="";
	size_t bufsize = sizeof(buf) - 1;
	for(;;){
		size_t readsize = op.read(buf,bufsize);
		s += buf;		
		if(bufsize > readsize){
			break;
		}
		memset(buf,0,sizeof(buf));
	}
	return true;
}



}//end of dkutil namespace

#endif //end of include once 



