#pragma once

#include "Mix/Dynamics/IRigidBody.h"
#include "Mix/Private/Dynamics/Object.h"
#include "Mix/Private/Container.h"

namespace Mix{ namespace Dynamics{

	class ObjectContext;
	class World;

	class RigidBody : public Mix::Dynamics::IRigidBody, public Mix::Dynamics::Object
	{
	private:
		struct USM_WORK
		{
			Mix::Dynamics::IShape* pShape;
			Mix::Dynamics::MATERIAL material;
		};

	public:
		static RigidBody* CreateInstance( Float32 mass, Mix::Dynamics::IShape* pShape );

	private:
		Mix::Dynamics::IShape* m_pShape;
		Mix::Dynamics::ICompoundShape* m_pCompoundShape;
		Mix::Dynamics::ObjectContext* m_pContext;

		Mix::Dynamics::IRigidBody::STATUS m_Status;
		Float32 m_Mass;
		btDefaultMotionState* m_pMotionState;
		btRigidBody* m_pObject;

		Boolean m_bAlwaysActive;

		Int32 m_UserIndex;
		void* m_pUserPtr;

	private:
		RigidBody( Float32 mass, Mix::Dynamics::IShape* pShape );
		virtual ~RigidBody( void );

		void UpdateStatus( void );
		Int32 GetActivationState( void ) const;

	public:
		Boolean Initialize( const wchar_t* pDebugName );

	public:
		virtual Mix::Dynamics::ObjectContext* GetContextPtr( void ) const;

		virtual btCollisionObject* Bullet_GetCollisionObjectPtr( void ) const;
		virtual btRigidBody* Bullet_GetRigidBodyPtr( void ) const;

	public:
		virtual Boolean IsSimulationEnabled( void ) const;
		virtual void SetSimulationEnabled( Boolean state );

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

		virtual Mix::Dynamics::IRigidBody::STATUS GetStatus( void ) const;
		virtual Boolean SetStatus( Mix::Dynamics::IRigidBody::STATUS status );

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

		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 Mix::Vector3 GetTotalLinearForce( void );
		virtual Mix::Vector3 GetTotalAngularForce( void );
		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 void ClearForce( void );

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

		virtual Boolean UpdateLocalInertia( void );

	public:
		virtual Mix::Dynamics::IObject::TYPE GetType( void ) const;

		virtual Boolean GetShape( Mix::Dynamics::IShape** ppShape );

		virtual Float32 GetShapeMargin( void ) const;
		virtual void SetShapeMargin( Float32 margin );

		virtual UInt16 GetFilterGroup( void ) const;
		virtual void SetFilterGroup( UInt16 filterGroup );

		virtual UInt16 GetFilterMask( void ) const;
		virtual void SetFilterMask( UInt16 filterMask );

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

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

		virtual void SetWorldRotation( const Mix::Quaternion& rotation );
		virtual void SetWorldPosition( const Mix::Vector3& pos );
		virtual void SetWorldTransform( const Mix::Quaternion& rot, const Mix::Vector3& pos );

		virtual Boolean IsInWorld( void ) const;

		virtual Mix::Geometry::AABB GetBounds( void ) const;

		virtual Boolean AddListener( Mix::Dynamics::IObjectListener* pListener );
		virtual void RemoveListener( Mix::Dynamics::IObjectListener* pListener );

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

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

		virtual UInt32 Debug_GetDrawFlags( void ) const;
		virtual void Debug_SetDrawFlags( UInt32 flags );

		virtual Float32 Debug_GetDrawAxisScaling( void ) const;
		virtual void Debug_SetDrawAxisScaling( Float32 scaling );

		virtual void Debug_Draw( Mix::Graphics::Utility::IPerspectiveRenderer* pPerspectiveRenderer, Float32 opacity );

	public:
		static const wchar_t* FAILED_CREATE;
	};

}}
