#include "BasicStaticData.h"

#include "MathTool.h"

namespace HPL {
using namespace DirectX;
using namespace std;

namespace E3D {
using namespace BasicStaticDataConsts;
BasicStaticData::BasicStaticData(HINSTANCE hInstance) {
	this->m_hInstance = hInstance;
	this->m_hWindowHandle = NULL;


	this->m_nSwapChainID = 0;
	this->m_nFPS = 0;

	this->m_diMouse = new DIMouse();
	this->set_Active( FALSE) ;

	
	this->set_CameraMode( CameraMode::AT_TARGET_MODE,
		-1);

	//乱数の種
	MathTool::setSeed( MathTool::getRandomSeedFromTime());

	// カメラ初期化
	// 初期値とかはいずれ読み込ませよう…
	this->m_cameraAtTarget = new DCameraManager(4000.f );

	this->m_cameraShotBehind = new DCameraManager(CAMERA_SHOT_BEHIND_MODE_TARGET_DISTANCE);
	//this->m_cameraShotBehind->set_NormalizedQuatanionDirection( - this->m_cameraShotBehind->get_NormalizedQuatanionDirection() );
	this->m_cameraSniper = new DCameraManager(3000.f );
	//this->m_cameraSniper->set_NormalizedQuatanionDirection( - this->m_cameraSniper->get_NormalizedQuatanionDirection() );


	this->set_Grab(TRUE);

	this->set_Pause( FALSE );
	//m_bIsNoCameraChange = FALSE;

	this->set_FontType( 0 );
}
BasicStaticData::~BasicStaticData() {
	delete this->m_cameraAtTarget;
	delete this->m_cameraShotBehind;
	delete this->m_cameraSniper;
	if( m_diMouse != NULL ) {
		delete m_diMouse;
	}

	int ret = 0;
	ret = E3DDestroyFont( this->m_aryFontIDList[FontType::MINCHO] );
}

/** WinMainで最初に行う処理
  *
  */
BOOL BasicStaticData::commonMainStart(int nAppTitleResourceID,
									  int nClassNameResourceID,
									  int nCmdShow,
									  int nIconResourceID, int nSmallIconResourceID,
										HCURSOR hCursor) {
	// タイトル読み込み
	LoadString(this->get_Instance(), nAppTitleResourceID, this->m_szTitle, 
		BasicStaticDataConsts::MAX_TITLE_AND_CLASSNAME_STRING_LENGTH);

	// クラス名読み込み
	LoadString(this->get_Instance(), nClassNameResourceID, this->m_szWindowClass, 
		BasicStaticDataConsts::MAX_TITLE_AND_CLASSNAME_STRING_LENGTH);

	
	this->registerClass( nIconResourceID, nSmallIconResourceID,
		hCursor );

	// デバッグログで何を出すか指定
	_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

	if( this->initInstance( nCmdShow) == FALSE ) {
		return FALSE;
	}

	if( this->oneTimeSceneInit() != 0 ) {
		return FALSE;
	}

	return TRUE;
}

/**
  *
  */
BOOL BasicStaticData::initInstance( int nCmdShow)
{

	// ウィンドウサイズ
	this->m_nScreenWidth = GetPrivateProfileInt(_T("Graphics"), _T("WindowWidth"), 640, //デフォルト
		BasicStaticDataConsts::INI_FILE_PATH);
	this->m_nScreenHeight = GetPrivateProfileInt(_T("Graphics"), _T("WindowHeight"), 480, //デフォルト
		BasicStaticDataConsts::INI_FILE_PATH);

	// FPS
	this->m_nBaseFPS = GetPrivateProfileInt(_T("System"), _T("BaseFPS"), 60 ,
		BasicStaticDataConsts::INI_FILE_PATH );

	this->m_hWindowHandle = 
		CreateWindow( 
		this->m_szWindowClass,
		this->m_szTitle,
		WS_OVERLAPPEDWINDOW,	// ウィンドウスタイル
		CW_USEDEFAULT,			// x
		CW_USEDEFAULT,			// y
		m_nScreenWidth,
		m_nScreenHeight,
		NULL,					// 親ウィンドウハンドル(HWND)
		NULL,					// メニューハンドル(HMENU)
		this->get_Instance(),
		NULL);					// ウィンドウ作成データ(LPVOID)

	if( this->m_hWindowHandle == NULL ) {
		_ASSERT(0);
		return FALSE;
	}

	// マウス
	HRESULT hr = m_diMouse->initDevice( get_Instance(), this->m_hWindowHandle );
	if(FAILED(hr) ) {
		return FALSE;
	}

	// 表示
	ShowWindow( this->m_hWindowHandle, nCmdShow );

	// 更新
	UpdateWindow( this->m_hWindowHandle );

	// ----------------
	// E3Dコード			START

	// デバッグファイル有効
#ifdef _DEBUG
	E3DEnableDbgFile();
#endif
	// フルスクリーンフラグ
	int nFullScreenFlag = GetPrivateProfileInt(_T("Graphics"), _T("FullScreenFlag"),
		0, //デフォルト=0=ウィンドウモード
		BasicStaticDataConsts::INI_FILE_PATH);

	// 色ビット数
	int nColorBitsPerPixel = GetPrivateProfileInt(_T("Graphics"), _T("ColorBitsPerPixel"),
		16, //デフォルト=16=TrueColor
		BasicStaticDataConsts::INI_FILE_PATH);

	// アンチエイリアス
	int nAntiAlias = GetPrivateProfileInt(_T("Graphics"), _T("AntiAlias"),
		0, //デフォルト=0=無効
		BasicStaticDataConsts::INI_FILE_PATH);

	// GPUのシェーダを使用するか
	int nGPUFlag = GetPrivateProfileInt(_T("Graphics"), _T("GPUFlag"),
		0, //デフォルト=0=無効
		BasicStaticDataConsts::INI_FILE_PATH);

	// ステレオリバーブを使用するか
	int nStereoReverb = GetPrivateProfileInt(_T("Graphics"), _T("StereoReverb"),
		0, //デフォルト=0=無効
		BasicStaticDataConsts::INI_FILE_PATH);

	int ret = E3DInit( 
		this->get_Instance(),
		this->m_hWindowHandle,
		nFullScreenFlag,
		nColorBitsPerPixel,
		nAntiAlias,
		nGPUFlag,
		nStereoReverb,
		1,		// initcomflag COMフラグ設定（.NETの場合0にしておく）
		0,		// 32インデックスビットモード→OFF
		&this->m_nSwapChainID );

	if( ret != 0 ) {
		// 初期化失敗
		_ASSERT( 0 );
		return FALSE;
	}
	// E3Dコード			END
	// ----------------

	ret = E3DCreateQ( &m_cameraAtTarget->m_nQuatanionID );
	ret = E3DCreateQ( &m_cameraShotBehind->m_nQuatanionID );
	ret = E3DCreateQ( &m_cameraSniper->m_nQuatanionID );

	// フォント生成
	int nFontID;
	ret = E3DCreateFont( FONT_SIZE, 0, 400, 0,0,0, "ＭＳ 明朝", &nFontID );
	this->m_aryFontIDList[FontType::MINCHO] = nFontID;
	


	return TRUE;
}

/** WinMainで終了時に行う処理
  *
  */
void BasicStaticData::commonMainEnd() {
	// ----------------
	// E3Dコード			START
	E3DBye();
	// E3Dコード			END
	// ----------------
}

/** 
  * @retval 本アプリケーションのインスタンス
  */
HINSTANCE BasicStaticData::get_Instance() {
	return this->m_hInstance;
}

/**
  * @retval 本アプリケーションのメインウィンドウのハンドル
  */
HWND BasicStaticData::get_WindowHandle() {
	return this->m_hWindowHandle;
}

/** ウィンドウクラスを登録
  */
ATOM BasicStaticData::registerClass(int nIconResourceID, int nSmallIconResourceID,
									HCURSOR hCursor) {
	WNDCLASSEX wcex;
	// 0で初期化
	memset( &wcex, 0, sizeof(WNDCLASSEX));

	// 構造体のサイズ
	wcex.cbSize		= sizeof(WNDCLASSEX);
	
	// ウィンドウスタイル
	// 縦(V)横(H)にウィンドウサイズが変更された場合に再描画
	wcex.style		= CS_HREDRAW | CS_VREDRAW;

	// WindowProcedure ここでは定義しないので、各々のアプリケーションで記述する
	wcex.lpfnWndProc = WindowProcedure;

	// 拡張領域のサイズ
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;

	// 親インスタンス設定
	wcex.hInstance	= this->get_Instance();

	// アイコン
	wcex.hIcon		= LoadIcon(this->get_Instance(), MAKEINTRESOURCE(nIconResourceID));

	// カーソル
	wcex.hCursor	= hCursor;

	// バックグラウンドカラー
	wcex.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1);

	// メニュー
	wcex.lpszMenuName = NULL;

	// クラス名
	wcex.lpszClassName = this->m_szWindowClass;

	// 最小化時等のアイコン
	wcex.hIconSm	= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(nSmallIconResourceID));

	return RegisterClassEx(&wcex);
}
/** メディアディレクトリパスを取得
  *
  */
const char* BasicStaticData::get_MediaDirectory() {
	return "Media\\";
}
/** スワップチェインID取得
  * @retval スワップチェインID
  */
int BasicStaticData::get_SwapChainID() {
	return this->m_nSwapChainID;
}
int BasicStaticData::get_FPS() {
	return this->m_nFPS;
}
int BasicStaticData::get_BaseFPS() {
	return this->m_nBaseFPS;
}

DirectX::DIMouse* BasicStaticData::get_DIMouse() {
	return this->m_diMouse;
}

/** メインループ
  *
  */
int BasicStaticData::render3DEnvironment() {
	int ret = 0;

	// 取得
	HRESULT hr = this->get_DIMouse()->get_Key();
/*	if(FAILED(hr) ) {
		_ASSERT( 0 );
		return hr;
	}*/

	// キー情報更新
	ret = this->updateKeyBuffer();
	if(ret ) {
		_ASSERT( 0 );
		return ret;
	}

	// シーン処理
	this->m_SceneManager.get_Scene()->process();

	// バッファリング交換
	if( E3DPresent( this->get_SwapChainID() ) ) {
		_ASSERT( 0 );
		return 1;
	}

	// FPS計測＆ウェイト
	if( E3DWaitbyFPS( this->get_BaseFPS(), &this->m_nFPS) ) {
		_ASSERT( 0 );
		return 1;
	}
	return 0;
}
BOOL BasicStaticData::get_Active() {
	return this->m_bActive;
}
VOID BasicStaticData::set_Active(BOOL bActive) {
	this->m_bActive = bActive;
}

int BasicStaticData::updateKeyBuffer() {
	for(int i = 0; i < MAX_KEY_BUFFER; i ++ ) {
		m_lpPreviousKeyBuffer[i] = m_lpCurrentKeyBuffer[i];
	}

	int ret = E3DGetKeyboardCnt( m_lpCurrentKeyBuffer ) ;
	if(ret ) {
		_ASSERT( 0 );
		return ret;
	}

	return ret;

}
int BasicStaticData::get_CurrentKeyBuffer( int nVirtualKey ) {
	if(nVirtualKey < 0 || nVirtualKey >= BasicStaticDataConsts::MAX_KEY_BUFFER ) {
		_ASSERT( 0 );
		return -1;
	}
	return this->m_lpCurrentKeyBuffer[nVirtualKey];
}
int BasicStaticData::get_PreviousKeyBuffer( int nVirtualKey ) {
	if(nVirtualKey < 0 || nVirtualKey >= BasicStaticDataConsts::MAX_KEY_BUFFER ) {
		_ASSERT( 0 );
		return -1;
	}
	return this->m_lpPreviousKeyBuffer[nVirtualKey];
}





BOOL BasicStaticData::get_Grab() {
	return this->m_bGrab;
}
VOID BasicStaticData::set_Grab(BOOL bGrab) {

	if( this->m_bGrab != bGrab ) {
		this->m_bGrab = bGrab;

		// マウスカーソルを消す・表示する
		while( true ) {
			int n = ShowCursor(bGrab == FALSE);
 			if( bGrab == FALSE && n >= 0 ||
				bGrab == TRUE && n < 0 )
			{
				break;
			}
		}
	}
}

void BasicStaticData::get_ClientRect(RECT* rClientRect ) {
	GetClientRect( this->get_WindowHandle(), rClientRect );
}
void BasicStaticData::get_ClientCenter( POINT* pClientCenter ) {
	RECT rect;
	get_ClientRect( &rect );
	LONG lWidth = rect.right - rect.left;
	LONG lHeight = rect.bottom - rect.top;
	pClientCenter->x = lWidth / 2;
	pClientCenter->y = lHeight / 2;
}

/** クォータニオンをvDirection方向へセットする
  * @param[in] vDirection	向く方向
  * @param[in] nDivision	分割数
  */
void BasicStaticData::face( D3DXVECTOR3 vDirection , int nDivision, int nSigID,
					  int nQuoatanion)
{
	// 即座に向ける
	//E3DSetDir( nSigID, vDirection );

	E3DGetDirQ2( nSigID, nQuoatanion );

	// 宙返り無し
	int nUpFlag = 0;
	E3DLookAtQ( nQuoatanion, vDirection, D3DXVECTOR3(0.f,0.f,1.f), nUpFlag, nDivision );

	E3DSetDirQ2( nSigID, nQuoatanion );
}

/** 
  * @param[in] vDirection			移動方向
  * @param[in] fSpeed				移動量
  * @param[in] vCurrentPosition		現在位置
  * @param[out] vNewPosition		新位置
  * @retval D3DXVECTOR3				移動ベクトル（=vDirection * fSpeed）
  */
D3DXVECTOR3 BasicStaticData::move( 
		D3DXVECTOR3 vDirection,
		float fSpeed,
		D3DXVECTOR3 vCurrentPosition,
		D3DXVECTOR3* vNewPosition )
{
	E3DVec3Normalize(vDirection, &vDirection );
	// 移動量
	D3DXVECTOR3 vVelocity = vDirection * fSpeed;

	*vNewPosition = vCurrentPosition + vVelocity;

	return vVelocity;
}

void BasicStaticData::set_Pause( BOOL bPause ) {
	this->m_bPause = bPause;
}
BOOL BasicStaticData::is_Pause() {
	return this->m_bPause;
}
int BasicStaticData::get_FontType() {
	return this->m_nFontType;
}
int BasicStaticData::set_FontType( int nFontType ) {
	this->m_nFontType = nFontType;
	return 0;
}
int BasicStaticData::get_FontID() {
	return this->m_aryFontIDList[ this->get_FontType() ];
}


}// namespace E3D
}// namespace HPL




