#pragma once

#include <list>
#include <vector>
#include <map>

#include "Mix/Tool/Win32/Core/Object.h"

namespace Mix{ namespace Tool{ namespace Win32{ namespace Graphics{
	class LineHelper;
}}}}

namespace Mix{ namespace Tool{ namespace Win32{ namespace Dynamics{
	class World;
	class Shape;
	class RigidBody;
}}}}

namespace Mix{ namespace Tool{ namespace Win32{ namespace Dynamics{ namespace Design{

	class Actor;

	class Basic : public Mix::Tool::Win32::Object
	{
	public:
		//座標系列挙定数
		enum COORDINATE_SYSTEM
		{
			LEFT_HANDED		= 1,	//左手座標系
			RIGHT_HANDED	= 2,	//右手座標系
		};

		//モード列挙定数
		enum MODE
		{
			EDIT	= 0,	//編集
			STAND	= 1,	//スタンド
			RAGDOLL	= 2,	//ラグドール
		};

		//オブジェクトタイプ列挙定数
		enum OBJECT_TYPE
		{
			COLLIDER	= 1,	//コライダー
			SENSOR		= 2,	//センサー
		};

		//コライダータイプ列挙定数
		enum COLLIDER_TYPE
		{
			DEFAULT		= 1,	//デフォルト
			STATIC		= 2,	//スタティック
			KINEMATIC	= 3,	//キネマティック
		};

		//回転軸列挙定数
		enum ROTATION_AXIS
		{
			RA_X	= 0x00000001,	//Ｘ軸での回転が有効
			RA_Y	= 0x00000002,	//Ｙ軸での回転が有効
			RA_Z	= 0x00000004,	//Ｚ軸での回転が有効

			RA_ALL	= 0x00000007,
		};

		//ワールド変更イベント記述構造体
		struct WORLD_CHANGED_EVENT_ARGS
		{
			Mix::Tool::Win32::Dynamics::World* pOldWorld;
			Mix::Tool::Win32::Dynamics::World* pNewWorld;

			WORLD_CHANGED_EVENT_ARGS( Mix::Tool::Win32::Dynamics::World* _pOldWorld, Mix::Tool::Win32::Dynamics::World* _pNewWorld )
			{
				pOldWorld = _pOldWorld;
				pNewWorld = _pNewWorld;
			}
		};

		//座標系変更イベント記述構造体
		struct COORDINATE_SYSTEM_CHANGED_EVENT_ARGS
		{
			Basic::COORDINATE_SYSTEM newCoordinateSystem;

			COORDINATE_SYSTEM_CHANGED_EVENT_ARGS( Basic::COORDINATE_SYSTEM cs )
			{
				newCoordinateSystem = cs;
			}
		};

		//モード変更イベント記述構造体
		struct MODE_CHANGED_EVENT_ARGS
		{
			Basic::MODE oldMode;
			Basic::MODE newMode;

			D3DXVECTOR3 impulse;

			MODE_CHANGED_EVENT_ARGS( Basic::MODE _oldMode, Basic::MODE _newMode, const D3DXVECTOR3& _impulse )
			{
				oldMode = _oldMode;
				newMode = _newMode;
				impulse = _impulse;
			}
		};

	public:
		//シェイプ情報構造体
		struct SHAPE
		{
			D3DXQUATERNION rot;
			D3DXVECTOR3 pos;

			SHAPE( const D3DXQUATERNION& _rot, const D3DXVECTOR3& _pos )
			{
				rot = _rot;
				pos = _pos;
			}
		};

		typedef std::map<HANDLE, Basic::SHAPE> ShapeMap;
		typedef std::vector<HANDLE> HandleList;

		//オブジェクト構造体
		struct OBJECT
		{
			Basic::OBJECT_TYPE type;
			int* handle;

			std::wstring name;

			Mix::Tool::Win32::Dynamics::RigidBody* pRigidBody;

			D3DXQUATERNION centerRot;
			D3DXVECTOR3 centerPos;
			D3DXMATRIX centerMat;		//リジッドボディの中心へ変換する行列

//			D3DXMATRIX invCenterMat;	//シェイプをリジッドボディのローカル空間へ変換するための行列
			D3DXMATRIX restoreMat;		//リジッドボディをボーンの空間へ変換するための行列

			Basic::ShapeMap shapeMap;
			Basic::HandleList shapeHandleList;

			Basic::COLLIDER_TYPE colliderType;
			D3DXQUATERNION initalColliderRot;
			D3DXVECTOR3 initalColliderPos;
			int rotAxisFlags;
		};

		typedef std::map<HANDLE, Basic::OBJECT> ObjectMap;
		typedef std::vector<Basic::OBJECT*> ObjectPtrList;

	protected:
		Actor* m_pSubject;

		Mix::Tool::Win32::Dynamics::World* m_pWorld;

		D3DXVECTOR3 m_LocalPos;

		D3DXQUATERNION m_DefCenterRot;
		D3DXVECTOR3 m_DefCenterPos;
		D3DXMATRIX m_DefCenterMat;
//		D3DXMATRIX m_DefInvCenterMat;
		D3DXMATRIX m_DefRestoreMat;

		D3DXMATRIX m_InitalWorldMat;

		D3DXQUATERNION m_DefInitalColliderRot;
		D3DXVECTOR3 m_DefInitalColliderPos;

		D3DXVECTOR3 m_WorldS;
//		D3DXVECTOR3 m_AbsWorldS;
		D3DXQUATERNION m_WorldR;
		D3DXVECTOR3 m_WorldT;
		D3DXMATRIX m_WorldMat;
		D3DXMATRIX m_PreWorldMat;

		Basic::COORDINATE_SYSTEM m_CoordinateSystem;
		Basic::MODE m_Mode;

		bool m_bWorldMatReseted;
		bool m_bWorldRotRefreshed;
		bool m_bWorldPosRefreshed;

	private:
		Basic::ObjectMap m_ObjectMap;
		Basic::HandleList m_ObjectHandleList;

		Basic::OBJECT* m_ColliderObjectPtr;
		Basic::ObjectPtrList m_SensorObjectPtrList;

		Basic::OBJECT* m_SelectedObjectPtr;

	public:
		Basic( void );
		Basic(	Actor* pSubject,
				Basic::COORDINATE_SYSTEM coordinateSystem,
				const D3DXVECTOR3& localPos,
				const D3DXMATRIX& worldMat,
				const D3DXQUATERNION& centerRot,
				const D3DXVECTOR3& centerPos );

		virtual ~Basic( void );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 全般
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual Basic::COORDINATE_SYSTEM GetCoordinateSystem( void ) const;
		Basic::MODE GetMode( void ) const;

		const D3DXMATRIX& GetInitalWorldMatrix( void ) const;

		const D3DXVECTOR3& GetWorldScaling( void ) const;
		const D3DXQUATERNION& GetWorldRotation( void ) const;
		const D3DXVECTOR3& GetWorldTranslation( void ) const;
		const D3DXMATRIX& GetWorldMatrix( void ) const;
		virtual void SetWorldMatrix( const D3DXMATRIX& worldMat );

		void ResetWorldMatrix( void );

		virtual bool IsWorldMatrixRefreshed( void ) const;
		virtual bool IsWorldRotationRefreshed( void ) const;
		virtual bool IsWorldPositionRefreshed( void ) const;

		void Draw(	Mix::Tool::Win32::Graphics::LineHelper* pLineHelper,
					bool bSensor,
					bool bBody,
					const D3DXVECTOR4& selectedColor,
					const D3DXVECTOR4& sensorColor,
					const D3DXVECTOR4& bodyColor,
					float axisScale );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// オブジェクト : 全般
		////////////////////////////////////////////////////////////////////////////////////////////////////

		HANDLE Object_Add( Basic::OBJECT_TYPE type );
		bool Object_Remove( HANDLE hObject );

		bool Object_GetType( HANDLE hObject, Basic::OBJECT_TYPE& type ) const;

		int Object_GetColliderCount( void ) const;
		int Object_GetSensorCount( void ) const;

		int Object_GetHandleCount( void ) const;
		HANDLE Object_GetHandle( int index ) const;

		void Object_Selected( HANDLE hObject );

		bool Object_GetName( HANDLE hObject, std::wstring& name ) const;
		bool Object_SetName( HANDLE hObject, const wchar_t* pName );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// オブジェクト : センタートランスフォーム
		////////////////////////////////////////////////////////////////////////////////////////////////////

		bool Object_GetCenterMatrix( HANDLE hObject, D3DXMATRIX& mat ) const;
		bool Object_SetCenterTransform( HANDLE hObject, const D3DXQUATERNION& rot, const D3DXVECTOR3& pos );

		bool Object_GetCenterRotation( HANDLE hObject, D3DXQUATERNION& rot ) const;
		bool Object_GetCenterRotation( HANDLE hObject, D3DXVECTOR3& rot ) const;
		bool Object_SetCenterRotation( HANDLE hObject, const D3DXQUATERNION& rot );
		bool Object_SetCenterRotation( HANDLE hObject, const D3DXVECTOR3& rot );
		bool Object_ResetCenterRotation( HANDLE hObject );

		bool Object_GetCenterPosition( HANDLE hObject, D3DXVECTOR3& pos ) const;
		bool Object_SetCenterPosition( HANDLE hObject, const D3DXVECTOR3& pos );
		bool Object_ResetCenterPosition( HANDLE hObject );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// オブジェクト : シェイプ
		////////////////////////////////////////////////////////////////////////////////////////////////////

		HANDLE Object_AddShape( HANDLE hObject, Mix::Tool::Win32::Dynamics::Shape* pShape, const D3DXQUATERNION& rot, const D3DXVECTOR3& pos );
		HANDLE Object_AddShape( HANDLE hObject, Mix::Tool::Win32::Dynamics::Shape* pShape, const D3DXVECTOR3& rot, const D3DXVECTOR3& pos );
		bool Object_RemoveShape( HANDLE hObject, HANDLE hShape );

		const Mix::Tool::Win32::Dynamics::Shape* Object_GetShape( HANDLE hObject, HANDLE hShape ) const;
		bool Object_SetShape( HANDLE hObject, HANDLE hShape, Mix::Tool::Win32::Dynamics::Shape* pShape );
		bool Object_SetShape( HANDLE hObject, HANDLE hShape, Mix::Tool::Win32::Dynamics::Shape* pShape, const D3DXQUATERNION& rot, const D3DXVECTOR3& pos );
		bool Object_SetShape( HANDLE hObject, HANDLE hShape, Mix::Tool::Win32::Dynamics::Shape* pShape, const D3DXVECTOR3& rot, const D3DXVECTOR3& pos );

		bool Object_GetShapeRotation( HANDLE hObject, HANDLE hShape, D3DXQUATERNION& rot ) const;
		bool Object_SetShapeRotation( HANDLE hObject, HANDLE hShape, const D3DXQUATERNION& rot );
		bool Object_GetShapeRotation( HANDLE hObject, HANDLE hShape, D3DXVECTOR3& rot ) const;
		bool Object_SetShapeRotation( HANDLE hObject, HANDLE hShape, const D3DXVECTOR3& rot );

		bool Object_GetShapePosition( HANDLE hObject, HANDLE hShape, D3DXVECTOR3& pos ) const;
		bool Object_SetShapePosition( HANDLE hObject, HANDLE hShape, const D3DXVECTOR3& pos );

		int Object_GetShapeHandleCount( HANDLE hObject ) const;
		const HANDLE Object_GetShapeHandle( HANDLE hObject, int index ) const;

		bool Object_ShapeSelected( HANDLE hObject, HANDLE hShape );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// オブジェクト : マテリアル
		////////////////////////////////////////////////////////////////////////////////////////////////////

		bool Object_GetMaterial( HANDLE hObject, Mix::Tool::Win32::Dynamics::MATERIAL& material ) const;
		bool Object_SetMaterial( HANDLE hObject, const Mix::Tool::Win32::Dynamics::MATERIAL& material );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// コライダー : 基本
		////////////////////////////////////////////////////////////////////////////////////////////////////

		bool Collider_GetType( HANDLE hObject, Basic::COLLIDER_TYPE& type );
		bool Collider_SetType( HANDLE hObject, Basic::COLLIDER_TYPE type );

		bool Collider_GetMass( HANDLE hObject, float& mass ) const;
		bool Collider_SetMass( HANDLE hObject, float mass );

		bool Collider_GetAlwaysActive( HANDLE hObject, bool& state) const;
		bool Collider_SetAlwaysActive( HANDLE hObject, bool state );

		bool Collider_GetRotationAxis( HANDLE hObject, int& flags ) const;
		bool Collider_SetRotationAxis( HANDLE hObject, int flags );

		bool Collider_IsAvailable( void ) const;
		bool Collider_IsDefault( void ) const;
		bool Collider_IsStatic( void ) const;
		bool Collider_IsKinematic( void ) const;

		bool Collider_IsCastMotion( void ) const;

		const D3DXMATRIX& Collider_GetCenterMatrix( void ) const;

		const D3DXQUATERNION& Collider_GetInitalRotation( void ) const;
		const D3DXVECTOR3& Collider_GetInitalPosition( void ) const;

		const Basic::OBJECT* Collider_GetPtr( void ) const;
		Mix::Tool::Win32::Dynamics::RigidBody* Collider_GetRigidBodyPtr( void );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// センサー : 基本
		////////////////////////////////////////////////////////////////////////////////////////////////////

		int Sensor_GetCount( void ) const;
		const Basic::OBJECT* Sensor_GetPtr( int index ) const;
		bool Sensor_IsAvailale( int index ) const;

		int Sensor_CountAvailable( void ) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// ユーティリティ
		////////////////////////////////////////////////////////////////////////////////////////////////////

		//シェイプが一つだった場合のリジッドボディのトランスフォームを求める
		void Utility_ComputeSimpleTransform( const D3DXQUATERNION& centerRot, const D3DXVECTOR3& centerPos, D3DXMATRIX& centerMat, D3DXMATRIX& restoreMat, D3DXQUATERNION& rot, D3DXVECTOR3& pos );

	protected:
		virtual void OnWorldChanged( const Basic::WORLD_CHANGED_EVENT_ARGS& args );
		virtual void OnModeChanged( const Basic::MODE_CHANGED_EVENT_ARGS& args );
		virtual void OnColliderChanged( void );
		virtual void OnRefresh( void );
		virtual bool OnRefreshWorldTransform( D3DXMATRIX& worldMat ); //無効なボディだった場合のみ呼び出される

		Basic::OBJECT* Object_GetPtr( HANDLE hObject );
		const Basic::OBJECT* Object_GetConstPtr( HANDLE hObject ) const;

		Basic::SHAPE* Object_GetShapePtr( HANDLE hObject, HANDLE hShape );
		const Basic::SHAPE* Object_GetShapeConstPtr( HANDLE hObject, HANDLE hShape ) const;

		Basic::SHAPE* Object_GetShapePtrByObjPtr( Basic::OBJECT* pObj, HANDLE hShape );
		const Basic::SHAPE* Object_GetShapeConstPtrByObjPtr( const Basic::OBJECT* pObj, HANDLE hShape ) const;

		void Object_UpdateCenterTransform( Basic::OBJECT* pObj );
		void Object_UpdateShapeTransform( Basic::OBJECT* pObj );
		void Object_UpdateRigidBodyTransform( Basic::OBJECT* pObj );

		void Collider_Reset( void );
		bool Collider_UpdateType( void );
		void Collider_UpdateTransform( void );

		void ComputeObjectTransform( const D3DXQUATERNION& centerRot, const D3DXVECTOR3& centerPos, D3DXMATRIX& centerMat/*, D3DXMATRIX& invCenterMat*/, D3DXMATRIX& restoreMat );
		void ComputeShapeTransform( Basic::OBJECT* pObj, const D3DXQUATERNION& sr, const D3DXVECTOR3& sp, D3DXQUATERNION& dr, D3DXVECTOR3& dp );
		void ComputeRigidBodyTransform( const D3DXMATRIX& centerMat, D3DXQUATERNION& rot, D3DXVECTOR3& pos );
		void ComputeInitalRigidBodyTransform( const D3DXMATRIX& centerMat, D3DXQUATERNION& rot, D3DXVECTOR3& pos );

		void ComposeWorldMatrix( void );
		void DecomposeWorldMatrix( void );

		Mix::Tool::Win32::Dynamics::World* GetWorldPtr( void );

		void AttachWorld( Mix::Tool::Win32::Dynamics::World* pWorld );
		void DetachWorld( Mix::Tool::Win32::Dynamics::World* pWorld );

		void NotifyColliderChanged( void );

	public:
		MIX_OBJECT_TYPE( Mix::Tool::Win32::Object::DYNAMICS__BASIC_DESIGNER, Mix::Tool::Win32::Object )

		friend class Actor;
		friend class Part;
	};

}}}}}

