#pragma once

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

class btVector3;
class btTransform;
class btRigidBody;
class btConeTwistConstraint;

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

	class World;

	class BallJoint : public Mix::Tool::Win32::Dynamics::BallJoint
	{
	private:
		static const int DRAW_SWING_SEGMENTS;
		static const float DRAW_TWIST_STEP_DEG;

		enum PRIVATE_VALUE
		{
			PT_MAX	= BallJoint::PT_CFM + 1,
			PA_MAX	= BallJoint::PA_ROTATION + 1,
		};

	private:
		btConeTwistConstraint* 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;

		bool m_bCollisionDisabled;

		unsigned int m_ParamFlags;
		float m_ParamValues[BallJoint::PT_MAX][BallJoint::PA_MAX];

		D3DXVECTOR3 m_PivotA;
		D3DXVECTOR3 m_PivotB;
		D3DXVECTOR3 m_SwingAxis;
		D3DXVECTOR3 m_TwistAxis;
		D3DXVECTOR3 m_NormSwingAxis;
		D3DXVECTOR3 m_NormTwistAxis;
		float m_SwingLimit1;
		float m_SwingLimit2;
		float m_TwistLimit;

	public:
		BallJoint( void );
		BallJoint(	const D3DXVECTOR3& swingAxis,
					const D3DXVECTOR3& twistAxis,
					float swingLimit1,
					float swingLimit2,
					float twistLimit,
					bool bCollisionDisabled,
					float spring,
					float damper,
					float limitSpring,
					float limitDamper );

		virtual ~BallJoint( void );

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

		virtual const D3DXVECTOR3& GetNormalizeSwingAxis( void ) const;
		virtual const D3DXVECTOR3& GetSwingAxis( void ) const;
		virtual void SetSwingAxis( const D3DXVECTOR3& axis );

		virtual const D3DXVECTOR3& GetNormalizeTwistAxis( void ) const;
		virtual const D3DXVECTOR3& GetTwistAxis( void ) const;
		virtual void SetTwistAxis( const D3DXVECTOR3& axis );

		virtual float GetSwingLimit1( void ) const;
		virtual void SetSwingLimit1( float rad );

		virtual float GetSwingLimit2( void ) const;
		virtual void SetSwingLimit2( float rad );

		virtual float GetTwistLimit( void ) const;
		virtual void SetTwistLimit( float rad );

		virtual float GetSpring( void ) const;
		virtual void SetSpring( float value );

		virtual float GetDamper( void ) const;
		virtual void SetDamper( float value );

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

		virtual float GetLimitDamper( void ) const;
		virtual void SetLimitDamper( 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 const Mix::Tool::Win32::Dynamics::RigidBody* GetRigidBodyB( void ) const;

		virtual D3DXVECTOR3 GetPivotA( void );
		virtual void SetPivotA( const D3DXVECTOR3& pivot );

		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* swingAxis,
									const btVector3* twistAxis,
									btTransform* frameA,
									btTransform* frameB );

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

		static unsigned int GetParamBit( int type, int axis );
	};

}}}}}
