
#ifndef DKUTIL_GUI_WIN32_DIALOG_H
#define DKUTIL_GUI_WIN32_DIALOG_H

#include <dkutil/scoped_buffer.hpp>
#include <dkutil/gui/win32/CommonControl.h>
#include <dkutil/boost/parm_string.hpp>
#include <dkutil/parser/string_util.hpp>
#include <dkutil/dll.hpp>

//for win32...
#include <commdlg.h>


namespace dkutil{
	


///☆カラー選択ダイアログカラー選択ダイアログを開き色の取得をします。

inline bool OpenColorDialog(COLORREF *GetAndSetColor,HWND WindowHandle=NULL)
{
	COLORREF GetColor = *GetAndSetColor;
	COLORREF SetColor = *GetAndSetColor;

	CHOOSECOLOR cc = {
		sizeof(CHOOSECOLOR),
		WindowHandle,
		NULL,
		GetColor,
		&SetColor,
		CC_FULLOPEN,
	};
	//ダイアログを開く
	if ( !::ChooseColor( &cc ) ) return false;
	//選択されたと思われるカラーを入れる
	*GetAndSetColor = cc.rgbResult;

	return true;

}


/*!
@param	 *pR[out]	: 赤色格納先アドレス
@param	 *pG[out]	: 緑色格納先アドレス
@param	 *pB[out]	: 青色格納先アドレス
@param WindowHandle[in] Windowのハンドル。（無い場合はNULLでOK
@param 成功 true / 失敗 false
*/
///COLORREF構造体版のWrapper
inline  bool OpenColorDialog( long *pR, long *pG, long *pB ,HWND WindowHandle=NULL)
{
	COLORREF color=RGB(*pR,*pG,*pB);
	bool r = OpenColorDialog(&color,WindowHandle);
	*pR = (color>>16) & 0xFF;
	*pG = (color>> 8) & 0xFF;
	*pB = (color>> 0) & 0xFF;
	return r;
}




///RGUTRIPLE版OpenColorDialog･･･
inline bool OpenColorDialog(RGBTRIPLE *color_tag,HWND WindowHandle=NULL){
	if(NULL==color_tag) return false;
	long r=0,g=0,b=0;
	bool result = OpenColorDialog(
		&r,
		&g,
		&b,
		WindowHandle);
	color_tag->rgbtRed = (BYTE)r;
	color_tag->rgbtGreen = (BYTE)g;
	color_tag->rgbtBlue = (BYTE)b;
	return result;
}
///RGUQUAD版OpenColorDialog･･･実際、Alpha値を取れるかは誰も知らない･･･
inline bool OpenColorDialog(RGBQUAD *QuadColor,HWND WindowHandle=NULL){
	COLORREF *ptr = (COLORREF *)&QuadColor;
	COLORREF color = *ptr;
	bool r = OpenColorDialog(&color,WindowHandle);
	*ptr = color;
	return r;
}


inline bool ShutDownDialog(){
	DLLManager mgr;
	if(false==mgr.reset("SHELL32.DLL")){
		return false;
	}
	typedef VOID (WINAPI *FUNC_TYPE)(ULONG Reserved);
	FUNC_TYPE SHExitWindowsDialog;
	SHExitWindowsDialog = (FUNC_TYPE)mgr.find(MAKEINTRESOURCE(60));
	if(NULL==SHExitWindowsDialog){
		return false;
	}
	SHExitWindowsDialog(0);
	return true;
}

/*!
☆ファイルオープンダイアログ:ファイルオープンダイアログをだします。
@param	*pPath[out]		: ファイルが格納されるパス
@param size[in] pPathのサイズ。(MAX_PATH以上でないと、falseを返す。
@param	*pTitle[in]: ダイアログのタイトル
@param	*pFilter[in]	: 拡張子の指定 例："text(*.txt)\0*.txt\0All files(*.*)\0*.*\0\0"
"text(*.txt)￥０*.txt￥０All files(*.*)￥０*.*￥０￥０"　<=小文字で￥０を入れてね＾＾；
@param	*pExt[in]		: 拡張子 例："text = テキスト文章"
@param WindowHandle[in] 親ウインドウハンドル。(別にNULLでもOK
@return		: 成功 true / 失敗 false ( ファイルが選択されなかったを含む )
@note
この関数はカレントディレクトリ問題に対応しています。<br>
<b>＊カレントディレクトリ問題。</b><br>
ファイルを開く系のダイアログを表示して、OKを押した際、カレントディレクトリが
変更されてしまい、今まで、fopen("OK.txt");とかやって相対パスで読み込んでいたファイルが
読み込めなくなってしまう現象。

*/
inline bool FileOpenDialog( char *pPath,size_t size, const char *pTitle, const char *pFilter, const char *pExt ,HWND WindowHandle=NULL)
{
	if(pPath == NULL || size < MAX_PATH){
		return false;
	}
	pPath[0] = '\0';

	//今この関数を呼び出しているソフトのディレクトリを保存。
	char path[MAX_PATH];
	memset(path,0,sizeof(path));
	::GetCurrentDirectory(MAX_PATH,path);
	
	// ファイルオープン
	
	OPENFILENAME ofn;
	ZeroMemory( &ofn, sizeof(OPENFILENAME) );
	
	ofn.lStructSize		= sizeof(OPENFILENAME);
	ofn.hwndOwner		= WindowHandle;
	ofn.lpstrTitle		= pTitle;
	ofn.lpstrFilter		= pFilter;
	ofn.nFilterIndex	= 1;
	ofn.lpstrFile		= pPath;
	ofn.nMaxFile		= 256;
	ofn.lpstrDefExt		= pExt;
	ofn.lpstrInitialDir	= NULL;
	ofn.Flags			= OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;

	bool result = (::GetOpenFileName( &ofn ) != false);

	//ディレクトリ設定を戻す
	SetCurrentDirectory(path);

	return result;
}


/*!
☆ファイルオープンダイアログ:ファイルオープンダイアログをだします。

@param	*pPath[out]		: ファイルが格納されるパス
@param size[in] pPathのサイズ(MAX_PATH以上でないとfalseを返します。)
@param	*pTitle[in]	: ダイアログのタイトル
@param	*pFilter[in]	: 拡張子の指定
@param	*pExt[in]		: 拡張子
@param WindowHandle[in] 親ウインドウハンドル。(別にNULLでもOK
@return	bool	: 成功 true / 失敗 false (キャンセルされた場合もfalse)
@note
カレントディレクトリ問題に対応しています。詳しくはFileOpenDialog()にて。
*/
inline bool FileSaveDialog( char *pPath, size_t size,const char *pTitle, const char *pFilter, const char *pExt ,HWND WindowHandle=NULL)
{
	if(pPath==NULL || size < MAX_PATH){
		return false;
	}
	pPath[0] = '\0';
	
	//今この関数を呼び出しているソフトのディレクトリを保存。
	char path[MAX_PATH];
	memset(path,0,sizeof(path));
	::GetCurrentDirectory(MAX_PATH,path);


	OPENFILENAME ofn;
	ZeroMemory( &ofn, sizeof(OPENFILENAME) );
	
	ofn.lStructSize		= sizeof(OPENFILENAME);
	ofn.hwndOwner		= WindowHandle;
	ofn.lpstrTitle		= pTitle;
	ofn.lpstrFilter		= pFilter;
	ofn.nFilterIndex	= 1;
	ofn.lpstrFile		= pPath;
	ofn.nMaxFile		= 256;
	ofn.lpstrDefExt		= pExt;
	ofn.lpstrInitialDir	= NULL;
	ofn.Flags			= OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;

	bool result = (::GetOpenFileName( &ofn ) != false);

	//ディレクトリ設定を戻す
	SetCurrentDirectory(path);

	return result;
}	


///潜在的なバグのある可能性アリ　ヽ(`Д´)ﾉムキィ
class FileSelectDialog{
private:
	void copy_double_null(scoped_buffer &b,const char *double_null_str){
		size_t len = double_null_strlen(double_null_str);
		b.copy(double_null_str, len);
	}
protected:
	std::string mCurrentDirectory;
	std::string mTitle;
	//std::string mFilter;
	scoped_buffer mFilter;
	int mFilterFlag;
	///TRUEならすべて選択できるフィルターもつける。
	bool mPlusAll;
	///選択済みのファイル名
	scoped_buffer mSelected;
public:
	FileSelectDialog(){
		mCurrentDirectory.clear();
		//mTitle = "ファイルを選択してください。";
		mTitle = "Please Select Your File.";
		mFilterFlag = edkfALL;
		mPlusAll = true;
		reset(NULL,mFilterFlag,mTitle.c_str(),mPlusAll);
	}
	//~FileSelectDialog(){}
	bool reset(parm_string current_directory,int flag,
		parm_string title,bool plusall=true)
	{
		if(!current_directory.empty()){
			mCurrentDirectory = current_directory;
		}
		if(!title.empty()){
			mTitle = title;
		}
		return reset(flag,plusall);
	}
	/*!
	@param flga[in] edkFileSignature列挙体のどれかをぶち込む
	@param plusall[in] all *.*拡張子のフィルターもプラスする。
	@return bool型なら分かるでしょう＾＾；；；；
	*/
	bool reset(int flag=edkfALL,bool plusall=true){
		if(flag < edkfALL && flag >= edkfSENTINEL){
			return false;
		}
#ifndef CF
#	define CF const char *
#else
#	error "error... please undef cf"
#endif
		CF all="All files(*.*)\0*.*\0\0";
		CF txt="text files(*.txt)\0*.txt\0\0";
		CF html="HTML files (*.html *.htm)\0*.htm;*.html\0\0";
		CF xml="XML files (*.xml)\0*.xml\0\0";
		CF avi="AVI files (*.avi)\0*.avi\0\0";
		CF mpeg="MPEG files (*.mpeg)\0*.mpg;*.mpeg\0\0";
		CF mov="MOV files (*.mov)\0*.mov\0\0";
		CF wav="WAVE files (*.wav)\0*.wav\0\0";
		CF midi="MIDI files (*.mid)\0*.mid\0\0";
		CF mp3="MP3 files (*.mp3)\0*.mp3\0\0";
		CF ogg="Ogg Vorbis files (*.ogg)\0*.ogg\0\0";
		CF png="PNG files (*.png)\0*.png\0\0";
		CF bmp="BitMap files (*.bmp)\0*.bmp\0\0";
		CF tiff="TIFF files (*.tif *.tiff)\0*.tif;*.tiff\0\0";
		CF jpeg="JPEG files (*.jpg *.jpeg)\0*.jpg;*.jpeg\0\0";
		CF gif="GIF files (*.gif)\0*.gif\0\0";
		CF zip="ZIP files (*.zip)\0*.zip\0\0";
		CF lzh="LZH files (*.lzh)\0*.lzh\0\0";
		CF gz="GZ files (*.gz)\0*.gz\0\0";
		CF gca="GCA files (*.gca)\0*.gca\0\0";
		CF dgc="DGC files (*.dgc)\0*.dgc\0\0";
		CF rar="RAR files (*.rar)\0*.rar\0\0";
#ifdef CF
#	undef CF
#endif
		//std::string filter;
		scoped_buffer filter;
		switch(flag){
		case edkfALL:
			copy_double_null( filter, all );
			break;
		case edkfTXT:	//テキスト系
			copy_double_null(filter , txt );
			break;
		case edkfHTML:
			copy_double_null(filter , html);
			break;
		case edkfXML:
			copy_double_null(filter , xml);
			break;
		case edkfAVI://ムービー系
			copy_double_null(filter , avi);
			break;
		case edkfMPEG:
			copy_double_null(filter , mpeg);
			break;
		case edkfMOV:
			copy_double_null(filter , mov);
			break;
		case edkfWAV://音系
			copy_double_null(filter , wav);
			break;
		case edkfMIDI:
			copy_double_null(filter , midi);
			break;
		case edkfMP3:
			copy_double_null(filter , mp3);
			break;
		case edkfOGG:
			copy_double_null(filter , ogg);
			break;
	
		case edkfPNG://画像系
			copy_double_null(filter , png);
			break;
		case edkfBMP:
			copy_double_null(filter , bmp);
			break;
		case edkfTIFF:
			copy_double_null(filter , tiff);
			break;
		case edkfJPEG:
			copy_double_null(filter , jpeg);
			break;
		case edkfGIF:
			copy_double_null(filter , gif);
			break;
		case edkfZIP://圧縮系
			copy_double_null(filter , zip);
			break;
		case edkfLZH:
			copy_double_null(filter , lzh);
			break;
		case edkfGZ:
			copy_double_null(filter , gz);
			break;
		case edkfGCA:
			copy_double_null(filter , gca);
			break;
		case edkfDGC:
			copy_double_null(filter , dgc);
			break;
		case edkfRAR:
			copy_double_null(filter , rar);
			break;
		//default:break;
			//default無しで最適化でjump table化させる。
		}
		//std::stringの実装によっては後ろに二つのNULLは付けられないかも
		//なので、スコープドバッファーを使う。
		//byte_buffer buf(filter.size());
		//buf.SetString(filter.c_str());
//#error double null string を作る
		//やっぱメンドイ
		{
			//std::string &s = filter;
			size_t len = double_null_strlen(filter.get());

			

			if(plusall){
				size_t al = double_null_strlen(all);
				filter.resize(len + al + 1);
				memcpy(&filter.get()[len],all,al);
			}
			//ぶち込む
			//mFilter += s;
			mFilter = filter;
			mFilterFlag = flag;
		}
		return true;

	}

	virtual bool open(){
		//std::string &s=mFilter;



		scoped_buffer buf(mFilter.size() + 2);
		
		//buf = mFilter;//(完璧にmFilterと同じになるため。

		dkstrcpy(
			buf.get(),buf.size(),
			mFilter.get(),mFilter.size()
		);

		const char *double_null="\0\0";

		dkmemcpy(
			&( buf[mFilter.size()] ) ,
			buf.size()-mFilter.size(),
			double_null,
			2//strlen(double_null)
		);
		

		scoped_buffer path(dkcdMAXPATH * 30);
		
		if(false==FileOpenDialog(
			path.get(),path.size(),
			mTitle.c_str(),buf.get(),
			NULL,NULL
			))
		{
			return false;
		}
		mSelected = path;
		return true;
	}
	virtual std::string getFilename()const{
		return mSelected.to_string();
	}





};

#if 0

class FileDialog{
	bool reset(parm_string folder,parm_string file_extension){
		
	}
	bool save();
	bool open(parm_string *




};
	
#endif

/*
class FolderSelectDialog{
private:
	FolderSelector dialog;
	std::string mFilename;
public:
	///とりあえずfolder選択ダイアログをオープンする。
	bool open(parm_string title="Please select folder",parm_string default_folder=NULL,
		UINT Flag=BIF_EDITBOX,HWND WindowHandle=NULL)
	{
		char path[MAX_PATH + 20]="";//20は気持ち＾＾；
		bool result = DKUTIL_SUCCEEDED_BOOL(
			dialog.FolderSelectLogic(path,sizeof(path),
				default_folder.c_str(),title.c_str(),Flag,WindowHandle)
			);

		mFilename = path;
		
		return result;
	}
	///@return open()した後の選択した文字列をゲットする。
	const char *getFilename()const{
		return mFilename.c_str();
	}
};
*/
}//end of dkutil namespace











#endif //end of include once
