#pragma once

#include "Mix/Scene/IActorDynamicsDirector.h"
#include "Mix/Private/Queue.h"

namespace Mix{ namespace Scene{ namespace Common{

	class ActorDynamicsCluster;
	class ActorDynamicsFigure;
	class ActorDynamicsPart;
	class ActorCollider;
	class ActorSensor;
	class ActorKinematicCharacter;

	class ActorDynamicsDirector : public Mix::Scene::IActorDynamicsDirector
	{
	private:
		enum COMMAND_TYPE
		{
			//Update
			CU_SET_COLLIDER_MODE		= 0x01000000,
			CU_ACTIVATE					= 0x02000000,
			CU_DEACTIVATE				= 0x03000000,
			CU_FIRST					= CU_SET_COLLIDER_MODE,
			CU_LAST						= CU_DEACTIVATE,

			//Refresh
			CR_CLEAR_FORCE				= 0x04000000,
			CR_CLEAR_MOTION				= 0x05000000,
			CR_FIRST					= CR_CLEAR_FORCE,
			CR_LAST						= CR_CLEAR_MOTION,

			//マスク( 32Bit )
			CT_MASK						= 0xFF000000,	//タイプ
			CD_MASK						= 0x00FFFFFF,	//データ

			//キュー
			CQ_DEF_CAPACITY				= 8,
			CQ_RESIZE_STEP				= 4,
		};

		template<typename T, typename IT>
		class Collection : public IActorDynamicsDirector::ICollection<T>
		{
		public:
			typedef Mix::STL::Vector<Mix::Memory::SECTION_SCENE, IT*> Type;
			typedef Collection<T, IT> CollectionType;

		public:
			static Collection<T, IT>* CreateInstance( void )
			{
				return MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, CollectionType );
			}

		private:
			Type m_List;

		private:
			Collection( void ) {}
			virtual ~Collection( void )
			{
				for( Type::iterator it = m_List.begin(); it != m_List.end(); ++it )
				{
					MIX_RELEASE( ( *it ) );
				}
			}

		public:
			void Add( IT* pObject )
			{
				MIX_ASSERT( pObject != NULL );

				MIX_ADD_REF( pObject );
				m_List.push_back( pObject );
			}

			typename Type::iterator Begin( void )
			{
				return m_List.begin();
			}

			typename Type::iterator End( void )
			{
				return m_List.end();
			}

			typename Type::const_iterator Begin( void ) const
			{
				return m_List.begin();
			}

			typename Type::const_iterator End( void ) const
			{
				return m_List.end();
			}

			IT** GetBeginPtr( void ) const
			{
				MIX_ASSERT( m_List.size() > 0 );

				return &( m_List[0] );
			}

			IT** GetEndPtr( void ) const
			{
				MIX_ASSERT( m_List.size() > 0 );

				return ( m_List[0] + m_List.size() );
			}

		public:
			virtual UInt32 GetCount( void ) const
			{
				return MIX_UIT_TO_UI32( m_List.size() );
			}

			virtual Boolean Get( UInt32 index, T** ppObject )
			{
				if( ( m_List.size() <= index ) ||
					( ppObject == NULL ) )
				{
					return False;
				}

				T* pObject = m_List[index];

				MIX_ADD_REF( pObject );
				( *ppObject ) = pObject;

				return True;
			}

			virtual T* operator[] ( UInt32 index ) const
			{
				if( m_List.size() <= index )
				{
					MIX_ERROR( L"範囲を超えたインデックスが指定されています" );
					return NULL;
				}

				return m_List[index];
			}
		};

		typedef	Mix::STL::Vector<Mix::Memory::SECTION_SCENE, Mix::Scene::Common::ActorDynamicsCluster*> ClusterList;

		typedef ActorDynamicsDirector::Collection<IActorCollider, ActorCollider> ColliderCollection;
		typedef ActorDynamicsDirector::Collection<IActorSensor, ActorSensor> SensorCollection;

		typedef Mix::STL::Map<Mix::Memory::SECTION_SCENE, Mix::StringW, ActorDynamicsDirector::ColliderCollection*> ColliderCollectionMap;
		typedef Mix::STL::Map<Mix::Memory::SECTION_SCENE, Mix::StringW, ActorDynamicsDirector::SensorCollection*> SensorCollectionMap;

	public:
		static ActorDynamicsDirector* CreateInstance( const wchar_t* pDebugName );

	private:
		Mix::Scene::DYNAMICS_KCHAR_MODE m_KCharMode;

		Boolean m_bColliderEnabled;
		Mix::Scene::DYNAMICS_COLLIDER_MODE m_ColliderMode;

		Boolean m_bSensorEnabled;

		Mix::Scene::Common::ActorDynamicsFigure* m_pFigure;
		ActorDynamicsDirector::ClusterList m_ClusterList;
		ActorDynamicsDirector::ClusterList m_CollideClusterList;

		ActorDynamicsDirector::ColliderCollectionMap m_ColliderCollectionMap;
		ActorDynamicsDirector::ColliderCollection* m_pColliderCollection;

		ActorDynamicsDirector::SensorCollectionMap m_SensorCollectionMap;
		ActorDynamicsDirector::SensorCollection* m_pSensorCollection;

		Mix::QueueT<Mix::Memory::SECTION_SCENE, UInt32> m_Commands;

		Float32 m_LinearSleepingThreshold;
		Float32 m_AngularSleepingThreshold;

		Boolean m_bActive;

		Boolean m_bDisposed;

	protected:
		ActorDynamicsDirector( const wchar_t* pDebugName );
		virtual ~ActorDynamicsDirector( void );

	public:
		Boolean Initialize( void );
		void Dispose( void );

		Boolean SetFigure( Mix::Scene::Common::ActorDynamicsFigure* pFigure );
		Boolean AddPart( Mix::Scene::Common::ActorDynamicsPart* pPart );

		void AttachToWorld( Mix::Dynamics::IWorld* pWorld, Mix::Dynamics::IObjectListener* pObjectListener );
		void DetachFromWorld( Mix::Dynamics::IWorld* pWorld );

		void Reset( void );
		void Update( void );
		void Refresh( void );

	private:
		Boolean AddCluster( Mix::Scene::Common::ActorDynamicsCluster* pCluster );

		void Proc_SetColliderMode( Mix::Scene::DYNAMICS_COLLIDER_MODE mode );
		void Proc_ActivateCollider( void );
		void Proc_DeactivateCollider( Boolean bForce );
		void Proc_ClearColliderForce( void );
		void Proc_ClearColliderMotion( void );

	public:
		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IActorDynamicsDirector
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual Boolean IsCharacterEnabled( void ) const;
		virtual void SetCharacterEnabled( Boolean state );
		virtual Mix::Scene::DYNAMICS_KCHAR_MODE GetCharacterMode( void ) const;
		virtual void SetCharacterMode( Mix::Scene::DYNAMICS_KCHAR_MODE mode, Boolean bInstantly );

		virtual Boolean IsColliderEnabled( void ) const;
		virtual void SetColliderEnabled( Boolean state );
		virtual Mix::Scene::DYNAMICS_COLLIDER_MODE GetColliderMode( void ) const;
		virtual void SetColliderMode( Mix::Scene::DYNAMICS_COLLIDER_MODE mode, Boolean bInstantly );

		virtual Boolean IsSensorEnabled( void ) const;
		virtual void SetSensorEnabled( Boolean state );

		virtual Boolean GetColliders( Mix::Scene::IActorDynamicsDirector::ICollection<Mix::Scene::IActorCollider>** ppCollection );
		virtual Boolean GetColliders( const wchar_t* pName, Mix::Scene::IActorDynamicsDirector::ICollection<Mix::Scene::IActorCollider>** ppCollection );

		virtual Boolean GetSensors( Mix::Scene::IActorDynamicsDirector::ICollection<Mix::Scene::IActorSensor>** ppCollection );
		virtual Boolean GetSensors( const wchar_t* pName, Mix::Scene::IActorDynamicsDirector::ICollection<Mix::Scene::IActorSensor>** ppCollection );

		virtual Boolean IsActive( void ) const;
		virtual void Activate( Boolean bInstantly );
		virtual void Deactivate( Boolean bForce, Boolean bInstantly );

		virtual void ClearForce( Boolean bInstantly );
		virtual void ClearMotion( Boolean bInstantly );

		virtual Float32 GetLinearSleepingThresholds( void ) const;
		virtual void SetLinearSleepingThresholds( Float32 threshold );

		virtual Float32 GetAngularSleepingThresholds( void ) const;
		virtual void SetAngularSleepingThresholds( Float32 threshold );
	};

}}}
