#include"CSingleWindowAppWindows.h"
#include"../../auxiliary/CString.h"
#include"../../auxiliary/Windows/CShell.h"
#include"../../auxiliary/Debug/CWarning.h"
#include"../../auxiliary/Debug/CAssert.h"
#include"../../auxiliary/Debug/CTrace.h"
#include"../../auxiliary/Debug/CException.h"

#include"../../Graphic/Core/Driver/Windows/Direct3D09/CVideoCardDriverD3D9.h"
#include"../../Auxiliary/Windows/CTimer_timeGetTime.h"

#include"../../Sound/Core/Driver/DirectSound8/CSoundCardDriverDS8.h"

#include"../../Input/Driver/Windows/EventMessage/CInputDriverWindowsMSG.h"

#include"../../Input/Driver/Windows/CInputMethodDriverWindows.h"
#include"../../template/Collision.h"

namespace Maid
{

CSingleWindowAppWindows::CSingleWindowAppWindows( const SPGAMETHREAD& pGame )
{
	m_pGame = pGame;
	m_Initialize = false;
}


void CSingleWindowAppWindows::OnSetup()
{
	m_hAppEvent  = ::CreateEvent(NULL, TRUE, FALSE, NULL);
	m_hGameEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);


	m_Thread.SetFunc( MakeThreadObject(&CSingleWindowAppWindows::ThreadFunction,this) );
	m_Thread.Execute();


	::ResetEvent(m_hAppEvent);
	::WaitForSingleObject(m_hAppEvent, INFINITE);

	if( m_pGame->IsExitGame() )
	{
		ApplicationExit();
		return ; 
	}

	const APPCONFIG& Conf = m_pGame->GetAppConfig();

	{
		CWindow& win = m_Window;

		win.RegistCallBack( WM_ACTIVATE,		MakeCallBackObject( &CSingleWindowAppWindows::wmActivate, this) );
		win.RegistCallBack( WM_NCLBUTTONDBLCLK, MakeCallBackObject( &CSingleWindowAppWindows::wmNcLButtonDblClk, this) );
		win.RegistCallBack( WM_SYSCOMMAND,      MakeCallBackObject( &CSingleWindowAppWindows::wmSysCommand, this) );
		win.RegistCallBack( WM_KEYDOWN,         MakeCallBackObject( &CSingleWindowAppWindows::wmKeyDown, this) );
		win.RegistCallBack( WM_SYSKEYDOWN,      MakeCallBackObject( &CSingleWindowAppWindows::wmSysKeyDown, this) );
		win.RegistCallBack( WM_PAINT,           MakeCallBackObject( &CSingleWindowAppWindows::wmPaint, this) );
		win.RegistCallBack( WM_CLOSE,           MakeCallBackObject( &CSingleWindowAppWindows::wmClose, this) );

		win.SetSize( Conf.Graphic.Size );
		win.SetCaption( Conf.Graphic.WindowCaption );
		win.SetStyle( CWindow::WINDOWSTYLE_NORMAL );

		win.Create();

		{
			HICON hIcon = LoadIcon();
			if( hIcon!=NULL )
			{
				::SendMessage( win.GetHWND(), WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon );
			}
		}

		win.Show();

		::SetForegroundWindow( win.GetHWND() );
	}

	SPTIMER pTimer( new CTimer_timeGetTime() );

	{
		const APPCONFIG::GRAPHIC& conf = Conf.Graphic;
		IVideoCardDriver::SCREENMODE m;

		m.Mode = (IVideoCardDriver::SCREENMODE::TYPE)conf.Screen;
		m.Size = conf.Size;
		m.RefreshRate  = conf.RefreshRate;
		m.IsSoftTnL    = conf.IsSoftTnL;
		m.IsWaitVSync  = conf.IsWaitVSync;
		m.IsAspectLock = conf.IsAspectLock;

		SPVIDEOCARDDRIVER pDriver( new CVideoCardDriverD3D9(m_Window.GetHWND()) );

		m_GraphicCore.Initialize( pDriver, m );
	}

	{
		SPSOUNDCARDDRIVER	pDriver( new CSoundCardDriverDS8(m_Window.GetHWND()) );

		ISoundCardDriver::PCMBUFFERFORMAT fmt;

		fmt.BitsPerSample	= Conf.Sound.BitsPerSample;
		fmt.Channels		= Conf.Sound.Channels;
		fmt.SamplesPerSec	= Conf.Sound.SamplesPerSec;

		m_SoundCore.Initialize( pDriver, pTimer, fmt );
	}

	{
		CInputDriverWindowsMSG driver(m_Window.GetHWND());

		m_pKeybordDriver  = driver.CreateKeybordDriver();
		m_pMouseDriver    = driver.CreateMouseDriver();
		m_pCharCodeDriver = driver.CreateCharCodeDriver();

		m_pKeybordDriver->Initialize();
		m_pMouseDriver->Initialize();

		{
			m_pCharCodeDriver->Initialize();
			m_pCharCodeDriver->SetCallBack(MakeCharCodeFunctionObject(&CSingleWindowAppWindows::OnCharCode,this) );
		}

		{
			CInputMethodDriverWindows* p = new CInputMethodDriverWindows;
			p->Initialize( m_Window.GetHWND() );

			m_pIMEDriver.reset( p );
			m_pIMEDriver->SetResultCodeFunction( MakeResultCodeFunctionObject(&CSingleWindowAppWindows::OnIMEResult,this) );
		}
	}
	m_IsFrameUpdating = false;
	m_Initialize = true;
	::SetEvent(m_hGameEvent);
}


void CSingleWindowAppWindows::OnLoop()
{
	HardWareCursorCheck();

	{
		//	スレッドが終了してたら終了
		if( m_Thread.IsThreadExited() )
		{
			if( m_Thread.IsThreadAssert() )
			{
				//	エラー終了だったら没
			}else
			{
				CThreadMutexLocker Lock(m_MessageMutex);
				m_GraphicCore.DrawFrame(m_ReturnMessageQue);
			}

			ApplicationExit();
			return ;
		}
	}

	if( m_IsFrameUpdating )
	{
		//	キューにたまっているものを描画
		CThreadMutexLocker Lock(m_MessageMutex);


		m_GraphicCore.DrawFrame( m_ReturnMessageQue );
		m_IsFrameUpdating = false;
	}else
	{
		::Sleep(1);
		return ;
	}
}

void CSingleWindowAppWindows::OnCleanup()
{
	m_Thread.Close();

	m_GraphicCore.Finalize();

	::CloseHandle(m_hAppEvent);
	::CloseHandle(m_hGameEvent);
}

HICON	CSingleWindowAppWindows::LoadIcon()
{
	return NULL; 
}

void CSingleWindowAppWindows::HardWareCursorCheck()
{
	MySTL::vector<int> pos;
	MySTL::vector<bool> key;

	m_pMouseDriver->GetState( pos, key );

	RECT2DI ClientRect;
	{
		RECT rc;
		::GetClientRect( m_Window.GetHWND(), &rc );

		ClientRect.x = 0;
		ClientRect.y = 0;
		ClientRect.w = rc.right - rc.left;
		ClientRect.h = rc.bottom - rc.top;
	}

	const bool IsWindowIn = Collision<int>::IsPointToRect( pos[0], pos[1],  ClientRect );
	const bool IsShow = m_pMouseDriver->IsCursorShow();

	if( IsWindowIn )
	{
		if( IsShow ) { m_pMouseDriver->SetDrawHardWareCursor(false); }
	}else
	{
		if( !IsShow ) { m_pMouseDriver->SetDrawHardWareCursor(true); }
	}
}


}
