
#ifndef DKUTIL_FILESYSTEM_UTILITY_HPP
#define DKUTIL_FILESYSTEM_UTILITY_HPP

//#include <dkutil_c/dkc.h>
#include <string>
#include <dkutil/filesystem/path_string.hpp>
#include <dkutil/macro.hpp>
#include <dkutil/dll.hpp>
#include <dkutil/parser/char_util.hpp>
#include <math.h>

#ifdef WIN32
# include <dkutil/filesystem/win32_utility.hpp>
#endif

namespace dkutil{
		
inline bool FileBinaryCompare(path_string_ref f1,path_string_ref f2){
	return DKUTIL_SUCCEEDED_BOOL(dkcFileBinaryCompare(f1.c_str(),f2.c_str()));
}
///ファイルサイズを得る。
/*!
@param str[in] ファイルの名前(パス）
@param high[out] ファイルのサイズの上位ダブルワード(これにMAXDWORDをかけてlowを足すとファイルサイズになる。
@param low[out] ファイルサイズの下位ダブルワード
*/
///ファイルサイズを得る。ロックされたファイルでも得ることが出来るので便利＾＾；
inline bool GetFileSizeHighLow(parm_string str,DWORD *high,DWORD *low){
	/*WIN32_FIND_DATA findData={0};
	HANDLE hFind=NULL;
	// ファイルサイズ取得
	if((hFind = FindFirstFile(str,&findData)) == INVALID_HANDLE_VALUE){
		return false;
	}

	//ファイルのサイズをヴちこむ
	*high = findData.nFileSizeHigh;
	*low = findData.nFileSizeLow;
	FindClose(hFind);
	return true;
	*/
	return TRUE==dkcFileSize64(str.c_str(),high,low);

}
/*!
@param str[in] ファイルの名前(パス）
@param  *GetSize[out] ファイルのサイズを入れるULONGLONG型の変数へのポインタ
*/
///ファイルサイズを得る。dGetFileSizeHighLowのラッパー
//inline bool GetFileSize(const char *str,ULONGLONG *GetSize){
inline bool GetFileSize64(parm_string str,ULONGLONG *GetSize){
	DWORD High=0,Low=0;
	bool result=false;
	result=GetFileSizeHighLow(str,&High,&Low);
	*GetSize = ( High * MAXDWORD ) + Low;
	return result;
}
inline bool GetFileSize(parm_string str,ULONGLONG *GetSize){
	return GetFileSize64(str,GetSize);
}
/*!
注意：約４GB以下のファイルサイズを得ることが出来る。ULONG_MAX byteですかね？<br>
@return 成功したらファイルサイズを返す。0だとdGetFileSize関数が失敗した,または約4GB以上（ ULONG_MAX byte以上)のファイルのことを表す。
*/
///ファイルサイズを得る（dGetFileSizeのラッパー)　ULONG_MAX byte以下のファイル専用
inline DWORD GetFileSizeMini(parm_string str){
	ULONGLONG Get;
	if(false==GetFileSize64(str.c_str(),&Get)) return 0;
	if(ULONG_MAX < Get) return 0;
	return static_cast< DWORD >(Get);
}



///@note ファイルのみ検索のはず！！＜＝2005/09/24よりdkcFileExist()はそれが保証されるようになった。
inline bool FileExist(parm_string s){
/*
#ifdef WIN32
#	ifdef _DEBUG
	DWORD dw = ::GetFileAttributes(s.c_str());
	return (dw != 0xFFFFFFFF);
#	else
	return (::GetFileAttributes(s) != 0xFFFFFFFF);
#	endif
#else
	return dkcFileExist(s.c_str());
#endif
*/
	return TRUE==dkcFileExist(s.c_str());
}

	
/*!
☆データセーブ:<br>
データをちょっと暗号化してセーブをします。<br>
なので、バイナリエディタで開いても一見分かりません。<br>
@param	*pFile[in]			: データ名
@param	*pData[out]			: データへのポインタ
@param	Size[in]	: データサイズ
@return	 成功 true / 失敗 false
*/
inline bool SaveData( const char *pFile, void *pData, unsigned long Size )
{
	bool result = false;
	unsigned char *p = (unsigned char *)pData;
	char *guid = "LSD";
	char key = (char)(Size&0xFF);
	FILE *fp = NULL;

	// ファイルオープン
	fp = fopen( pFile, "wb" );
	if ( fp == NULL ) goto END;

	// 識別子
	//fwrite( guid, sizeof(char), 4, fp );
	if(FALSE==dkcFWriteAllCheck(guid,4,fp)) goto END;
	// データサイズ
	//fwrite( &Size, sizeof(unsigned long), 1, fp );
	if(FALSE==dkcFWriteAllCheck(&Size,sizeof(unsigned long),fp)) goto END;

	// データ書き出し
	while ( Size-- )
	{
		// 簡単な暗号
		char data = *p++;
		data ^= key++;
		char temp = 0;
		temp |= (char)((data&0x0F)<<4);
		temp |= (char)((data&0xF0)>>4);

		if(temp != fputc( temp, fp ))
			goto END;
	}

	result = true;

END:
	if ( fp != NULL ) fclose( fp );

	return result;
}

/*!
☆データロード:dkutil::SaveData()で保存したデータロードをします。
@param *pFile[in]			: データ名
@param *pData[out]			: データへのポインタ
@param Size[in]	: データサイズ
@return : 成功 true / 失敗 false

*/
inline bool LoadData( const char *pFile, void *pData, unsigned long Size )
{
	bool result = false;
	unsigned char *p = (unsigned char *)pData;
	char guid[4] = "";
	unsigned long SizeTemp = 0;
	char key = 0;
	FILE *fp = NULL;

	//別にいらないかな^^;
	//Luna::ResetCurrentDirectory();

	 //ファイルオープン
	fp = fopen( pFile, "rb" );
	if ( fp == NULL ) goto END;

	// 識別子
	fread( guid, sizeof(char), 4, fp );
	if ( strcmp( guid, "LSD" ) ) goto END;

	// データサイズ
	fread( &SizeTemp, sizeof(unsigned long), 1, fp );
	if ( SizeTemp != Size ) goto END;

	// ファイルサイズからキー生成
	key = (char)(Size&0xFF);
	unsigned long i;
	// データ読み出し
	for ( i = 0; i < Size; i++ )
	{
		// 簡単な暗号
		char temp = (char)fgetc( fp );
		char data = 0;
		data |= (char)((temp&0x0F)<<4);
		data |= (char)((temp&0xF0)>>4);
		data ^= key++;

		p[i] = data;
	}

	result = true;

END:
	if ( fp != NULL ) fclose( fp );

	return result;
}
/*!
☆フォルダ生成フォルダの生成をします。
@param	 *pPath[in]		: 生成フォルダパス
@return	: 成功 true / 失敗 false
*/
inline bool CreateDirectory( const char *pPath )
{
/*	SECURITY_ATTRIBUTES attr={0};
	char work[MAX_PATH] = "";
	unsigned long n = 0;
	unsigned long len = strlen(pPath);
	
	while ( n < len )
	{
		 //フォルダ名取得
		while ( n < len )
		{
			if ( (pPath[n] == '\\') && (n != '\0') )
			{
				if ( work[n-1] != ':' )
				{
					break;
				}
			}
			work[n] = pPath[n];
			n++;
		}
		work[n] = '\0';

		 //フォルダ作成
		attr.nLength = sizeof(SECURITY_ATTRIBUTES);
		attr.lpSecurityDescriptor = NULL;
		attr.bInheritHandle = false;

		::CreateDirectory( work, &attr );

		work[n++] = '\\';
	}
	
	
	return true;
	*/

	return DKUTIL_SUCCEEDED(dkcCreateDirectory(pPath));
}


inline bool CreateZeroByteFile(const char *filename,bool rewrite=false){
	return TRUE==dkcCreateZeroByteFile(filename,rewrite);
}


inline void EraseSlashDotSlash(std::string &t)
{
	do{//"\\.\\"を削除
		std::string::size_type tpos = t.find("\\.\\");
		if(tpos==std::string::npos) break;
		t.erase(tpos,2);
	}while(1);
}
/*!
@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();
	std::string spl;
	if(len >= 2){
		//簡易絶対パス判定
		//dkcmNOT_ASSERT((dkutil::isAlpha(fname[0]) && fname[1] == ':'));
		dkcmFORCE_NOT_ASSERT((dkutil::isAlpha(fname[0]) && fname[1] == ':'));
		if((dkutil::isAlpha(fname[0]) && fname[1] == ':')){
			PathSplit split;split.reset(fname);
			spl = split.mFname + split.mExt;
			fname = spl.c_str();
			//return false;
		}
	}
	if(!dir.empty()){
		if(FALSE==dkcIsTailPathSep(dir.c_str(),dir.size())){//SJIS対策済み
			dir.insert(dir.end(),dkcdPATH_SEP);
		}
	}
	if(dkcmIS_PATH_SEP(*fname)){//SJIS文字の１文字目に\\や/は無いから大丈夫かな？
		dir += (fname + 1);
	}else{
		dir += fname;
	}
	EraseSlashDotSlash(dir);
	return true;
}


}//end of dkutil namespace



#endif
