#pragma once

#include "Mix/Scene/IActorKinematicCharacter.h"
#include "Mix/Private/Scene/Common/DynamicsObject.h"
#include "Mix/Timer.h"

namespace Mix{ namespace Scene{ namespace Common{

	class ActorKinematicCharacter : public Mix::Scene::IActorKinematicCharacter, public Mix::Scene::Common::DynamicsObject
	{
	public:
		static ActorKinematicCharacter* CreateInstance(	Mix::Dynamics::IKinematicCharacter* pInternalObject,
														const Mix::Matrix4x4& loadMat,
														const Mix::Matrix4x4& storeMat );

	private:
		Mix::Scene::IRendererObject* m_pOwner;
		Mix::Dynamics::IKinematicCharacter* m_pInternalObject;

		Mix::Scene::DYNAMICS_KCHAR_MODE m_Mode;

		Mix::Matrix4x4 m_LoadMat;
		Mix::Matrix4x4 m_StoreMat;

		Float32 m_Gravity;
		Mix::Scene::DYNAMICS_FILTER m_FilterTable[Mix::Scene::DKC_MAX];
		Mix::Quaternion m_AngularVelocity;
		Mix::Vector3 m_LinearVelocity;

	protected:
		ActorKinematicCharacter(	Mix::Dynamics::IKinematicCharacter* pInternalObject,
									const Mix::Matrix4x4& loadMat,
									const Mix::Matrix4x4& storeMat );

		virtual ~ActorKinematicCharacter( void );

		void UpdateFilter( void );

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

		Mix::Scene::DYNAMICS_KCHAR_MODE GetMode( void ) const;
		void SetMode( Mix::Scene::DYNAMICS_KCHAR_MODE mode );

		void ApplyVelocity( const Mix::Quaternion& angularVelocity, const Mix::Vector3& linearVelocity );

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

		void Update( const Mix::Matrix4x4& baseMat );
//		void Update( const Mix::Quaternion& angularVelocity, const Mix::Vector3& linearVelocity );

		Boolean CanRefresh( void ) const;
		Mix::Matrix4x4 Refresh( const Mix::Vector3& worldS ) const;

		void Dispose( void );

		Mix::Scene::Common::ActorKinematicCharacter* Clone( void );

		Mix::Dynamics::IKinematicCharacter* GetInternalKinematicCharacterPtr( void ) const;

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

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

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IActorKinematicCharacter
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual UInt16 GetCurrentFilterGroup( void ) const;
		virtual UInt16 GetFilterGroup( Mix::Scene::DYNAMICS_KCHAR_MODE mode ) const;
		virtual void SetFilterGroup( Mix::Scene::DYNAMICS_KCHAR_MODE mode, UInt16 filterGroup );

		virtual UInt16 GetCurrentFilterMask( void ) const;
		virtual UInt16 GetFilterMask( Mix::Scene::DYNAMICS_KCHAR_MODE mode ) const;
		virtual void SetFilterMask( Mix::Scene::DYNAMICS_KCHAR_MODE mode, UInt16 filterMask );

		virtual const Mix::Quaternion& GetAngularVelocity( void ) const;
		virtual void SetAngularVelocity( const Mix::Quaternion& vel );

		virtual void Stand( UInt32 upAxisIndex, const Mix::Vector3& worldUp );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IKinematicCharacter
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual Float32 GetHeight( void ) const;
		virtual Float32 GetRadius( void ) const;

		virtual Float32 GetGravity( void ) const;
		virtual void SetGravity( Float32 gravity );

		virtual Float32 GetMaxFallSpeed( void ) const;
		virtual void SetMaxFallSpeed( Float32 speed );

		virtual Float32 GetInitalJumpSpeed( void ) const;
		virtual void SetInitalJumpSpeed( Float32 speed );

		virtual Float32 GetStepHeight( void ) const;
		virtual void SetStepHeight( Float32 height );

		virtual Float32 GetSlopeLimit( void ) const;
		virtual void SetSlopeLimit( Float32 rad );

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

		virtual Boolean OnGround( void ) const;

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

		virtual Float32 GetActiveThreshold( void ) const;
		virtual void SetActiveThreshold( Float32 threshold );
		virtual Float32 GetDeactivationElapsedTime( void ) const;
		virtual void SetDeactivationElapsedTime( Float32 elapsedTime );

		virtual Boolean IsActive( void ) const;

		virtual Boolean CanJump( void ) const;
		virtual Boolean Jump( void );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 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 FILTER_CAST_GROUP;
		static const UInt16 FILTER_CAST_MASK;
		static const UInt16 FILTER_RECEIVE_GROUP;
		static const UInt16 FILTER_RECEIVE_MASK;
	};

}}}
