#pragma once

#include "Mix/Scene/IDynamicsWorld.h"
#include "Mix/Dynamics/IObjectListener.h"
#include "Mix/Dynamics/IWorld.h"
#include "Mix/Private/Scene/Common/RendererObject.h"

namespace Mix{ namespace Scene{ namespace Common{

	class Camera;

	class DynamicsWorld : public Mix::Scene::IDynamicsWorld, public Mix::Scene::Common::RendererObject
	{
	private:
		class ContactProcessor : public Mix::Dynamics::IObjectListener
		{
		private:
			enum PRIVATE_VALUE
			{
				DEF_CONTACT_POINTS_CAPACITY = 32,
			};

		private:
			Mix::STL::Vector<Mix::Memory::SECTION_SCENE, Mix::Scene::DYNAMICS_CONTACT_POINT> m_Points;

		public:
			static ContactProcessor* CreateInstance( void );

		private:
			ContactProcessor( void );
			virtual ~ContactProcessor( void );

		public:
			virtual void OnAddedToWorld( Mix::Dynamics::IObject* pObject, Mix::Dynamics::IWorld* pWorld );
			virtual void OnRemovedFromWorld( Mix::Dynamics::IObject* pObject, Mix::Dynamics::IWorld* pWorld );
			virtual void OnContact( Mix::Dynamics::IObject* pObject, const Mix::Dynamics::MANIFOLD& manifold );
		};

		class InternalTestCallback : public Mix::Dynamics::IWorld::TestCallback
		{
		private:
			Mix::Scene::IDynamicsWorld::TestCallback* m_pCallback;

		public:
			InternalTestCallback( Mix::Scene::IDynamicsWorld::TestCallback* pCallback );
			virtual ~InternalTestCallback( void );

		public:
			virtual Boolean OnHit( Mix::Dynamics::IObject* pObject );
		};

	public:
		static DynamicsWorld* CreateInstance( const Mix::Dynamics::WORLD_CONFIG& config );

	private:
		Mix::Dynamics::IWorld* m_pWorld;
		DynamicsWorld::ContactProcessor* m_pContactProc;
		Mix::Dynamics::WORLD_CONFIG m_Config;

	private:
		DynamicsWorld( const Mix::Dynamics::WORLD_CONFIG& config );
		virtual ~DynamicsWorld( void );

	public:
		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::Common::DynamicsWorld
		////////////////////////////////////////////////////////////////////////////////////////////////////

		Boolean Initialize( const wchar_t* pDebugName );
		void Dispose( void );

		Mix::Dynamics::IObjectDragger* CreateObjectDragger( const wchar_t* pDebugName );

		Mix::Dynamics::IWorld* GetInternalWorldPtr( void ) const;
		Mix::Dynamics::IObjectListener* GetInternalObjectListenerPtr( void ) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IDynamicsWorld
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual const Mix::Vector3& GetGravity( void ) const;
		virtual void SetGravity( const Mix::Vector3& gravity );

		virtual UInt32 Activate( void );
		virtual UInt32 Deactivate( Boolean bForce );

		virtual Boolean TestRay(	UInt16 filterMask,
									const Mix::Vector3& fromWorldPos,
									const Mix::Vector3& toWorldPos,
									Mix::Scene::IDynamicsWorld::TestCallback* pCallback,
									Mix::Scene::IDynamicsWorld::TEST_RESULT& result );

		virtual Boolean TestSweep(	UInt16 filterMask,
									Mix::Dynamics::IShape* pShape,
									const Mix::Vector3& fromWorldPos,
									const Mix::Vector3& toWorldPos,
									Mix::Scene::IDynamicsWorld::TestCallback* pCallback,
									Mix::Scene::IDynamicsWorld::TEST_RESULT& result );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IRendererObject
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual Mix::Scene::IRendererObject::TYPE GetType( void ) const;
		virtual Boolean IsRendering( void ) const;
	};

}}}
