#pragma once

#include "Mix/Dynamics/IRigidBody.h"
#include "Mix/Scene/IActorCollider.h"
#include "Mix/Private/Scene/Common/DynamicsObject.h"

namespace Mix{ namespace Scene{ namespace Common{

	class ActorCollider : public Mix::Scene::IActorCollider, public Mix::Scene::Common::DynamicsObject
	{
	private:
		struct FILTER
		{
			UInt16 group;
			UInt16 mask;
		};

	public:
		static ActorCollider* CreateInstance(	const wchar_t* pName,
												const Mix::Matrix4x4& centerMat,
												const Mix::Matrix4x4& restoreMat,
												Mix::Dynamics::IRigidBody* pObject,
												Boolean bCastMotion );

	private:
		Mix::Scene::IRendererObject* m_pOwner;

		Mix::StringW m_Name;
		ActorCollider::FILTER m_FilterTable[Mix::Dynamics::RB_STATUS_MAX];
		Mix::Matrix4x4 m_CenterMat;
		Mix::Matrix4x4 m_RestoreMat;
		Mix::Dynamics::IRigidBody* m_pObject;
		Mix::Dynamics::IRigidBody::STATUS m_DefStatus;
		Boolean m_bCastMotion;

	private:
		ActorCollider(	const wchar_t* pName,
						const Mix::Matrix4x4& centerMat,
						const Mix::Matrix4x4& restoreMat,
						Mix::Dynamics::IRigidBody* pObject,
						Boolean bCastMotion );

		virtual ~ActorCollider( void );

		void UpdateFilter( void );

	public:
		void SetOwner( Mix::Scene::IRendererObject* pOwner );

		void SetMode( Mix::Scene::DYNAMICS_COLLIDER_MODE mode );

		void Reset( const Mix::Matrix4x4& baseMat );

		Boolean CanUpdateDefault( Mix::Scene::DYNAMICS_COLLIDER_MODE mode ) const;
		Mix::Matrix4x4 UpdateDefault( void );
		void UpdateKinematicOrStatic( const Mix::Matrix4x4& baseMat );

		Boolean CanRefresh( Mix::Scene::DYNAMICS_COLLIDER_MODE mode ) const;
		Mix::Matrix4x4 Refresh( const Mix::Vector3& worldScaling );

		Boolean IsCastMotion( void ) const;

		Mix::Dynamics::IRigidBody* GetInternalRigidBodyPtr( void ) const;

		ActorCollider* Clone( void );

		void Dispose( void );

	public:
		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::Common::DynamicsObject
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual Mix::Dynamics::IObject* GetInternalObjectPtr( void ) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IActorCollider
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual const wchar_t* GetName( void ) const;

		virtual UInt16 GetCurrentFilterGroup( void ) const;
		virtual UInt16 GetFilterGroup( Mix::Dynamics::IRigidBody::STATUS status ) const;
		virtual void SetFilterGroup( Mix::Dynamics::IRigidBody::STATUS status, UInt16 value );

		virtual UInt16 GetCurrentFilterMask( void ) const;
		virtual UInt16 GetFilterMask( Mix::Dynamics::IRigidBody::STATUS status ) const;
		virtual void SetFilterMask( Mix::Dynamics::IRigidBody::STATUS status, UInt16 value );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IKineticCollider
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual Float32 GetMass( void ) const;
		virtual void SetMass( Float32 mass );

		virtual const Mix::Dynamics::MATERIAL& GetMaterial( void ) const;
		virtual void SetMaterial( const Mix::Dynamics::MATERIAL& material );

		virtual Boolean IsAlwaysActive( void ) const;
		virtual Boolean SetAlwaysActive( Boolean state );

		virtual Boolean IsActive( void ) const;
		virtual Boolean Activate( void );
		virtual Boolean Deactivate( Boolean bFroce = False );

		virtual Mix::Vector3 GetLinearFactor( void ) const;
		virtual void SetLinearFactor( const Mix::Vector3& factor );

		virtual Float32 GetLinearDamping( void ) const;
		virtual void SetLinearDamping( Float32 damping );

		virtual Mix::Vector3 GetLinearVelocity( void );
		virtual Boolean SetLinearVelocity( const Mix::Vector3& velocity );

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

		virtual Mix::Vector3 GetAngularFactor( void ) const;
		virtual void SetAngularFactor( const Mix::Vector3& factor );

		virtual Float32 GetAngularDamping( void ) const;
		virtual void SetAngularDamping( Float32 damping );

		virtual Mix::Vector3 GetAngularVelocity( void );
		virtual Boolean SetAngularVelocity( const Mix::Vector3& velocity );

		virtual Float32 GetAngularSleepingThresholds( void ) const;
		virtual void SetAngularSleepingThresholds( Float32 thresholds );

		virtual Boolean ApplyLinearImpulse( const Mix::Vector3& impulse );
		virtual Boolean ApplyAngularImpulse( const Mix::Vector3& impulse );
		virtual Boolean ApplyImpulse( const Mix::Vector3& impulse, const Mix::Vector3& pos );

		virtual Boolean ApplyLinearForce( const Mix::Vector3& force );
		virtual Boolean ApplyAngularForce( const Mix::Vector3& torque );
		virtual Boolean ApplyForce( const Mix::Vector3& force, const Mix::Vector3& pos );

		virtual Mix::Vector3 GetTotalLinearForce( void );
		virtual Mix::Vector3 GetTotalAngularForce( void );

		virtual void ClearForce( void );

		virtual void ClearMotion( void );
		virtual void ClearMotion( const Mix::Quaternion& rot, const Mix::Vector3& pos );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::ICollider
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual Boolean IsDefault( void ) const;
		virtual Boolean IsStatic( void ) const;
		virtual Boolean IsKinematic( void ) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IDynamicsObject
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual Mix::Scene::IDynamicsObject::TYPE GetType( void ) const;

		virtual Boolean GetOwner( Mix::Scene::IRendererObject** ppOwner );
		virtual Mix::Scene::IRendererObject* GetOwnerPtr( void ) const;

		virtual Mix::Matrix4x4 GetWorldMatrix( void ) const;
		virtual Mix::Quaternion GetWorldRotation( void ) const;
		virtual Mix::Vector3 GetWorldPosition( void ) const;

		virtual Boolean HasContactListener( void ) const;
		virtual Boolean ContainsContactListener( Mix::Scene::IContactListener* pListener ) const;
		virtual Boolean AddContactListener( Mix::Scene::IContactListener* pListener );
		virtual Boolean RemoveContactListener( Mix::Scene::IContactListener* pListener );
		virtual void ClearContactListener( void );

		virtual Int32 GetUserIndex( void )  const;
		virtual void SetUserIndex( Int32 index );

		virtual void* GetUserPtr( void ) const;
		virtual void SetUserPtr( void* ptr );

	private:
		static const UInt16 DEFAULT_FILTER_GROUP;
		static const UInt16 DEFAULT_FILTER_MASK;
		static const UInt16 STATIC_FILTER_GROUP;
		static const UInt16 STATIC_FILTER_MASK;
		static const UInt16 KINEMATIC_FILTER_GROUP;
		static const UInt16 KINEMATIC_FILTER_MASK;
	};

}}}
