#pragma once

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

namespace Mix{ namespace Dynamics{

	class DofJoint : public Mix::Dynamics::IDofJoint, public Mix::Dynamics::Joint
	{
	public:
		static DofJoint* CreateInstance(	Mix::Dynamics::IRigidBody* pRigidBodyA,
											const Mix::Quaternion& rotA,
											const Mix::Vector3& pivotA );

		static DofJoint* CreateInstance(	Mix::Dynamics::IRigidBody* pRigidBodyA,
											Mix::Dynamics::IRigidBody* pRigidBodyB,
											const Mix::Quaternion& rotA,
											const Mix::Quaternion& rotB,
											const Mix::Vector3& pivotA,
											const Mix::Vector3& pivotB );

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

		Mix::Quaternion m_RotA;
		Mix::Quaternion m_RotB;
		Mix::Vector3 m_PivotA;
		Mix::Vector3 m_PivotB;

		Mix::Vector3 m_LowerLinearLimit;
		Mix::Vector3 m_UpperLinearLimit;
		Mix::Vector3 m_LinearStiffness;
		Mix::Vector3 m_LinearDamping;
		Mix::Vector3 m_LinearLimitSpring;
		Mix::Vector3 m_LinearLimitDamper;

		Mix::Vector3 m_LowerAngularLimit;
		Mix::Vector3 m_UpperAngularLimit;
		Mix::Vector3 m_AngularStiffness;
		Mix::Vector3 m_AngularDamping;
		Mix::Vector3 m_AngularLimitSpring;
		Mix::Vector3 m_AngularLimitDamper;

		btGeneric6DofSpringConstraint* m_pObject;

	private:
		DofJoint(	Mix::Dynamics::IRigidBody* pRigidBodyA,
					const Mix::Quaternion& rotA,
					const Mix::Vector3& pivotA );

		DofJoint(	Mix::Dynamics::IRigidBody* pRigidBodyA,
					Mix::Dynamics::IRigidBody* pRigidBodyB,
					const Mix::Quaternion& rotA,
					const Mix::Quaternion& rotB,
					const Mix::Vector3& pivotA,
					const Mix::Vector3& pivotB );

		virtual ~DofJoint( void );

	public:
		Boolean Initialize( const wchar_t* pDebugName );
		void UpdateFrames( void );

	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::Quaternion& GetRotationA( void ) const;
		virtual void SetRotationA( const Mix::Quaternion& rot );

		virtual const Mix::Quaternion& GetRotationB( void ) const;
		virtual void SetRotationB( const Mix::Quaternion& rot );

		virtual void SetLinearLimit( const Mix::Vector3& lower, const Mix::Vector3& upper );
		virtual const Mix::Vector3& GetLinearLowerLimit( void ) const;
		virtual const Mix::Vector3& GetLinearUpperLimit( void ) const;
		virtual void SetLinearStiffness( const Mix::Vector3& stiffness );
		virtual const Mix::Vector3& GetLinearStiffness( void ) const;
		virtual void SetLinearDamping( const Mix::Vector3& damping );
		virtual const Mix::Vector3& GetLinearDamping( void ) const;
		virtual const Mix::Vector3& GetLinearLimitSpring( void ) const;
		virtual void SetLinearLimitSpring( const Mix::Vector3& spring );
		virtual const Mix::Vector3& GetLinearLimitDamper( void ) const;
		virtual void SetLinearLimitDamper( const Mix::Vector3& damper );

		virtual void SetAngularLimit( const Mix::Vector3& lower, const Mix::Vector3& upper );
		virtual const Mix::Vector3& GetAngularLowerLimit( void ) const;
		virtual const Mix::Vector3& GetAngularUpperLimit( void ) const;
		virtual void SetAngularStiffness( const Mix::Vector3& stiffness );
		virtual const Mix::Vector3& GetAngularStiffness( void ) const;
		virtual void SetAngularDamping( const Mix::Vector3& damping );
		virtual const Mix::Vector3& GetAngularDamping( void ) const;
		virtual const Mix::Vector3& GetAngularLimitSpring( void ) const;
		virtual void SetAngularLimitSpring( const Mix::Vector3& spring );
		virtual const Mix::Vector3& GetAngularLimitDamper( void ) const;
		virtual void SetAngularLimitDamper( const Mix::Vector3& damper );

		virtual void UpdateEquilibriumPoint( void );

	public:
		virtual btTypedConstraint* Bullet_GetTypedConstraintPtr( void ) const;

	public:
		static const wchar_t* FAILED_CREATE;
	};

}}
