#ifndef _BASIC_STATIC_DATA_
#define _BASIC_STATIC_DATA_

//! Windows ヘッダー ファイル:
#include <windows.h>

//! C ランタイム ヘッダー ファイル
#include <cstdlib>
//#include <malloc.h>
#include <memory.h>
#include <tchar.h>


#ifdef _DEBUG
//! デバッグ出力用
#include <crtdbg.h>

#endif


//! easy3d
#include <easy3d.h>

#include "E3DSigManager.h"
#include "E3DLightManager.h"

// マウス
#include "DIMouse.h"

// カメラ
#include "DCameraManager.h"

#include "E3DObject.h"

#include <list>

#include "HPLSceneManager.h"

namespace HPL {

namespace E3D {
namespace BasicStaticDataConsts {
	static const int MAX_TITLE_AND_CLASSNAME_STRING_LENGTH = 1024;
	static const TCHAR* INI_FILE_PATH = _T("data/General.ini");
	static const int MAX_KEY_BUFFER = 256;

	//! EDF射撃モードで、照準までの距離
	static const float CAMERA_SHOT_BEHIND_MODE_TARGET_DISTANCE = 5000.f;
	//! EDF射撃モードで、プレイヤーから少し後ろのカメラの距離
	static const float CAMERA_SHOT_BEHIND_MODE_CAMERA_DISTANCE = 1300.f;
	static const float CAMERA_SHOT_BEHIND_DELTA_HEIGHT = 700.f;

	static const float MOUSE_LOOK_AT_TARGET_MODE_DEGREE_HORIZONTAL = 0.2f;		//! 横方向カメラ向き変更角度
	static const float MOUSE_LOOK_AT_TARGET_MODE_DEGREE_VERTICAL = 0.2f;		//! 縦方向カメラ向き変更角度
	static const float MOUSE_LOOK_SHOT_BEHIND_MODE_DEGREE_HORIZONTAL = 0.1f;		//! 横方向カメラ向き変更角度
	static const float MOUSE_LOOK_SHOT_BEHIND_MODE_DEGREE_VERTICAL = 0.1f;		//! 縦方向カメラ向き変更角度
	static const float MOUSE_LOOK_SNIPER_MODE_DEGREE_HORIZONTAL = 0.2f;		//! 横方向カメラ向き変更角度
	static const float MOUSE_LOOK_SNIPER_MODE_DEGREE_VERTICAL = 0.2f;		//! 縦方向カメラ向き変更角度

	static const float PLAYER_EYE_HEIGHT_FROM_CENTER = 1000;		//! プレイヤーの中心座標から目の高さまでの相対高度
	static const float PLAYER_SHOT_HEIGHT_FROM_CENTER = 800.f;		//! プレイヤーの中心座標から弾の発射位置までの相対高度
	static const float PLAYER_EYE_HEIGHT_FROM_CENTER_LOW = 100.f;
	static const float PLAYER_EYE_HEIGHT_FROM_CENTER_HIGH = 2000.f;

	static const int CAMERA_ROTATE_DIV = 1;
	static const float GRAVITY = -3.f;
	static const int FONT_SIZE = 16;


	/** マウスカメラモード
	  * カメラを切り替えていく。
	  */
	namespace CameraMode {
		enum {
			/** ターゲットを中心にカメラが球面上を動く
			  * 初期位置	：どこでもいい。背中とか。
			  * 角度変化	：マウスに合わせてカメラを上下左右に球面上移動させる
			  * Disable時	：回転させる
			  */
			AT_TARGET_MODE,

			/** EDF/GTA射撃モード。プレイヤーの肩の後ろからターゲットを見る感じ
			  * 初期位置	：プレイヤーの背中
			  * 角度変化	：プレイヤーも回転させる（理想はプレイヤーの上半身のみ）
			  * Disable時	：回転させる
			  */
			SHOT_BEHIND_MODE,

			/** プレイヤーの目の位置を中心に描画する（EyeFromCamera == FALSE）
			  * これも一応クォータニオらないといけない
			  * 初期位置	：プレイヤーが向いている方向、一定距離離れたところ
			  * 角度変化	：通常のカメラとは逆方向に回転
			  * Disable時	：回転させない。Enable時に毎回初期化する。
			  *				　逆にEnable時はプレイヤーを表示しないようにすること
			  */
			SNIPER_MODE,

			MAX_NUM,
		} ;

	}

	/** カメラの上フラグ
	  *
	  */
	namespace CameraUpFlag {
		enum {
			ALWAYS_Y_AXIS			= 0x000000,	//! 上向き方向を常にY軸上にする
			ALWAYS_NEGATIVE_Y_AXIS	= 0x000001,	//! 上向き方向を常にY軸下にする
			SEQUENCE				= 0x000002,	//! 連続した向きを取る
			FREE					= 0x000003,	//! 制御無し
		};
	}

	namespace FontType {
		enum {
			MINCHO,
			GOTHIC,
			MAX_NUM
		};
	}
}

class BasicStaticData {
public:
	//! オブジェクトマネージャ
	//std::list<E3DObject*> m_lstObjectList;

	//! マウスによるカメラ切り替えをしない
	//! 別途カメラモードを切り替える事
	//BOOL m_bIsNoCameraChange;


private:
	int m_nFontType;
	int m_aryFontIDList[BasicStaticDataConsts::FontType::MAX_NUM];

	//! アプリケーションのインスタンス
	HINSTANCE m_hInstance;

	//! メインウィンドウのハンドル
	HWND m_hWindowHandle;

	TCHAR m_szTitle[BasicStaticDataConsts::MAX_TITLE_AND_CLASSNAME_STRING_LENGTH];
	TCHAR m_szWindowClass[BasicStaticDataConsts::MAX_TITLE_AND_CLASSNAME_STRING_LENGTH];

	/** スワップチェインID：どの部分に描画を行うか指定する際に使用
	  *  E3DChkInView, E3DRender, E3DBeginScene, E3DPresent等で使用
	  */
	int m_nSwapChainID;

	//! baseのFPS
	int m_nBaseFPS;

	//! カメラの高さ
	//float m_fCameraHeight;

	//! カメラの距離
	//float m_fCameraDistance;

	//! カメラの位置
	//D3DXVECTOR3 m_vCameraPosition;

	//! キー情報
	int m_lpCurrentKeyBuffer[BasicStaticDataConsts::MAX_KEY_BUFFER];
	int m_lpPreviousKeyBuffer[BasicStaticDataConsts::MAX_KEY_BUFFER];

	DirectX::DIMouse* m_diMouse;

	//! ウィンドウは今アクティブか？
	BOOL m_bActive;

	//! カメラモード
	int m_nCameraMode;

	//! GTA歩行モード風カメラアングル
	//! つまり、対象を中心に緯度、経度方向にカメラが移動する
	DirectX::DCameraManager* m_cameraAtTarget;

	//! GTA射撃モード風カメラアングル
	//! つまり、プレイヤーの肩から少し後ろからターゲットを見ている状態
	//! あくまでカメラ→プレイヤーの座標として、実際のカメラアングルは
	//! カメラ→プレイヤーが向いている方向に少しはなれた位置
	DirectX::DCameraManager* m_cameraShotBehind;
	//! 補助衛星// キャラクターと上記のカメラは、この衛星の方向をみるようにする
	//DirectX::DCameraManager* m_cameraShotBehindSub;

	//! スナイパーカメラ
	//! プレイヤーを中心として
	DirectX::DCameraManager* m_cameraSniper;

	//! マウスカーソルを捕まえるかどうか
	BOOL m_bGrab;

	//! ポーズ
	BOOL m_bPause;
public:
	//! スクリーンの仮想上の横幅。
	//! 実際のウィンドウのサイズとは関係ない
	int m_nScreenWidth;
	int m_nScreenHeight;
public:
	//! FPS
	int m_nFPS;

	//! Sig/Quaファイル管理
	E3DSigManager m_SigManager;

	//! 光源管理
	E3DLightManager m_LightManager;

	//! シーン管理
	General::HPLSceneManager m_SceneManager;
	
public:
	/** コンストラクタ
	  *
	  */
	BasicStaticData(HINSTANCE hInstance);

	/** デストラクタ 
	  *
	  */
	~BasicStaticData();

public:	// Getter/Setter
	/** 
	  * @retval 本アプリケーションのインスタンス
	  */
	HINSTANCE get_Instance();

	/**
	  * @retval 本アプリケーションのメインウインドウのハンドル
	  */
	HWND get_WindowHandle();

	/** メディアディレクトリパスを取得
	  *
	  */
	const char* get_MediaDirectory();

	/** スワップチェインID取得
	  * @retval スワップチェインID
	  */
	int get_SwapChainID();

	/**
	  * @retval FPS
	  */
	int get_FPS();
	/**
	  * @retval BaseFPS
	  */
	int get_BaseFPS();
	DirectX::DIMouse* get_DIMouse();
	BOOL get_Active();
	VOID set_Active(BOOL bActive);

	/** 
	  * @param[in]	nCameraMode			カメラモード
	  * @param[in]	nPlayerSigID		プレイヤーモデルの回転を制御する可能性があるため、指定する
	  *									また、スナイパーの方向を取得するのにも必要
	  */
	VOID set_CameraMode( int nCameraMode, int nPlayerSigID);
	int get_CameraMode();

	DirectX::DCameraManager* get_Camera();

	BOOL get_Grab();
	VOID set_Grab(BOOL bGrab);

	void set_Pause( BOOL bPause );
	BOOL is_Pause();

	int get_FontType();
	int set_FontType( int nFontType );
	int get_FontID();

private:// 内部関数
	/** インスタンス初期化
	  * @param nCmdShow
	  */
	BOOL initInstance( int nCmdShow);

protected:
public: // 共通オペレーション


	/** WinMainで最初に行う処理
	  * @param[in] nAppTitleResourceID	タイトル文字列のリソースID
	  * @param[in] nClassNameResourceID	アプリケーションクラスの名称文字列のリソースID
	  */
	BOOL commonMainStart(
		int nAppTitleResourceID,
		int nClassNameResourceID,
		int nCmdShow,
		int nIconResourceID, int nSmallIconResourceID,
									HCURSOR hCursor);

	/** WinMainで終了時に行う処理
	  *
	  */
	void commonMainEnd();

	/** ウィンドウクラスを登録
	  * @param[in] hCursor			アイコンハンドル
	  */
	ATOM registerClass( int nIconResourceID, int nSmallIconResourceID, HCURSOR hCursor);

	/** 3Dレンダリング
	  * @retval 0以外 処理に失敗した場合
	  */
	int render3DEnvironment();
	/**
	  *
	  */
	int updateKeyBuffer();
	int get_CurrentKeyBuffer( int nVirtualKey );
	int get_PreviousKeyBuffer( int nVirtualKey );

	/** カメラ位置、方向を設定
	  * @param[in]	vPlayerPosition			プレイヤーの位置
	  * @param[in]	vPlayerDirection		プレイヤーの向いている方向
	  */
	int updateCameraPosition( int nPlayerSigID, D3DXVECTOR3& vPlayerPosition, float fHeight);

	/**
	  *
	  * @param[in]	lQuatanionHorizontal	クォータニオン的横回転
	  * @param[in]	fQuatanionVertical	クォータニオン的縦回転
	  */
	int moveCameraPosition(
		long lQuatanionHorizontal,
		long lQuatanionVertical,
		float *fRateHorizontal,
		float *fRateVertical );

	/** カメラターゲット設定（E3Dのあれまで実施する）
	  * @param[in]	
	  * @return		0	正常終了
	  */
	int set_CameraLookAt(
		int nPlayerSigID , int nPlayerQuatanionID, float fHeight);

	void get_ClientRect(RECT* rClientRect);
	void get_ClientCenter( POINT* pClientCenter );

	/** クォータニオンをvDirection方向へセットする
	  * @param[in] vDirection	向く方向
	  * @param[in] nDivision	分割数
	  * @param[in] nSigID		回転対象モデル
	  */
	void face( D3DXVECTOR3 vDirection , int nDivision, int nSigID,
		int nQuoatanion);

	/** 
	  * @param[in] vDirection			移動方向
	  * @param[in] fSpeed				移動量
	  * @param[in] vCurrentPosition		現在位置
	  * @param[out] vNewPosition		新位置
	  * @retval D3DXVECTOR3				移動ベクトル（=vDirection * fSpeed）
	  */
	D3DXVECTOR3 move( 
			D3DXVECTOR3 vDirection,
			float fSpeed,
			D3DXVECTOR3 vCurrentPosition,
			D3DXVECTOR3* vNewPosition );
public: // 仮想関数 要オーバーライド

	/** 一回だけ実施するシーン初期化
	  * @retval 成功時は0
	  */
	virtual int oneTimeSceneInit() = 0;


};


}// namespace E3D
}// namespace HPL
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
#endif
