#include"CApplicationWindows.h"
#include"../../auxiliary/CString.h"
#include"../../auxiliary/Windows/CShell.h"
#include"../../auxiliary/Debug/CWarning.h"
#include"../../auxiliary/Debug/CAssert.h"
#include"../../auxiliary/Debug/CException.h"
#include"../../auxiliary/CRand.h"

namespace Maid
{

static const char* DEFAULT_CLASSNAME = "Maid_application";

static IApplicationWindows* g_pApp;

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! コンストラクタ
/*!
 */
IApplicationWindows::IApplicationWindows()
{
#ifdef CHECK_MEMORY_LEAK
	//!	メモリリークのチェックをする
	_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF|_CRTDBG_CHECK_ALWAYS_DF);
#endif

	MAID_ASSERT( g_pApp!=NULL, "すでに存在しています" );

	g_pApp = this;
	CShell::CoInitialize();
	CShell::InitCommonControls();
	m_ApplicationExitCode = 0;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! デストラクタ
/*!
 */
IApplicationWindows::~IApplicationWindows()
{
	CShell::CoUninitialize();
}

HINSTANCE		IApplicationWindows::GetHINSTANCE()	const { return m_Instance; }
const mstring	IApplicationWindows::GetClassName()	const { return CString::ConvertSJIStoMAID(DEFAULT_CLASSNAME); }
const LPSTR		IApplicationWindows::GetCmdLineALL()	const { return m_pCmdLine; }
const MySTL::vector<mstring>&	IApplicationWindows::GetCmdLine()const { return m_DivComdList; }

mstring	IApplicationWindows::GetCmdLine( int no )const
{
	if( !(no<(int)m_DivComdList.size()) ) { return mstring(); }

	return m_DivComdList[no];
}


IApplicationWindows* IApplicationWindows::GetInstance()
{
	return g_pApp;
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! アプリが生きているか？
/*!
	詳しくは IApplication::IsValid() を参照
 */
bool IApplicationWindows::IsValid()
{
	MSG Msg;

	while( ::PeekMessage( &Msg, NULL, 0, 0, PM_REMOVE )!=0 )
	{
		if( Msg.message == WM_QUIT )
		{
			m_ApplicationExitCode = (int)Msg.wParam;
			return false;	
		}
		::TranslateMessage( &Msg );
		::DispatchMessage( &Msg );
	}

	return true;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! アプリケーションを終了させる
/*!
	詳しくは IApplication::ApplicationExit() を参照
 */
void IApplicationWindows::ApplicationExit()
{
	::PostQuitMessage(0);
}




/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! アプリケーションの起動
/*!
 	@param	hInstance		[i ]	WinMain() から渡された引数
 	@param	hPrevInstance	[i ]	WinMain() から渡された引数
 	@param	lpCmdLine		[i ]	WinMain() から渡された引数
 	@param	nCmdShow		[i ]	WinMain() から渡された引数

	@return アプリケーションの終了コード WinMain の返り値として使います

	@exception CException 異常終了した場合

 */
int IApplicationWindows::Run( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
{
	try
	{
		{	//	初期設定
			mstring ExePath = CShell::GetExeFileName();
			mstring ExeDir = CString::GetDirectory(ExePath);

			CShell::SetCurrentDirectory( ExeDir );

			CRand::SetSeed(::GetTickCount());
		}

		m_Instance = hInstance;
		m_PrevInstance = hPrevInstance;
		m_pCmdLine = lpCmdLine;
		m_CmdShow = nCmdShow;

		{	//	コマンドラインの判別
			// UNICODE でいいなら CommandLineToArgvW という便利な関数があるようです。
			// http://www7a.biglobe.ne.jp/~lshen/EternalWindows/WinBase/Window/Window06.html
			const mstring arg = CString::ConvertSJIStoMAID(::GetCommandLine());

			for( int pos=0; pos<(int)arg.length(); ++pos )
			{
				if( arg[pos]==' ' ) { continue; }

				mstring str;

				if( arg[pos]=='\"' )
				{
					pos += 1;
					for( ; pos<(int)arg.length(); ++pos )
					{
						if( arg[pos]=='\"' ) { ++pos; break; }
						str += arg[pos];
					}
				}else
				{
					for( ; pos<(int)arg.length(); ++pos )
					{
						if( arg[pos]==' ' ) { break; }
						str += arg[pos];
					}
				}

				m_DivComdList.push_back(str); 
			}
		}


		{	//	プロセスの登録
			WNDCLASSEX		wc = {0};
			wc.cbSize			= sizeof(WNDCLASSEX);
			wc.style			= CS_VREDRAW | CS_HREDRAW; 
			wc.lpfnWndProc		= ProcessProc; 
			wc.hInstance		= m_Instance;
			wc.cbClsExtra		= 0;
			wc.cbWndExtra		= 0;
			wc.hIcon			= ::LoadIcon( m_Instance,IDI_APPLICATION); 
			wc.hCursor			= ::LoadCursor( NULL, IDC_ARROW ); 
			wc.hbrBackground	= (HBRUSH)::GetStockObject(BLACK_BRUSH);
			wc.lpszMenuName		= NULL; 
			wc.lpszClassName	= DEFAULT_CLASSNAME;
			 
			wc.hIconSm			= NULL;

			if( ::RegisterClassEx(&wc)==0 ) 
			{
				MAID_THROWEXCEPTION(MAIDTEXT("RegisterClassEx に失敗"));
			}
		}



		OnSetup();

		while( IsValid() )
		{
			OnLoop();
		}

		OnCleanup();
	}
	catch(CException& e )
	{
		MAID_WARNING( "ライブラリ例外:" << e.Text );

		const mstring str = MAIDTEXT("エラーが発生しました。アプリケーションを終了します\n") + e.Text;

		::MessageBox( NULL, CString::ConvertMAIDtoSJIS(str).c_str(), "execption", MB_OK );	
	}
	catch(...)
	{
		MAID_WARNING( "システム例外" );
		throw;
	}

	return m_ApplicationExitCode;
}

LRESULT CALLBACK IApplicationWindows::ProcessProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
	CWindowsMessage mess(hWnd,msg,wParam,lParam);
	return g_pApp->m_HookManager.OnMessage( mess );
}

}