//////////////////////////////////////////////////////////
//
//	MyuWindow
//
//////////////////////////////////////////////////////////

#ifndef __MyuWindow_H__
#define __MyuWindow_H__

#pragma warning( disable : 4786 ) // VC での警告を取り除きます。

//#include "MyuCommonException.h"
#include <windows.h>
#include "MyuWndBase.h"

//	クラス宣言
class CMyuWindowDetailEx : public CMyuWndBase
{
protected:
	//HWND m_hWnd;

	//	overridable
	virtual void OnWindowMain();
	virtual BOOL OnNoPeekMessage();

	virtual bool _OnCreatedWindow(){ return true; }
	virtual bool OnShowWindow(){ return true; }
	virtual bool OnUpdateWindow(){ return true; }

public:
	CMyuWindowDetailEx();
	virtual ~CMyuWindowDetailEx();

	DWORD StartWindowDetailEx( WNDCLASSEX &wc, const char* szAppCaption,
							  int nWinXPos, int nWinYPos, int nWinWidthSize, int nWinHeightSize,
							  DWORD dwWinStyle, int nWindowShow, HMENU hMenu=NULL, HWND hWndParent=NULL, LPVOID lpParam=NULL );
};

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

#include <map>

//	HWndとポインタを関連付けるマップ
template <typename T=void*>
class CMyuHwndMap
{
protected:
	std::map<HWND,T> m_map;

public:
	CMyuHwndMap(){}
	virtual ~CMyuHwndMap(){}

	void Add(HWND hWnd, T p){ m_map[hWnd] = p; }
	T FindFromHwnd(HWND hWnd){
		std::map<HWND,T>::iterator it = m_map.find(hWnd);
		if ( it == m_map.end() )
			return NULL;
		else
			return it->second;
	}
	T operator [](HWND hWnd){ return FindFromHwnd(hWnd); }
};

///////////////////////////////////////////////////////
/*
//	クラスの関数ポインタクソ紛らわしいんですがこんな感じです
class CMyuMsgProcMap;
typedef LRESULT (CMyuMsgProcMap::*MYU_MSG_PROC_CALLBACK)(HWND,WPARAM,LPARAM);

//	メッセージプロシージャのマップ
template <typename T> class CMyuMsgProcMap
{
public:
	//typedef LRESULT (*MSGPROC_CALLBACK)(HWND hWnd, WPARAM wParam, LPARAM lParam);
	//typedef LRESULT (*CALLBACK_t)(WPARAM wParam, LPARAM lParam);
	typedef MYU_MSG_PROC_CALLBACK CALLBACK_t;

protected:
	typedef std::map<UINT,CALLBACK_t> CALLBACK_MAP_t;
	CALLBACK_MAP_t m_map;

public:
	CMyuMsgProcMap(){}
	virtual ~CMyuMsgProcMap(){}

	//	追加
	void Add(UINT msg, CALLBACK_t pFunc){ m_map[msg] = pFunc; }

	//	探す
	CALLBACK_t Find(UINT msg){
		CALLBACK_MAP_t::iterator it = m_map.find(msg);
		if ( it == m_map.end() )
			return NULL;
		else
			return it->second;
	}
	//	実行までやっちゃう
	LRESULT CallProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ){
		CALLBACK_t pFunc = Find(msg);
		if ( pFunc != NULL )
			return (this->*pFunc)(hWnd, wParam, lParam);
		else
			return ::DefWindowProc( hWnd, msg, wParam, lParam );
	}
};
*/
///////////////////////////////////////////////////////

/*
//	クラスの関数ポインタクソ紛らわしいんですがこんな感じです
template <typename PARENT> class CMyuMsgProcMap;
typedef LRESULT (CMyuMsgProcMap<int>::*MYU_MSG_PROC_CALLBACK)(HWND,WPARAM,LPARAM);

//	メッセージプロシージャのマップ
template <typename PARENT> class CMyuMsgProcMap
{
public:
	//typedef LRESULT (*MSGPROC_CALLBACK)(HWND hWnd, WPARAM wParam, LPARAM lParam);
	//typedef LRESULT (*CALLBACK_t)(WPARAM wParam, LPARAM lParam);
	typedef LRESULT (PARENT::*CALLBACK_t)(HWND,WPARAM,LPARAM);

protected:
	typedef std::map<UINT,CALLBACK_t> CALLBACK_MAP_t;
	CALLBACK_MAP_t m_map;

	PARENT* m_pParent;

public:
	CMyuMsgProcMap(){ m_pParent = NULL; }
	virtual ~CMyuMsgProcMap(){}

	//	追加
	void Add(UINT msg, CALLBACK_t pFunc){ m_map[msg] = pFunc; }

	//	探す
	CALLBACK_t Find(UINT msg){
		CALLBACK_MAP_t::iterator it = m_map.find(msg);
		if ( it == m_map.end() )
			return NULL;
		else
			return it->second;
	}
	//	実行までやっちゃう
	LRESULT CallProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ){
		CALLBACK_t pFunc = Find(msg);
		if ( pFunc != NULL )
			return (m_pParent->*pFunc)(hWnd, wParam, lParam);
		else
			return ::DefWindowProc( hWnd, msg, wParam, lParam );
	}

	void SetParent(PARENT* pParent){ m_pParent = pParent; }
};
*/
///////////////////////////////////////////////////////

class CMyuWindow;
typedef LRESULT (CMyuWindow::*MYU_MSG_PROC_CALLBACK)(HWND,WPARAM,LPARAM);

#define MYU_WINPOS_CENTER	(0x7fffffff)
#define MYU_WINPOS_AUTO		MYU_WINPOS_CENTER
#define MYU_WINDOW_DEFAULT_STYLE		(WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU)

typedef struct
{
	HINSTANCE hInstance;
	HICON hIcon;
	HCURSOR hCursor;
	HBRUSH hbrBackground;
	LPCSTR lpszMenuName;
	HICON hIconSmall;
	HMENU hMenu;
	HWND hWndParent;
	LPVOID lpParam;
}
MYU_WINDOW_EX_INFO;

//	クラス宣言
//class DLL_EXP CMyuWindow
class CMyuWindow : public CMyuWindowDetailEx
{
public:
	typedef MYU_MSG_PROC_CALLBACK CALLBACK_t;
	typedef std::map<UINT,CALLBACK_t> CALLBACK_MAP_t;

protected:
	BOOL m_bQuit;	//	WM_QUITきたらTRUE

	//	メッセージプロシージャのコールバックマップ <msg,コールバック>
	CALLBACK_MAP_t m_msgProcCallbackMap;
	//CMyuMsgProcMap<CMyuWindow> m_msgProcCallbackMap;

	//	MessageProcがどのCMyuWindowから呼ばれてるのかを知るための、HWNDからthisを取るためのマップ（static）
	static CMyuHwndMap<CMyuWindow*> m_hwndToThisMap;
	//static std::map<HWND,CMyuWindow*> m_hwndToThisMap;

	//	ExtendsInfo
	BOOL m_bEnableDropfiles;

	////////////////////////////////////////////////////////
	//	Methods

	//virtual BOOL OnMessageProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
	virtual LRESULT OnMessageProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );

	//	override
	void OnWindowMain();
	bool _OnCreatedWindow();

	//	overridable
	virtual void OnCreatedWindow(){}
	virtual bool OnClose(){ return true; }	//	閉じて良い:true / 閉じちゃ駄目:false
	virtual bool OnDropFiles(std::vector<std::string> &files){ return false; }	//	何か処理をした
	//	overridable MSG
	virtual LRESULT OnWmClose(HWND hWnd, WPARAM wParam, LPARAM lParam);
	virtual LRESULT OnWmDestroy(HWND hWnd, WPARAM wParam, LPARAM lParam);
	virtual LRESULT OnWmDropfiles(HWND hWnd, WPARAM wParam, LPARAM lParam);

	LRESULT DefWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
		return ::DefWindowProc( hWnd, msg, wParam, lParam ); }
	////////// MessageProc ////////////////////////////////////

/*	virtual LRESULT On
*/
private:
	static LRESULT WINAPI MessageProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );

public:
	CMyuWindow();
	virtual ~CMyuWindow();

	/*int StartWindow( const char* szAppCaption, const char* szWinClassName,
		int nWinWidthSize, int nWinHeightSize, int nWinXPos, int nWinYPos ){

	}*/
	int Start( const char* szWindowTitle, const char* szWinClassName,
		int nWinWidthSize, int nWinHeightSize, int nWinXPos=MYU_WINPOS_AUTO, int nWinYPos=MYU_WINPOS_AUTO,
		DWORD dwWinStyle=MYU_WINDOW_DEFAULT_STYLE, int nWindowShow=SW_SHOWDEFAULT )
	{
		return StartWindowEx(szWindowTitle, szWinClassName, nWinWidthSize, nWinHeightSize,
			nWinXPos, nWinYPos, dwWinStyle, nWindowShow );
	}

	int StartWindow( const char* szWindowTitle, const char* szWinClassName,
		int nWinWidthSize, int nWinHeightSize, int nWinXPos=MYU_WINPOS_AUTO, int nWinYPos=MYU_WINPOS_AUTO,
		DWORD dwWinStyle=MYU_WINDOW_DEFAULT_STYLE, int nWindowShow=SW_SHOWDEFAULT )
	{
		return StartWindowEx(szWindowTitle, szWinClassName, nWinWidthSize, nWinHeightSize,
			nWinXPos, nWinYPos, dwWinStyle, nWindowShow );
	}

	int StartWindowEx( const char* szWindowTitle, const char* szWinClassName,
		int nWinWidthSize, int nWinHeightSize, int nWinXPos, int nWinYPos,
		DWORD dwWinStyle, int nWindowShow, MYU_WINDOW_EX_INFO *ex )
	{
		return StartWindowEx(szWindowTitle, szWinClassName, nWinWidthSize, nWinHeightSize,
			nWinXPos, nWinYPos, dwWinStyle, nWindowShow,
			ex->hInstance, ex->hIcon, ex->hCursor,
			ex->hbrBackground, ex->lpszMenuName, ex->hIconSmall,
			ex->hMenu, ex->hWndParent, ex->lpParam);
	}

	int StartWindowEx( const char* szWindowTitle, const char* szWinClassName,
		int nWinWidthSize, int nWinHeightSize, int nWinXPos=MYU_WINPOS_AUTO, int nWinYPos=MYU_WINPOS_AUTO,
		DWORD dwWinStyle=MYU_WINDOW_DEFAULT_STYLE, int nWindowShow=SW_SHOWDEFAULT,
		HINSTANCE hInstance=NULL, HICON hIcon=NULL, HCURSOR hCursor=NULL,
		HBRUSH hbrBackground=NULL, LPCSTR lpszMenuName=NULL, HICON hIconSmall=NULL,
		HMENU hMenu=NULL, HWND hWndParent=NULL, LPVOID lpParam=NULL );

	void Quit();

	BOOL IsQuit() { return m_bQuit; }

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

	//	static Util
	static BOOL GetScreenSize( int* pnWidth, int* pnHeight );

	///////////////////////////////////////////////////////////////////////
	
	//	追加
	//void AddMsgCallback(UINT msg, CALLBACK_t pFunc){ m_msgProcCallbackMap[msg] = pFunc; }
	void AddMsgCallback(UINT msg, CALLBACK_t pFunc);	//	STL-DLLの関係でcpp内でやるっす。（何 - 2009/04/16

	//	探す
	CALLBACK_t FindMsgCallback(UINT msg){
		CALLBACK_MAP_t::iterator it = m_msgProcCallbackMap.find(msg);
		if ( it == m_msgProcCallbackMap.end() )
			return NULL;
		else
			return it->second;
	}

	//	実行までやっちゃう
	LRESULT ExecMsgCallbacks( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ){
		CALLBACK_t pFunc = FindMsgCallback(msg);
		if ( pFunc != NULL )
			return (this->*pFunc)(hWnd, wParam, lParam);
		else
			return ::DefWindowProc( hWnd, msg, wParam, lParam );
	}

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

	//	プロパティ系
	void EnableDropFiles(BOOL bEnable=TRUE){
		m_bEnableDropfiles = bEnable;
		if ( m_hWnd != NULL )
			::DragAcceptFiles( m_hWnd, bEnable );

		AddMsgCallback(WM_DROPFILES,	(CALLBACK_t)&CMyuWindow::OnWmDropfiles);
	}
	void DisableDropFiles(){ EnableDropFiles(FALSE);
		//	TODO: m_msgProcCallbackMapから削除してやるか？（そこまでする必要はあるのか？）
		/*m_bEnableDropfiles = FALSE;
		if ( m_hWnd != NULL )
			::DragAcceptFiles( m_hWnd, FALSE );*/
	}
};

#endif//__MyuWindow_H__
