
#include"CWindow.h"

#include"../../Auxiliary/Debug/CAssert.h"
#include"../../Auxiliary/CString.h"
#include"../../Auxiliary/Debug/CException.h"
#include"../../Auxiliary/Debug/CTrace.h"

#include"CApplicationWindows.h"
#include<shellapi.h>

namespace Maid
{
/*!
 	@class	CWindow CWindow.h
 	@brief	ウィンドウクラス
\n			１ウィンドウにつき１クラスです。
 */ 

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! コンストラクタ
/*!
 */
CWindow::CWindow()
{
	m_Caption = MAIDTEXT("window");
	m_Pos  = POINT2DI(CW_USEDEFAULT,CW_USEDEFAULT);
	m_Size = SIZE2DI(320, 240);
	m_Style= WINDOWSTYLE_NORMAL;

	m_IsShow  = false;
	m_IsDandD = false;
	m_hWnd = NULL;
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! デストラクタ
/*!
 */
CWindow::~CWindow()
{
	Destory();
}


HWND CWindow::GetHWND()
{
	return m_hWnd;
}

SIZE2DI CWindow::GetSize()
{
	return m_Size;
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! メッセージが飛んできたときにコールバックされる関数の設定
/*!
 *	\param	Msg			[i ]	ここで指定したメッセージが飛んでくるとコールバックされます
 *	\param	Function	[i ]	メッセージがきたときに呼ぶ予定の関数
 */
void CWindow::RegistCallBack( UINT Msg, const MESSAGEFUNCTION& Function )
{
	m_MessageMap[Msg] = Function;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! メッセージが飛んできたときにコールバックされる関数の削除
/*!
 *	\param	Msg			[i ]	削除したい関数
 */
void CWindow::DeleteCallBack( UINT Msg )
{
	m_MessageMap.erase( Msg );
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! 作成されたウィンドウを表示します
/*!
 */
void CWindow::Show()
{
	MAID_ASSERT( m_hWnd==NULL, "まだウィンドウが作成されていません" );

//	if( !m_IsShow ) 
	{
		::ShowWindow(m_hWnd, SW_SHOW );
		m_IsShow = true;
	}
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! 作成されたウィンドウを非表示にします
/*!
 */
void CWindow::Hide()
{
	MAID_ASSERT( m_hWnd==NULL, "まだウィンドウが作成されていません" );

	if( m_IsShow )
	{
		ShowWindow(m_hWnd, SW_HIDE );
		m_IsShow = false;
	}
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! ウィンドウの表示位置の変更
/*!
 	@param	pos [i ]	あたらしく設定する表示座標
 */
void CWindow::SetPosition( const POINT2DI& pos )
{
	if( m_hWnd!=NULL )
	{
		::SetWindowPos( m_hWnd, NULL, pos.x, pos.y, 0, 0, SWP_NOZORDER|SWP_NOSIZE );
	}

	m_Pos = pos;
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! ウィンドウの表示位置の変更
/*!
 	@param	size [i ]	あたらしく設定するクライアントサイズ
 */
void CWindow::SetSize( const SIZE2DI& size )
{
	if( m_hWnd!=NULL )
	{
		const DWORD StyleFlag = _GetWindowStyle(m_Style);
		::RECT	rc = { 0, 0, size.w, size.h };
		::AdjustWindowRect( &rc, StyleFlag, FALSE );
		const int w = rc.right  - rc.left;
		const int h = rc.bottom - rc.top;

		::SetWindowPos( m_hWnd, NULL, 0, 0, w, h, SWP_NOZORDER|SWP_NOMOVE );
	}

	m_Size = size;
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! ウィンドウスタイルの変更
/*!
 *
 */
void CWindow::SetStyle( WINDOWSTYLE Style )
{
	if( m_hWnd!=NULL )
	{
		const DWORD StyleFlag = _GetWindowStyle(Style);
		::SetWindowLong( m_hWnd, GWL_STYLE, StyleFlag );

		::SetWindowPos( m_hWnd, NULL,
				-1, -1,
				-1, -1,
				SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED|SWP_SHOWWINDOW );

	}

	m_Style = Style;

	//	ウィンドウの大きさがかわることがあるので、再設定
	SetSize(m_Size);
}

void CWindow::SetCaption( const mstring& Name )
{
	m_Caption = Name;
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! このウィンドウへのＤ＆Ｄを許可するか？
/*!
 	@param	IsAccept	[i ]	true で許可
 */
void CWindow::SetDragDropMode( bool IsAccept )
{
	if( m_hWnd!=NULL )
	{
		::DragAcceptFiles( m_hWnd, IsAccept? TRUE:FALSE );
	}
	m_IsDandD = IsAccept;
}










/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! ウィンドウを作成します
/*!
 	作成されるだけでまだ表示されません
 	表示させるときは Show() を呼び出す必要があります
 
	@exception CException オープンに失敗した場合
 */
void CWindow::Create()
{
	Destory();


	HWND hWnd = NULL;
	DWORD StyleFlag = _GetWindowStyle(m_Style);
	MySTL::string ClassName;
	MySTL::string Caption = CString::ConvertMAIDtoSJIS(m_Caption);

	switch( m_Style )
	{
	case WINDOWSTYLE_CONSOLE: { ClassName = "LISTBOX"; }break;
	default: 
		{
			const mstring name = IApplicationWindows::GetInstance()->GetClassName();
			ClassName = CString::ConvertMAIDtoSJIS(name);
		}
	}


	RECT	rc = { 0, 0, m_Size.w, m_Size.h };
	AdjustWindowRect( &rc, StyleFlag, FALSE );
	const int w = rc.right  - rc.left;
	const int h = rc.bottom - rc.top;

	//	CreateWindowEx() の内部でメッセージが送られてくる可能性があるけど
	//	RegistCallBack()でフックしようとしてもフックできない。
	//	そこで強引に行ってしまう

	AddProc( NULL );
	hWnd = ::CreateWindowEx(	NULL,
								ClassName.c_str(),
								Caption.c_str(),
								StyleFlag,
								m_Pos.x , m_Pos.y,
								w, h,
								NULL, NULL,
								IApplicationWindows::GetInstance()->GetHINSTANCE(),
								NULL );
	DelProc();

	if( hWnd==NULL )
	{
		MAID_THROWEXCEPTION( MAIDTEXT("ウィンドウの作成に失敗") );
	}

	AddProc( hWnd );
	m_hWnd = hWnd;

	if( m_IsDandD ) { SetDragDropMode(true); }

}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! ウィンドウを破棄します
/*!
 */
void CWindow::Destory()
{
	if( m_hWnd!=NULL )
	{
		::DestroyWindow( m_hWnd );
		DelProc();
	}

	m_hWnd = NULL;
	m_IsShow = false;
	m_IsDandD= false;
}




/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! CInitializeWindows からフックされて呼び出される関数
/*!
 	引数などは IMessageHook::WindowProc を参照すること
 */
IMessageHook::RETURNCODE CWindow::OnMessage( CWindowsMessage& Param )
{
	MySTL::map<UINT,MESSAGEFUNCTION>::iterator ite = m_MessageMap.find( Param.GetMSG() );

	if( ite!=m_MessageMap.end() )
	{
		switch( ite->second( Param ) )
		{
		case CALLBACKCODE_EXIT:		{ return RETURNCODE_EXIT; }break;
		case CALLBACKCODE_CONTINUE:	{ return RETURNCODE_CONTINUE; }break;
		}
	}

	return RETURNCODE_CONTINUE;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! ウィンドウスタイルをＡＰＩの引数に変換する
/*!
	@param	Style	[i ]	知りたいウィンドウスタイル

	@return 実際のウィンドウスタイル
\n			そのまま CreateWindow() に使える
 */
DWORD	CWindow::_GetWindowStyle( WINDOWSTYLE Style )
{
	DWORD StyleFlag;
	switch( Style )
	{
	case WINDOWSTYLE_NORMAL:
		{
			StyleFlag = WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_DLGFRAME | WS_CAPTION;
		}break;

	case WINDOWSTYLE_OVERLAP:
		{
			StyleFlag = WS_OVERLAPPEDWINDOW;
		}break;

	case WINDOWSTYLE_POPUP:
		{
			StyleFlag = WS_POPUP;
		}break;
	case WINDOWSTYLE_CONSOLE:
		{
			StyleFlag =   WS_VISIBLE | WS_CAPTION | LBS_NOINTEGRALHEIGHT | WS_VSCROLL
							| WS_SIZEBOX									//	サイズは可変
							| WS_MAXIMIZEBOX | WS_MINIMIZEBOX| WS_SYSMENU;	//	これを入れると、ウィンドウの×印がつく。
		}break;
	}

	return StyleFlag;
}

}