#pragma once

#include <map>
#include <vector>
#include "Mix/Tool/Win32/Core/Dynamics/RigidBody.h"

struct btDefaultMotionState;
class btCollisionShape;
class btCompoundShape;
class btRigidBody;

namespace Mix{ namespace Tool{ namespace Win32{ namespace Dynamics{ namespace Impl{

	class World;

	class RigidBody : public Mix::Tool::Win32::Dynamics::RigidBody
	{
	private:
		struct SHAPE_INFO
		{
			int* handle;

			int index;
			Mix::Tool::Win32::Dynamics::Shape* pShape;
			btCollisionShape* pCollisionShape;

			SHAPE_INFO( int* _handle, int _index, Mix::Tool::Win32::Dynamics::Shape* _pShape, btCollisionShape* _pCollisionShape )
			{
				handle = _handle;
				index = _index;
				pShape = _pShape;
				pCollisionShape = _pCollisionShape;
			}
		};

		typedef std::map<HANDLE, RigidBody::SHAPE_INFO> ShapeInfoMap;
		typedef std::vector<HANDLE> ShapeHandleList;

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

		btDefaultMotionState* m_pMotionState;
		btCompoundShape* m_pShape;
		btRigidBody* m_pRigidBody;

		RigidBody::ShapeInfoMap m_ShapeInfoMap;
		RigidBody::ShapeHandleList m_ShapeHandleList;

		HANDLE m_hHighlightShape;
		btCollisionShape* m_pHighlightShape;

		Mix::Tool::Win32::Dynamics::MATERIAL m_Material;

		float m_Mass;
		float m_InvMass;
		bool m_bPick;
		bool m_bAlwaysActive;
		RigidBody::STATUS m_Status;

		short m_Group;
		short m_GroupMask;

	public:
		RigidBody( void );
		virtual ~RigidBody( void );

		bool Initialize( void );
		void SetWorldPtr( Mix::Tool::Win32::Dynamics::Impl::World* pWorld );
		void SetPick( bool state );

		btRigidBody* Bullet_GetRigidBodyPtr( void );

	private:
		void BeginRefresh( void );
		void EndRefresh( void );

		bool UpdateShapeIndex( void );
		void UpdateInertiaTensor( float mass );
		void UpdateInertiaTensor( void );
		void UpdateStatus( void );

	public:
		virtual HANDLE AddShape( Mix::Tool::Win32::Dynamics::Shape* pShape, const D3DXQUATERNION& rot, const D3DXVECTOR3& pos );
		virtual bool RemoveShape( const HANDLE handle );

		virtual Mix::Tool::Win32::Dynamics::Shape* GetShape( const HANDLE handle ) const;
		virtual bool SetShape( const HANDLE handle, Mix::Tool::Win32::Dynamics::Shape* pShape );

		virtual bool SetShapeTransform( const HANDLE handle, const D3DXQUATERNION& rot, const D3DXVECTOR3& pos );

		virtual bool GetShapeRotation( const HANDLE handle, D3DXQUATERNION& rot ) const;
		virtual bool SetShapeRotation( const HANDLE handle, const D3DXQUATERNION& rot );

		virtual bool GetShapePosition( const HANDLE handle, D3DXVECTOR3& pos ) const;
		virtual bool SetShapePosition( const HANDLE handle, const D3DXVECTOR3& pos );

		virtual void SetHighlightShape( const HANDLE handle );
		virtual const HANDLE GetHighlightShapeHandle( void ) const;

		virtual int GetShapeHandleCount( void ) const;
		virtual const HANDLE GetShapeHandle( int index ) const;

		virtual float GetMass( void ) const;
		virtual float GetInvMass( void ) const;
		virtual void SetMass( float mass );

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

		virtual D3DXVECTOR3 GetLinearVelocity( void );
		virtual void SetLinearVelocity( const D3DXVECTOR3& vel );

		virtual D3DXVECTOR3 GetAngularVelocity( void );
		virtual void SetAngularVelocity( const D3DXVECTOR3& vel );

		virtual D3DXVECTOR3 GetLinearFactor( void );
		virtual void SetLinearFactor( const D3DXVECTOR3& factor );

		virtual D3DXVECTOR3 GetAngularFactor( void );
		virtual void SetAngularFactor( const D3DXVECTOR3& factor );

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

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

		virtual bool GetAlwaysActive( void ) const;
		virtual void SetAlwaysActive( bool state );

		virtual RigidBody::STATUS GetStatus( void ) const;
		virtual void SetStatus( RigidBody::STATUS status );

		virtual void Reset( void );
		virtual void Reset( const D3DXQUATERNION& rot, const D3DXVECTOR3& pos );

		virtual void Activate( void );
		virtual void Deactivate( void );

		virtual void ApplyImpulse( const D3DXVECTOR3& impulse );
		virtual void ApplyImpulse( const D3DXVECTOR3& impulse, const D3DXVECTOR3& relPos );

		virtual void Draw( Mix::Tool::Win32::Graphics::LineHelper* pLineHelper, const D3DXVECTOR4& defColor, const D3DXVECTOR4& selColor );

	public:
		virtual short GetGroup( void ) const;
		virtual void SetGroup( short data );

		virtual short GetGroupMask( void ) const;
		virtual void SetGroupMask( short data );

		virtual D3DXQUATERNION GetWorldRotation( void ) const;
		virtual void SetWorldRotation( const D3DXQUATERNION& rot );

		virtual D3DXVECTOR3 GetWorldPosition( void ) const;
		virtual void SetWorldPosition( const D3DXVECTOR3& pos );

		virtual D3DXMATRIX GetWorldMatrix( void ) const;
		virtual void SetWorldMatrix( const D3DXMATRIX& mat );

		virtual void SetWorldTransform( const D3DXQUATERNION& rot, const D3DXVECTOR3& pos );

		virtual bool IsInWorld( void ) const;

		virtual void Draw( Mix::Tool::Win32::Graphics::LineHelper* pLineHelper, const D3DXVECTOR4& color );

		friend class Factory;
	};

}}}}}
