#ifndef _dkutil_Shell__
#define _dkutil_Shell__


/*!
@note
参考サイト,文献
<ul>
<li>
らく氏の
<a href="http://www.geocities.co.jp/SiliconValley-SanJose/9190/">
Cx+
</a>-> C++ ライブラリ

</ul>

*/
#include "dkutilStdio.h"
#include "dkutilCommonControl.h"

#ifdef USE_DKINGYO_SHELL_AND_COMMON_CONTROL






#if DKUTIL_MSVC_MODE
#	pragma comment(lib,"shell32")
#	pragma comment(lib,"shlwapi") 
#endif

namespace dkutil{


/*!
☆デスクトップフォルダパス取得:デスクトップフォルダのパスを取得します。
	@param	 *pPath[out]			: デスクトップフォルダを受け取る文字列ポインタ
	@return: 成功 true / 失敗 false
*/
extern bool GetDesktopFolder( char *pPath );

/*!
☆ショートカット生成:ショートカットを生成します。
@param *pShortcutFile[in]		: 作成する[*.lnk]のフルパス名
@param *pDescription[in]		: ディスクリプション名
@param *pTargetFile[in]		: リンク元のファイルのフルパス名
@return		: 成功 true / 失敗 false
*/
extern bool CreateLinkFile( char *pShortcutFile, char *pDescription, char *pTargetFile );
	

#if 0
/*!
@param CONTAINER[in] std::list<WIN32_FIND_DATA>互換コンテナをぶち込む
普通はtypedefされている　FileFinderを使ってください。<br>
FileFinderBase<>みたいなかっちょわりぃ書き方したくないですし^^;<br>
まぁ、CONTAINERが変更できるってのがいいかなぁと思ったので、（そんなにメリットはないと思いますが。)<br>
@note
2003/10/18<br>
このクラスは廃止しました。今後はfile_finder_baseをお使いください。<br>

*/
template<class CONTAINER=std::list<WIN32_FIND_DATA> >
class FileFinderBase{
protected:
	FileFinderBase(const FileFinderBase&);
	FileFinderBase& operator =(const FileFinderBase&);


	CONTAINER mDataList;
	
	
	std::string mDir;
	TCHAR mTmp[MAX_PATH + MAX_PATH];
public:
	typedef CONTAINER::iterator iterator;
	
	FileFinderBase(){
		mDir.clear();
		mDataList.clear();
		
		{
			char tmp[MAX_PATH];
			::GetCurrentDirectory(sizeof(tmp),tmp);
			mDir = tmp;
		}
		NULL_CHAR_ARRAY(mTmp);
	}
	virtual ~FileFinderBase(){
		Release();
	}
	///すべてを開放し、初期値にする。しかし、またFindを呼び出すことが出来る。
	void Release(){
		mDir.clear();
		mDataList.clear();
		NULL_CHAR_ARRAY(mTmp);
		{
			char tmp[MAX_PATH];
			::GetCurrentDirectory(sizeof(tmp),tmp);
			mDir = tmp;
		}
	}
	///@return 内部で使われているstd::list<WIN32_FIND_DATA>互換コンテナの参照を返す。
	CONTAINER &GetContainer(){return mDataList;}
	///STLでおなじみのbeginと同じ
	iterator begin(){return mDataList.begin();}
	///STLでおなじみのendと同じ
	iterator end(){return mDataList.end();}
	///ディレクトリを設定する。
	void SetDirectory(char *dir){
		mDir = dir;
	}
	///今、このクラスで使われているディレクトリを得る。
	const char *GetDirectory()const{return mDir.c_str();}
	/*!
	@param filename[in] 見つけるファイル名（ワイルドカード可 例:*.htmlとか)
	@param set_directory[in] SetDirectoryに入れるのと同じ。
	@return edk_SUCCEEDEDなら成功！
	*/
	///指定のファイル見つける処理　前の処理結果は消える
	int Find(const char *filename,const char *set_directory=NULL){
		int result;
		bool ChangedDir = false;//Directoryを変更したかどうか？フラグ
		result = edk_FAILED;

		//ディレクトリセット
		{
			{
				int r;
				r = GetCurrentDirectory(sizeof(mTmp),mTmp);
				if(r == 0){
					goto end;
				}
			}
			//ディレクトリチェンジ
			if(set_directory){
				SetCurrentDirectory(set_directory);
				mDir = set_directory;
			}else if(!mDir.empty()){
				SetCurrentDirectory(mDir.c_str());
			}else{
				//SetCurrentDirectory(mTmp);
			}
			//フラグ立てとく
			ChangedDir = true;
		}

		//前検索したリストは削除する
		mDataList.clear();

		
		result = FindLogic(filename);
	end:
		//変更したディレクトリは元に戻す
		if(ChangedDir){	SetCurrentDirectory(mTmp);}
		return result;
	}

private:
	bool isFolder(WIN32_FIND_DATA &FindFileData){
		return (
			FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
			&& strcmp(FindFileData.cFileName,"..")!=0 
			&& strcmp(FindFileData.cFileName,".")!=0
			);
	}
	int FindLogic(const char *filename){
		int result = edk_FAILED;
		//探す
		{
			char subpath[_MAX_PATH]="";
			char temp[_MAX_PATH]="";
			dkstrcpy2(temp,sizeof(temp),filename,strlen(filename));
			
			WIN32_FIND_DATA FindFileData;
			HANDLE hFind = FindFirstFile(filename, &FindFileData);
			
			//temp[strlen(temp)-1]='\0';//*を消している

			if(hFind != INVALID_HANDLE_VALUE){
				do{
					mDataList.push_back(FindFileData);
					if(isFolder(FindFileData))
					{
						dksprintf(subpath,sizeof(subpath),"%s%s\\",temp,FindFileData.cFileName);
						return FindLogic(subpath);
					}

					if(0==FindNextFile(hFind, &FindFileData)){
						break;
					}
				} while(true);
				FindClose(hFind);
				result = edk_SUCCEEDED;
			}
			else{
				VISUAL_LASTERROR();
			}
		}
		return result;
	}
public:
	/*
	@param ptr[out] バッファへのポインタ
	@para size[in] size[in] ptrのサイズ
	@param it[in] begin()等でiteration中のiteratorとか
	@note
	これらのiteratorが使われている関数は
	TestFileFind()内を見ると良く分かるだろう。<br>
	*/
	bool GetFilePath(char *ptr,size_t size,iterator &it,LPTSTR directory=NULL) const
	{
		if(directory==NULL){
			directory = const_cast<char *>(GetDirectory());
		}
		//この関数ってあぶなくね？
		PathCombine((LPTSTR)mTmp, directory, (*it).cFileName);
		return DKUTIL_SUCCEEDED(dkstrcpy(ptr,size,mTmp,strlen(mTmp)));
	}

	/*!
	@param it[in] 例によってiteratorをぶち込んで！
	@return ファイルの名前へのポインタ？
	*/
	///DESCRIPTION: Retrieves the filename of the file found.
	const char * GetFileName(iterator &it) const
	{
		return (*it).cFileName;
	}
	/*!
	@param ptr[out] バッファへのポインタ
	@param size[in] ptrのサイズ
	@param it[in] 例のいてれーたん
	*/
	///DESCRIPTION: Retrieves the title of the file found.
	bool GetFileTitle(char *ptr,size_t size,iterator &it) const
	{
		//std::string str = GetFileName();
		NULL_CHAR_ARRAY(mTmp);
		
		{
			char *p = (*it).cFileName;
			dkstrcpy((char *)mTmp,sizeof(mTmp),p,strlen(p));
		}

		if(!IsDots(it))
		{
			//PathRemoveExtension(str.GetBuffer(0));
			//str.ReleaseBuffer();
			PathRemoveExtension((LPTSTR)mTmp);
		}
		int r = dkstrcpy(ptr,size,mTmp,sizeof(mTmp));

		return DKUTIL_SUCCEEDED(r);
	}
	BOOL MatchesMask(iterator &it,DWORD dwMask) const
	{
		return ((*it).dwFileAttributes & dwMask);
	}
	///Dotsか！？
	BOOL IsDots(iterator &it) const
	{
		if(IsDirectory(it))
		{
			return PathIsDots((*it).cFileName);
		}
		return FALSE;
	}
	///@return RootDirectoryを返す,ってかGetDirectory()のラッパ〜
	///DESCRIPTION: Retrieves the root directory of the file found.
	const char * GetRoot() const
	{
		return GetDirectory();
	}

	/*!
	@param ptr[out] 例のバッファ先
	@param size[in] ptrのサイズ
	@param it[in] 例のイテレータン（iterator)
	*/
	///file://をつけてptrにぶち込む
	///DESCRIPTION: Retrieves the URL of the file found.
	bool GetFileURL(char *ptr,size_t size,iterator &it) const
	{
		NULL_CHAR_ARRAY(mTmp);
		GetFilePath((char *)mTmp,sizeof(mTmp),it);
		dksprintf((char *)ptr,size,_T("file://"));
		int r = dkstrcat2(ptr,size,mTmp);
		return DKUTIL_SUCCEEDED(r);
	}
	inline BOOL IsReadOnly(iterator it)   const { return MatchesMask(it,FILE_ATTRIBUTE_READONLY); }
	inline BOOL IsDirectory(iterator &it)  const { return MatchesMask(it,FILE_ATTRIBUTE_DIRECTORY); }
	inline BOOL IsCompressed(iterator &it) const { return MatchesMask(it,FILE_ATTRIBUTE_COMPRESSED); }
	inline BOOL IsSystem(iterator &it)     const { return MatchesMask(it,FILE_ATTRIBUTE_SYSTEM); }
	inline BOOL IsHidden(iterator &it)     const { return MatchesMask(it,FILE_ATTRIBUTE_HIDDEN); }
	inline BOOL IsTemporary(iterator &it)  const { return MatchesMask(it,FILE_ATTRIBUTE_TEMPORARY); }
	inline BOOL IsNormal(iterator &it)     const { return MatchesMask(it,FILE_ATTRIBUTE_NORMAL); }
	inline BOOL IsArchived(iterator &it)   const { return MatchesMask(it,FILE_ATTRIBUTE_ARCHIVE); }
	///it先のファイルサイズを返す。
	inline ULONGLONG GetFileSize(iterator &it) const {
		return ((*it).nFileSizeLow + 
			((*it).nFileSizeHigh << 32));
	}
	BOOL PathIsDots(LPCTSTR lpszPath) const
	{
		if(*lpszPath == _T('.'))
		{
			switch(*(lpszPath + 1))
			{
				case _T('.'):
					if(*(lpszPath + 2))
					{
						break;
					}

				case _T('\0'):
					return TRUE;
			}
		}

		return FALSE;
	}
};

typedef FileFinderBase<> FileFinder ;

#endif //end of if 0





}//end of dkutil namespace



#endif//end of USE_DKINGYO_SHELL_AND_COMMON_CONTROL


#endif//end of include once