#pragma once

#include "Mix/Dynamics/IBallJoint.h"
#include "Mix/Private/Dynamics/Joint.h"

namespace Mix{ namespace Dynamics{

	class BallJoint : public Mix::Dynamics::IBallJoint, public Mix::Dynamics::Joint
	{
	private:
		enum PARAM_FLAG
		{
			PF_PIVOT_SPRING = 0x00000001,
			PF_PIVOT_DAMPER = 0x00000002,
			PF_LIMIT_SPRING = 0x00000004,
			PF_LIMIT_DAMPER = 0x00000008,
		};

	public:
		static BallJoint* CreateInstance(	Mix::Dynamics::IRigidBody* pRigidBodyA,
											const Mix::Vector3& posA,
											const Mix::Vector3& twistAxis,
											const Mix::Vector3& swingAxis );

		static BallJoint* CreateInstance(	Mix::Dynamics::IRigidBody* pRigidBodyA,
											Mix::Dynamics::IRigidBody* pRigidBodyB,
											const Mix::Vector3& posA,
											const Mix::Vector3& posB,
											const Mix::Vector3& twistAxis,
											const Mix::Vector3& swingAxis );

	private:
		Mix::Dynamics::IRigidBody* m_pRigidBodyA;
		Mix::Dynamics::IRigidBody* m_pRigidBodyB;
		btConeTwistConstraint* m_pObject;

		Mix::Vector3 m_PivotA;
		Mix::Vector3 m_PivotB;
		Mix::Vector3 m_SwingAxis;
		Mix::Vector3 m_TwistAxis;

		Float32 m_Damping;

		UInt32 m_ParamFlags;

	private:
		BallJoint(	Mix::Dynamics::IRigidBody* pRigidBodyA,
					const Mix::Vector3& posA,
					const Mix::Vector3& twistAxis,
					const Mix::Vector3& swingAxis );

		BallJoint(	Mix::Dynamics::IRigidBody* pRigidBodyA,
					Mix::Dynamics::IRigidBody* pRigidBodyB,
					const Mix::Vector3& posA,
					const Mix::Vector3& posB,
					const Mix::Vector3& twistAxis,
					const Mix::Vector3& swingAxis );

		virtual ~BallJoint( void );

		void UpdatePivots( void );
		void UpdateFrames( void );

		void Bullet_ComputeFrames(	const btRigidBody* rbA,
									const btVector3& posA,
									const btVector3& twistAxis,
									const btVector3& swingAxis,
									btTransform& frameA,
									btTransform& frameB );

		void Bullet_ComputeFrames(	const btRigidBody* rbA,
									const btRigidBody* rbB,
									const btVector3& posA,
									const btVector3& posB,
									const btVector3& twistAxis,
									const btVector3& swingAxis,
									btTransform& frameA,
									btTransform& frameB );

	public:
		Boolean Initialize( const wchar_t* pDebugName );

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

		virtual Boolean IsInWorld( void ) const;

		virtual Boolean IsEnabled( void ) const;
		virtual void SetEnabled( Boolean state );

		virtual Float32 GetBreakingImpulseThreshold( void ) const;
		virtual void SetBreakingImpulseThreshold( Float32 threshold );

		virtual Boolean IsSingle( void ) const;

		virtual void GetRigidBodyA( Mix::Dynamics::IRigidBody** ppRigidBody );
		virtual void GetRigidBodyB( Mix::Dynamics::IRigidBody** ppRigidBody );

		virtual const Mix::Vector3& GetPivotA( void ) const;
		virtual void SetPivotA( const Mix::Vector3& pivot );

		virtual const Mix::Vector3& GetPivotB( void ) const;
		virtual void SetPivotB( const Mix::Vector3& pivot );

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

		virtual Float32 Debug_GetDrawFrameMinSize( void ) const;
		virtual void Debug_SetDrawFrameMinSize( Float32 minSize );

		virtual Float32 Debug_GetDrawLimitScaling( void ) const;
		virtual void Debug_SetDrawLimitScaling( Float32 scaling );

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

	public:
		virtual const Mix::Vector3& GetTwistAxis( void ) const;
		virtual void SetTwistAxis( const Mix::Vector3& axis );

		virtual Float32 GetTwistLimit( void ) const;
		virtual void SetTwistLimit( Float32 limit );

		virtual const Mix::Vector3& GetSwingAxis( void ) const;
		virtual void SetSwingAxis( const Mix::Vector3& axis );

		virtual Float32 GetSwingLimit1( void ) const;
		virtual void SetSwingLimit1( Float32 limit );

		virtual Float32 GetSwingLimit2( void ) const;
		virtual void SetSwingLimit2( Float32 limit );

		virtual void SetDamping( Float32 damping );
		virtual Float32 GetDamping( void ) const;

		virtual Float32 GetPivotSpring( void ) const;
		virtual void SetPivotSpring( Float32 spring );

		virtual Float32 GetPivotDamper( void ) const;
		virtual void SetPivotDamper( Float32 damper );

		virtual Float32 GetLimitSpring( void ) const;
		virtual void SetLimitSpring( Float32 spring );

		virtual Float32 GetLimitDamper( void ) const;
		virtual void SetLimitDamper( Float32 damper );

	public:
		virtual btTypedConstraint* Bullet_GetTypedConstraintPtr( void ) const;

	public:
		static const Float32 DEF_DAMPING;
		static const wchar_t* FAILED_CREATE;

		static const Int32 DEBUG_DRAW_SWING_SEGMENTS;
		static const Float32 DEBUG_DRAW_TWIST_STEP_DEG;
	};

}}
