
#ifndef DKUTIL_FILESYSTEM_WIN32_UTILITY_HPP
#define DKUTIL_FILESYSTEM_WIN32_UTILITY_HPP

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

namespace dkutil{
		

struct PathSplit{

	std::string mDrive,mDir,mFname,mExt;
	PathSplit(parm_string str){
		reset(str);
	}
	PathSplit(){}
	bool reset(parm_string str){
		char drive[dkcdMAXPATH_BUFFER]="";
		char dir[dkcdMAXPATH_BUFFER]="";
		char fname[dkcdMAXPATH_BUFFER]="";
		char ext[dkcdMAXPATH_BUFFER]="";

		_splitpath( str.c_str(), drive, dir, fname, ext );
		mDrive = drive;
		mDir = dir;
		mFname = fname;
		mExt = ext;
		return true;
	}
};

/*!
☆ファイル存在チェックファイルの存在チェックをします。
@param	 *pFile[in]		: チェックするファイル名
@return 存在する＝true / 存在しない = false
@note
フォルダも検索されちゃうかも！？
*/
inline bool FileAndFolderExist(parm_string pFile )
{
	WIN32_FIND_DATA wfd;
	//  ファイル検索ハンドルを取得
	HANDLE hFile = ::FindFirstFile( pFile.c_str(), &wfd );
	// 検索できたかチェック
	bool bRet = (hFile != INVALID_HANDLE_VALUE);
	// 検索ハンドルをクローズ
	//if(hFile != INVALID_HANDLE_VALUE){
	if(bRet){
		::FindClose( hFile );
	}

	return bRet;
}

inline bool FolderExist(parm_string folder){
	WIN32_FIND_DATA fd;
	HANDLE hFile = ::FindFirstFile( folder.c_str(), &fd );
	bool bR = false;
	if(hFile == INVALID_HANDLE_VALUE){
		goto END;
	}
	if(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
	{
		bR = true;
	}

	::FindClose( hFile);
	
END:
	return bR;
}


/*!
Win32APIのファイル系関数を使ってセーブ、ロードを行う。
@param filename[in] ファイルネーム 例："sample.txt" 等
@param filedata[in] ファイルのデータ
@param size[in] ファイルのデータのサイズ(バイト単位)
@return edk_SUCCEEDED以外だったらエラー
@note
GetLastError()でエラー情報を取得できます。

*/ 
inline int SaveFile(const char *filename,const void *filedata,size_t size){
	HANDLE hFile;
	hFile = CreateFile(filename, GENERIC_WRITE, 0, 0, 
					OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if(hFile==INVALID_HANDLE_VALUE){
		//MB("CreateFile FAILED");
		//VISUAL_LASTERROR();//エラー表示マクロ
		return edk_FAILED;
	}
	SetFilePointer(
		hFile,    // ファイルハンドル 
		0,    // ファイルポインタを移動する距離
		0,    // 距離６４ビット分の上位３２ビット 
		FILE_BEGIN     // 移動の仕方 
	   );
	DWORD dwAccBytes;
	WriteFile(hFile, filedata, size , &dwAccBytes, NULL);
	SetFilePointer(hFile,size,0,FILE_BEGIN);
	SetEndOfFile(hFile);
	FlushFileBuffers(hFile);
	//wsprintf(szTitle, szTitle_org, szFile);
	//SetWindowText(hEdit, szTitle);
	if(CloseHandle(hFile) == 0){
		//MB("CloseHandle FAILED");
		 //VISUAL_LASTERROR();
		 return edk_FAILED;
	}
	return edk_SUCCEEDED;
}

/*!
@param filename[in] ファイルネーム 例："sample.txt" 等
@param filedata[in] ファイルのデータ
@param size[in] ファイルのデータのサイズ(バイト単位)
@param GetReadSize[in] 実際に読み込んだサイズ
@return edk_SUCCEEDED以外だったらエラー
@note
GetLastError()でエラー情報を取得できます。<br>
注意：エラーの場合、この戻り値をあまり信用しないで、VISUAL_LASTERROR()等のマクロを使ってみてください。<br>

*/
inline int LoadFile(const char *filename,void *Buff,size_t BuffSize,DWORD *GetReadSize)
{
	HANDLE hFile;
	DWORD dwSize;//ファイルサイズ
    DWORD dwAccBytes;//実際に読み込んだバイトサイズ？

	hFile = CreateFile(filename, GENERIC_READ, 0, 0, //OPEN_ALWAYS,
		OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, NULL);
  if(INVALID_HANDLE_VALUE==hFile){
		//VISUAL_LASTERROR();
		return edk_FileNotFound;
	}
	dwSize = ::GetFileSize(hFile, NULL);
    
  SetFilePointer(hFile, 0, 0, FILE_BEGIN);

  ReadFile(hFile, Buff, dwSize, &dwAccBytes, NULL);
	*GetReadSize = dwAccBytes;
    if(CloseHandle(hFile) == 0){
		 //ODS("CloseHandle FAILED");
		 //VISUAL_LASTERROR();
		return edk_FAILED;
	}
	return edk_SUCCEEDED;
}
	

/*!
	☆CDのボリュームラベル検索:<br>
	任意のボリュームラベルを持つＣＤを検索します。<br>
@param		*pLabel[in]	: 検索するボリュームラベル
@param		*pPath[in]		: 検索対象のボリュームラベルを持つドライブの格納先

@return				: 成功 true / 失敗 false
*/
inline bool CheckCDVolumeLabel( char *pLabel, char *pPath ,size_t pPathSize)
{
	// 全ドライブ検索
	for ( char i = 'A'; i <= 'Z'; i++ )
	{
		char Drive[8];
		_snprintf( Drive,8, "%c:\\", i );

		// CD-ROM発見
		if ( ::GetDriveType( Drive ) == DRIVE_CDROM )
		{
			unsigned long SerialNo;
			unsigned long MaximumComponentLength;
			unsigned long FileSystemFlag;
			char FileSystemName[256];
			char szVolumeLabel[256] = "NO CDROM";

			 //ボリュームラベル取得
			::GetVolumeInformation(
					Drive,
					szVolumeLabel,
					512,
					&SerialNo,
					&MaximumComponentLength,
					&FileSystemFlag,
					FileSystemName,
					512 );
			if ( !strcmp( pLabel, szVolumeLabel ) )
			{
				strncpy( pPath, Drive ,pPathSize);
				return true;
			}
		}
	}

	return false;
}
/*!
☆ファイルコピー:<br>
	ファイルコピーを行います。<br>
	ファイル属性が通常になりますので、
	CDからコピーされた場合は読取専用が
	解除されます。<br>
@param	*pSrc[in]	: コピー元
@param	*pDst[in]	: コピー先
@param bRewrite[in] trueだと、上書きします。
@return : 成功 true / 失敗 false
*/
inline bool CopyFileFromCD( LPCTSTR pSrc, LPCTSTR pDst ,bool bRewrite=false){
	//	 コピー
  if ( ::CopyFile( pSrc, pDst, !(bRewrite) ) )
	{
	// ファイル属性を通常にする
      return (::SetFileAttributes( pDst, FILE_ATTRIBUTE_NORMAL ) != false);
  }
  return false;
}


/*
typedef int (WINAPI *DISKCOPYRUNDLL)(LPSTR,LPSTR,LPSTR,LPSTR);

HINSTANCE hLib = (HINSTANCE)LoadLibrary("DISKCOPY.DLL");

DISKCOPYRUNDLL pDiskCopyRunDll = (DISKCOPYRUNDLL)GetProcAddress(hLib,"DiskCopyRunDll");

// "1" == B:ドライブを選択 
pDiskCopyRunDll(0,0,(LPSTR)"1",0); 

FreeLibrary(hLib);
*/
inline bool CheckDrive(BYTE c){
	DWORD drive = ::GetLogicalDrives();
	if(!isAlpha(c)) throw std::invalid_argument("文字定数入れろっツーの！");
	c =(BYTE) tolower((int)c);
	c -= 'a';
	DWORD mask =(DWORD)pow(2,c);
	if(drive & mask){
		return true;
	}
	return false;
}

inline void GetMemoryFreeSpace(DWORD *total_byte,DWORD *free_byte){
	MEMORYSTATUS MemState = { sizeof(MEMORYSTATUS) };
	::GlobalMemoryStatus( &MemState );
	
	*total_byte = MemState.dwTotalPhys;
	*free_byte = MemState.dwAvailPhys ;
}

class CSpaceGet{
public:
	CSpaceGet(){}
	virtual ~CSpaceGet(){}
	enum byte_flag{
		eByte = 0,eKB,eMB,eGB,
	};
	double collect(double t,byte_flag f){
		switch(f){
		case eByte:
			return t;
		case eKB:
			return t / 1024;
		case eMB:
			return t / 1024 / 1024;
		}
		return t / 1024 / 1024 / 1024;
	}
	double getTotalMemory(byte_flag f){
		DWORD t,a;
		GetMemoryFreeSpace(&t,&a);
		return collect(t,f);
	}
	double getFreeMemory(byte_flag f){
		DWORD t,a;
		GetMemoryFreeSpace(&t,&a);
		return collect(a,f);
	}
	/*
	double getFreeDisk
		


inline bool GetDiskFreeSpace
BOOL GetDiskFreeSpace(

  LPCTSTR lpRootPathName, // pointer to root path

  LPDWORD lpSectorsPerCluster, // pointer to sectors per cluster

  LPDWORD lpBytesPerSector, // pointer to bytes per sector

  LPDWORD lpNumberOfFreeClusters,

                             // pointer to number of free clusters

  LPDWORD lpTotalNumberOfClusters 

                             // pointer to total number of clusters

);
*/

};




}//end of dkutil namespace



#endif
