#pragma once

#include "Mix/Tool/Win32/Core/Dynamics/HingeJoint.h"

class btVector3;
class btTransform;
class btRigidBody;
class btHingeConstraint;

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

	class World;

	class HingeJoint : public Mix::Tool::Win32::Dynamics::HingeJoint
	{
	private:
		enum PRIVATE_VALUE
		{
			PT_FIRST	= HingeJoint::PT_STOP_ERP,
			PT_LAST		= HingeJoint::PT_STOP_CFM,
			PT_MAX		= HingeJoint::PT_STOP_CFM + 1,
		};

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

		Mix::Tool::Win32::Dynamics::RigidBody* m_pRigidBodyA;
		Mix::Tool::Win32::Dynamics::RigidBody* m_pRigidBodyB;

		bool m_bInitalRigidBodyTransform;
		D3DXQUATERNION m_InitalRigidBodyRotA;
		D3DXVECTOR3 m_InitalRigidBodyPosA;
		D3DXQUATERNION m_InitalRigidBodyRotB;
		D3DXVECTOR3 m_InitalRigidBodyPosB;

		D3DXVECTOR3 m_PivotA;
		D3DXVECTOR3 m_PivotB;

		bool m_bCollisionDisabled;

		unsigned int m_ParamFlags;
		float m_ParamValues[HingeJoint::PT_MAX];

		D3DXVECTOR3 m_Axis;
		D3DXVECTOR3 m_NormAxis;
		float m_LowerLimit;
		float m_UpperLimit;

	public:
		HingeJoint( void );
		HingeJoint(	const D3DXVECTOR3& axis,
					float lowerLimit,
					float upperLimit,
					bool collisionDisabled,
					float limitSpring,
					float limitDamper );

		virtual ~HingeJoint( void );

		void SetWorldPtr( Mix::Tool::Win32::Dynamics::Impl::World* pWorld );

		virtual const D3DXVECTOR3& GetNormalizeAxis( void ) const;
		virtual const D3DXVECTOR3& GetAxis( void ) const;
		virtual void SetAxis( const D3DXVECTOR3& axis );

		virtual float GetLowerLimit( void ) const;
		virtual void SetLowerLimit( float rad );

		virtual float GetUpperLimit( void ) const;
		virtual void SetUpperLimit( float rad );

		virtual float GetLimitSpring( void ) const;
		virtual void SetLimitSpring( float value );

		virtual float GetLimitDamper( void ) const;
		virtual void SetLimitDamper( float value );

		virtual float GetNormalSpring( void ) const;
		virtual void SetNormalSpring( float value );

	public:
		virtual void ResetInitalRigidBodyTransform( void );
		virtual void SetInitalRigidBodyTransform(	const D3DXQUATERNION& rotA,
													const D3DXVECTOR3& posA,
													const D3DXQUATERNION& rotB,
													const D3DXVECTOR3& posB );

		virtual bool SetFrame(	Mix::Tool::Win32::Dynamics::RigidBody* pRigidBodyA,
								const D3DXVECTOR3& pivotA );

		virtual bool SetFrame(	Mix::Tool::Win32::Dynamics::RigidBody* pRigidBodyA,
								Mix::Tool::Win32::Dynamics::RigidBody* pRigidBodyB,
								const D3DXVECTOR3& pivotA,
								const D3DXVECTOR3& pivotB );

		virtual const Mix::Tool::Win32::Dynamics::RigidBody* GetRigidBodyA( void ) const;
		virtual D3DXVECTOR3 GetPivotA( void );
		virtual void SetPivotA( const D3DXVECTOR3& pivot );

		virtual const Mix::Tool::Win32::Dynamics::RigidBody* GetRigidBodyB( void ) const;
		virtual D3DXVECTOR3 GetPivotB( void );
		virtual void SetPivotB( const D3DXVECTOR3& pivot );

		virtual bool GetCollisionDisabled( void ) const;
		virtual void SetCollisionDisabled( bool state );

		virtual bool IsParamSupported( int type, int axis ) const;
		virtual bool IsParamEnabled( int type, int axis ) const;
		virtual float GetParam( int type, int axis ) const;
		virtual void SetParam( int type, int axis, float value );
		virtual void ResetParam( int type, int axis );

		virtual void Draw(	Mix::Tool::Win32::Graphics::LineHelper* pLineHelper,
							const D3DXVECTOR4& axisColor,
							const D3DXVECTOR4& ballColor,
							const D3DXVECTOR4& limitColor,
							float scale );

		virtual void* Bullet_GetTypedConstraintPtr( void );

	private:
		void BeginRefresh( void );
		void EndRefresh( void );
		void Refresh( void );
		void UpdateLimit( void );
		void UpdatePivot( void );
		void UpdateFrames( void );
		void UpdateParams( void );

		void Bullet_ComputeFrames(	const btRigidBody* rbA,
									const btVector3* pivotA,
									const btVector3* axis,
									btTransform* frameA,
									btTransform* frameB );

		void Bullet_ComputeFrames(	const btRigidBody* rbA,
									const btRigidBody* rbB,
									const btVector3* pivotA,
									const btVector3* pivotB,
									const btVector3* axis,
									btTransform* frameA,
									btTransform* frameB );
	};

}}}}}
