//	Roast+ License

/*

	CFileBase
*/
#ifndef __SFJP_OPENMGL_roast_mxp_File_H__
#define __SFJP_OPENMGL_roast_mxp_File_H__

#include "roast/_common.hpp"
#include "roast_file.h"
#include <vector>
#include <string>

//#include "roast/file/file_win32.hpp"


_ROAST_NS_START

///////////////////////////////////////////////////

/*	ファイルの存在有無を調べる
//	ret:  ROAST_TRUE:存在  /  ROAST_FALSE:存在しない	*/
inline bool exist_file( const char* filename ){
	return ROAST_BOOL2bool( ::roast_exist_file(filename) );
}
/*	is_can_read	*/
inline bool is_can_read( const char* filename ){
	return ROAST_BOOL2bool( ::roast_canread(filename) );
}
/*	is_can_write */
inline bool is_can_write( const char* filename ){
	return ROAST_BOOL2bool( ::roast_canwrite(filename) );
}
/*	is_can_exec	*/
inline bool is_can_exec( const char* filename ){
	return ROAST_BOOL2bool( ::roast_canexec(filename) );
}
/*	set_read_only  */
inline bool set_read_only( const char* filename )
{
	/* TODO */
	return false;
}


/*	is_directory	*/
inline bool is_directory( const char* filename ){
	return ROAST_BOOL2bool( ::roast_is_directory(filename) );
}
inline bool IsDirectory( const char* filename ){
	return ROAST_BOOL2bool( ::roast_is_directory(filename) );
}
inline bool IsDirectoryEx( const char* filename, ROAST_BOOL *pbRetIs ){
	return ROAST_BOOL2bool( ::roast_is_directory_ex(filename, pbRetIs) );
}
/*	is_file	*/
inline bool is_file( const char* filename ){
	return ROAST_BOOL2bool( ::roast_is_file(filename) );
}
inline bool IsFile( const char* filename ){
	return ROAST_BOOL2bool( ::roast_is_file(filename) );
}
inline bool IsFileEx( const char* filename, ROAST_BOOL *pbRetIs ){
	return ROAST_BOOL2bool( ::roast_is_file_ex(filename, pbRetIs) );
}


/*	filesize	*/
inline long filesize( const char* filename ){
	return roast_filesize(filename);
}
/*	get_filesize	*/
inline long get_filesize( const char* filename ){
	return roast_filesize(filename);
}


/*	roast_mkdir	*/
/*	※引数modeはLinuxの場合でのみ有効。	*/
/*inline bool mkdir( const char* filename, unsigned long mode = 0744 )
{
	return ROAST_BOOL2bool( ::roast_mkdir(filename, mode) );
}*/
inline bool create_directory( const char* filename, unsigned long mode = 0744 )
{
	return ROAST_BOOL2bool( ::roast_mkdir(filename, mode) );
}

///////////////////////////////////////////////////////////

//	リネーム
inline bool rename_file(const char* from, const char* to){
	return ROAST_BOOL2bool( ::roast_rename_file( from, to ) );
}

//	削除
inline bool del_file( const char* filename ){
	return ROAST_BOOL2bool( ::roast_del_file( filename ) );
}

//	コピー
inline bool copy_file( const char* from, const char* to ){
	return ROAST_BOOL2bool( ::roast_copy_file( from, to ) );
}

//	移動
inline bool move_file( const char* from, const char* to ){
	return ROAST_BOOL2bool( ::roast_move_file( from, to ) );
}

///////////////////////////////////////////////////////////
//	読み書き

//	書き込み
inline bool write_file( const char* filename, unsigned char* membuf, unsigned int length){
	return ROAST_BOOL2bool( ::roast_write_file( filename, membuf, length ) );
}

//	追記書き込み
inline bool append_file( const char* filename, unsigned char* membuf, unsigned int length){
	return ROAST_BOOL2bool( ::roast_append_file( filename, membuf, length ) );
}

//	読み込み
inline unsigned char* read_file( const char* filename ){
	return roast_read_file_alloc( filename );
}
inline unsigned char* read_file( const char* filename, unsigned char* membuf, unsigned int length){
	return roast_read_file( filename, membuf, length );
}



/*********************************************************************/

//	パス関連

/*	\や/の連続を無くす	*/
inline char* DeleteRedundancyFileSep( char *szStr, unsigned int nStrBufSize ){
	return RoastDeleteRedundancyFileSep( szStr, nStrBufSize );
}

/*	.\だとか..\だとかそういうのを処理する	*/
inline char* fix_path( char* path, unsigned int bufsize ){
	return roast_fix_path( path, bufsize );
}

/*	ファイルパス区切り文字が付いていなかったら自動的に付加する	*/
inline char* auto_append_filesep( char* path, unsigned int bufsize ){
	return roast_auto_append_filesep( path, bufsize );
}

/*	フルパスを取得	*/
/*	./や../等も処理される	*/
inline const char* get_fullpath( const char* filename, char* fullpathout, unsigned int bufsize ){
	return roast_fullpath( filename, fullpathout, bufsize );
}
inline const char* get_full_path( const char* filename, char* fullpathout, unsigned int bufsize ){
	return roast_fullpath( filename, fullpathout, bufsize );
}
inline const char* GetFullPath( const char* filename, char* fullpathout, unsigned int bufsize ){
	return roast_fullpath( filename, fullpathout, bufsize );
}


/////////////////////////////////////////////////////////////////
//	ファイルリスト取得


//	GetFileList()のフラグ群

//#define ROAST_FL_INC_SUBDIR	(0x01)
#define ROAST_FL_RECURSIVE		(0x01)
//#define ROAST_FL_NO_SUBDIR	(0x00)
#define ROAST_FL_NO_RECURSIVE	(0x00)
#define ROAST_FL_TOPDIRONLY		(0x00)

#define ROAST_FL_INCDIR			(0x02)
#define ROAST_FL_NO_INCDIR		(0x00)

#define ROAST_FL_INCFILE		(0x04)
#define ROAST_FL_NO_INCFILE		(0x00)


#define ROAST_FL_ALLFILES		(0x02)	//	??

#define ROAST_FL_DEFAULT		(ROAST_FL_NO_RECURSIVE | ROAST_FL_INCDIR | ROAST_FL_INCFILE)


//bool GetFileList( std::vector<std::string> &fileListOut, const char* szTargetDir, unsigned long flags = ROAST_FL_TOPFILEONLY | ROAST_FL_NO_INCDIR | ROAST_FL_NO_SUBDIR);
bool GetFileList( std::vector<std::string> &fileListOut, const char* szTargetDir, unsigned long flags = ROAST_FL_DEFAULT );

class CFile;
bool GetFileList( std::vector<roast::CFile> &fileListOut, const char* szTargetDir, unsigned long flags = ROAST_FL_DEFAULT );



/// ドライブ関連 /////////////////////

bool GetDriveList( std::vector<std::string> &fileListOut);
//int GetDriveType(char cDrvie);
inline int GetDriveType(const char* szPath){
	return roast_get_drive_type(szPath);
}

///////////////////////////////////////////////////


//	CFileBase
class CFileBase
{
public:
	enum {
		DIR_SEP_LIN = '/',
		DIR_SEP_WIN = '\\'
	};

protected:
	std::string m_strFilePath;

public:
	//	コンストラクタ
	CFileBase(){};
	CFileBase(const char* szFilePath){ SetFilePath(szFilePath); }
	CFileBase(const std::string &s){ SetFilePath(s.c_str()); }
	CFileBase(const CFileBase &file){ operator = (file); }
	CFileBase(const CFileBase &parent, const char* szChild){/*******/};

	//	デストラクタ
	virtual ~CFileBase(){ /*Fclose();*/ }


	///////////////////////////////////////////////////////////
	//	ファイルパスの取得と設定

	CFileBase& operator = (const char* szFilePath){
		SetFilePath(szFilePath);
		return *this;
	}
	CFileBase& operator = (const CFileBase &file){
		//SetFilePath(file.GetFilePath());
		Set(&file);
		return *this;
	}

	void SetFilePath(const char* szFilePath){
		m_strFilePath = szFilePath;
	}

	const char* GetFilePath() const { return m_strFilePath.c_str(); }	//	2009/09/12  STL(vectorとか)のためにconst宣言にしたよ
	const char* GetFullPath() const { return m_strFilePath.c_str(); }	//	2009/09/12  STL(vectorとか)のためにconst宣言にしたよ

	void Set(const CFileBase *pFile){
		SetFilePath(pFile->GetFilePath());
	}

	///////////////////////////////////////////////////////

	//	ファイル名だけを取得
	const char* GetFileName(){};

	//	ディレクトリ名だけを取得
	const char* GetDirName(){};
	
	//	ファイルの場合、ディレクトリを取得
	//	ディレクトリの場合、親ディレクトリを取得
	//CFileBase GetParent()=0;
	
	//	ディレクトリパスだけ取得
	const char* GetPath(){}
	const char* GetDirPath(){ return GetPath(); }
	//const char* GetPath(){ return GetPath(); } <= ?

	/*CFileBase operator += (const char* szFilePath){
		CFileBase f;
		f.
	}*/

	///////////////////////////////////////////////////////////
	//	ユーティリティ


	//	ディレクトリか？ファイルか？
	virtual bool IsDirectory()=0;
	bool IsDir(){ return IsDirectory(); }
	bool IsFile(){ return IsDirectory() ? false : true; }
	
	//	存在しているか？
	virtual bool IsExist()=0;
	
	//	読める？書き込める？
	virtual bool IsCanRead()=0;
	bool IsReadable(){ return IsCanRead(); }
	virtual bool IsCanWrite()=0;
	bool IsWriteable(){ return IsCanWrite(); }
	
	//	権限変更
	virtual bool SetReadOnly()=0;
	bool SetReadonly(){ return SetReadOnly(); }
	bool DisableWriteable(){ return SetReadOnly(); }

	//	ファイル or ディレクトリの作成
	virtual bool CreateFile(const char* szFileName=NULL)=0;
	bool Create(const char* szFileName=NULL){ return CreateFile(szFileName); }
	virtual bool CreateDirectory(const char* szDirName=NULL)=0;
	bool CreateDir(const char* szDirName=NULL){ return CreateDirectory(szDirName); }
	
	//	ファイルサイズ取得
	virtual long GetFileSize()=0;
	long GetSize(){ return GetFileSize(); }
	long Size(){ return GetFileSize(); }
	long size(){ return GetFileSize(); }
	
	//virtual int64 GetFileSize64()=0;
	//int64 GetSize64(){ return GetFileSize(); }
	//int64 Size64(){ return GetFileSize(); }
	//int64 size64(){ return GetFileSize(); }
	
	//	名前変更
	virtual bool Rename(const char* szNewName)=0;
	bool ChName(const char* szNewName){ return Rename(szNewName); }
	bool ChangeName(const char* szNewName){ return Rename(szNewName); }
	
	//	削除
	virtual bool Delete()=0;
	bool Del(){ return Delete(); }
	bool Remove(){ return Delete(); }
	
	//	コピー
	virtual bool Copy(const char* szCopyTo)=0;
	bool Copy(CFileBase &copyTo){ return Copy(copyTo.GetFilePath()); }
	
	//	移動
	virtual bool Move(const char* szMoveTo)=0;
	bool Move(CFileBase &moveTo){ return Move(moveTo.GetFilePath()); }
	
	
	///////////////////////////////////////////////////////////
	//	読み書き
	
	//	書き込み
	virtual bool WriteFile(unsigned char* membuf, unsigned int length)=0;
	bool Write(unsigned char* membuf, unsigned int length){ return WriteFile(membuf,length); }
	bool WriteMem(unsigned char* membuf, unsigned int length){ return WriteFile(membuf,length); }
	bool WriteMemory(unsigned char* membuf, unsigned int length){ return WriteFile(membuf,length); }
	bool WriteString(char* str){ return WriteFile((unsigned char*)str, strlen(str)); }
	
	//	追記書き込み
	virtual bool AppendFile(unsigned char* membuf, unsigned int length)=0;
	bool Append(unsigned char* membuf, unsigned int length){ return AppendFile(membuf,length); }
	bool AppendMem(unsigned char* membuf, unsigned int length){ return AppendFile(membuf,length); }
	bool AppendMemory(unsigned char* membuf, unsigned int length){ return AppendFile(membuf,length); }
	bool AppendString(char* str){ return AppendFile((unsigned char*)str, strlen(str)); }
	
	//	読み込み
	virtual unsigned char* ReadFile()=0;
	virtual unsigned char* ReadFile(unsigned char* membuf, unsigned int length)=0;
	unsigned char* Read(){ return ReadFile(); }
	unsigned char* Read(unsigned char* membuf, unsigned int length){ return ReadFile(membuf,length); }
	
	
	///////////////////////////////////////////////////////////
	//	標準入出力
	
	virtual FILE* Fopen(const char* szMode)=0;
	FILE* FOpen(const char* szMode){ return Fopen(szMode); }
	FILE* fopen(const char* szMode){ return Fopen(szMode); }
	//FILE* Open(){ return Fopen(); }
	
	virtual int Fclose()=0;
	int FClose(){ return Fclose(); }
	int fclose(){ return Fclose(); }
	//int Close(){ return Fclose(); }
};

///////////////////////////////////////////////////
//##################################################
///////////////////////////////////////////////////

class CFile : public CFileBase
{
protected:
	FILE* m_fp;
private:
	void _Init(){ m_fp = NULL; }
public:
	//	コンストラクタ
	CFile()/* : CFileBase()*/{ _Init(); };
	CFile(const char* szFilePath) : CFileBase(szFilePath){ _Init(); };
	CFile(const std::string &s) : CFileBase(s){ _Init(); };
	CFile(const CFile &file) : CFileBase(file){ _Init(); };
	CFile(const CFile &parent, const char* szChild) : CFileBase(parent,szChild){ _Init(); };

	//	デストラクタ
	virtual ~CFile(){ Fclose(); }
	
	///////////////////////////////////////////////////////

	CFile operator + (const char* szName){
		return CFile( m_strFilePath + szName );
	}

	CFile& operator = (const roast::CFile &file)
	{
		CFileBase::Set(&file);
		return *this;
	}

	///////////////////////////////////////////////////////
	
	CFile GetParent(){ 
		//const char* p_fullpath = GetFilePath();
		const char* p_fullpath = m_strFilePath.c_str();
		size_t len_fullpath = strlen(p_fullpath);
		char *work_buf = (char*)malloc( len_fullpath+1 );
		char* p = work_buf + len_fullpath - 2;

		memcpy(work_buf, p_fullpath, len_fullpath+1);
		for(; p != work_buf; p--)
		{
			if ( *p == DIR_SEP_LIN || *p == DIR_SEP_WIN ){
				*(p+1) = '\0';
				break;
			}
		}

		CFile f;
		if ( p == work_buf )
			f = CFile("");
		else
			f = CFile(work_buf);

		free(work_buf);

		return f;
	}


	CFile GetChild(const char* szName){
		return CFile( m_strFilePath + ROAST_DIR_SEP_CHAR + szName );
	}

	bool GetChildList(std::vector<roast::CFile> &fileListOut, unsigned long flags = ROAST_FL_DEFAULT){
		return roast::GetFileList(fileListOut, GetFilePath(), flags);
	}

	bool GetChildListVctStr(std::vector<std::string> &fileListOut, unsigned long flags = ROAST_FL_DEFAULT){
		return roast::GetFileList(fileListOut, GetFilePath(), flags);
	}

	/////////////////////////////////////////////////////

	enum {
		UNKNOWN_DRIVE = ROAST_DRIVE_TYPE_UNKNOWN,
		FIXED_DRIVE = ROAST_DRIVE_TYPE_FIXED,
		REMOVABLE_DRIVE = ROAST_DRIVE_TYPE_REMOVABLE,
		CDROM_DRIVE = ROAST_DRIVE_TYPE_CDROM,
		RAMDISK_DRIVE = ROAST_DRIVE_TYPE_RAMDISK,
		REMOTE_DRIVE = ROAST_DRIVE_TYPE_REMOTE
	};
	enum {
		HD_DRIVE = ROAST_DRIVE_TYPE_HDD,
		NETWORK_DRIVE = ROAST_DRIVE_TYPE_NETWORK
	};

	bool static GetDriveList(std::vector<std::string> &fileListOut){
		return roast::GetDriveList(fileListOut);
	}

	bool static GetDriveList(std::vector<roast::CFile> &fileListOut)
	{
		std::vector<std::string> vsFileListOut;
		if ( roast::GetDriveList(vsFileListOut) != true )
			return false;

		for(unsigned int i=0; i<vsFileListOut.size(); i++)
		{
			fileListOut.push_back(roast::CFile(vsFileListOut[i]));
		}
		return true;
	}

	int GetDriveType(){ return roast::GetDriveType( GetFilePath() ); }


	///////////////////////////////////////////////////////
	//	implements

	//	ディレクトリか？ファイルか？
	bool IsDirectory(){ return roast::is_directory( GetFilePath() ); }
	
	//	存在しているか？
	bool IsExist(){ return roast::exist_file( GetFilePath() ); }

	//	読める？書き込める？
	virtual bool IsCanRead(){ return roast::is_can_read( GetFilePath() ); }
	virtual bool IsCanWrite(){ return roast::is_can_write( GetFilePath() ); }
	
	//	権限変更
	virtual bool SetReadOnly(){ return roast::set_read_only( GetFilePath() ); }

	//	ファイル or ディレクトリの作成
	virtual bool CreateFile(const char* szFileName=NULL){ return false; /* TODO */ }
	virtual bool CreateDirectory(const char* szDirName=NULL){ return roast::create_directory( GetChild(szDirName).GetFullPath() ); }
	
	//	ファイルサイズ取得
	virtual long GetFileSize(){ return roast::get_filesize( GetFilePath() ); }

	//	名前変更
	virtual bool Rename(const char* szNewName){ return roast::rename_file( GetFilePath(), szNewName ); }
	
	//	削除
	virtual bool Delete(){ return roast::del_file( GetFilePath() ); }
	
	//	コピー
	virtual bool Copy(const char* szCopyTo){ return roast::copy_file( GetFilePath(), szCopyTo ); }
	
	//	移動
	virtual bool Move(const char* szMoveTo){ return roast::move_file( GetFilePath(), szMoveTo ); }
	
	
	///////////////////////////////////////////////////////////
	//	読み書き
	
	//	書き込み
	virtual bool WriteFile(unsigned char* membuf, unsigned int length){ return roast::write_file( GetFilePath(), membuf, length ); }
	
	//	追記書き込み
	virtual bool AppendFile(unsigned char* membuf, unsigned int length){ return roast::append_file( GetFilePath(), membuf, length ); }
	
	//	読み込み
	virtual unsigned char* ReadFile(){ return roast::read_file( GetFilePath() ); }
	virtual unsigned char* ReadFile(unsigned char* membuf, unsigned int length){ return roast::read_file( GetFilePath(), membuf, length ); }

	
	///////////////////////////////////////////////////////////
	//	標準入出力
	
	virtual FILE* Fopen(const char* szMode){
		m_fp = ::fopen(GetFilePath(), szMode);
		return m_fp;
	}
	
	virtual int Fclose(){
		int ret = 0;
		if ( m_fp != NULL ){
			ret = ::fclose(m_fp);
			m_fp = NULL;
		}
		return ret;
	}
};

///////////////////////////////////////////////////


_ROAST_NS_END


///////////////////////////////////////////////////



//	typedefs
typedef roast::CFileBase CRoastFileBase;
typedef roast::CFile CRoastFile;




#endif//__SFJP_OPENMGL_roast_mxp_File_H__
