#pragma once

#include "Mix/Scene/IFloor.h"
#include "Mix/Scene/ISimpleCollider.h"
#include "Mix/Private/Scene/Common/RendererObject.h"
#include "Mix/Private/Scene/Common/DynamicsObject.h"

namespace Mix{ namespace Scene{ namespace Common{

	class Floor : public Mix::Scene::IFloor, public Mix::Scene::Common::RendererObject
	{
	private:
		class InternalCollider : public Mix::Scene::ISimpleCollider, public Mix::Scene::Common::DynamicsObject
		{
		public:
			Mix::Scene::IRendererObject* m_pOwner;
			Mix::Dynamics::IStaticPlane* m_pStaticPlane;

		public:
			static InternalCollider* CreateInstance( Mix::Scene::IRendererObject* pOwner );

		private:
			InternalCollider( Mix::Scene::IRendererObject* pOwner );
			virtual ~InternalCollider( void );

		public:
			Boolean Initialize(	const Mix::Vector3& normal, Float32 offset, const wchar_t* pDebugName );

			void Dispose( void );

			void SetWorldRotation( const Mix::Quaternion& rot );
			void SetWorldPosition( const Mix::Vector3& pos );
			void SetWorldMatrix( const Mix::Matrix4x4& mat );

			Mix::Dynamics::IStaticPlane* GetStaticPlanePtr( void ) const;

		public:
			////////////////////////////////////////////////////////////////////////////////////////////////////
			// Mix::Scene::Common::DynamicsObject
			////////////////////////////////////////////////////////////////////////////////////////////////////

			virtual Mix::Dynamics::IObject* GetInternalObjectPtr( void ) const;

			////////////////////////////////////////////////////////////////////////////////////////////////////
			// Mix::Scene::ISimpleCollider
			////////////////////////////////////////////////////////////////////////////////////////////////////

			virtual UInt16 GetFilterGroup( void ) const;
			virtual void SetFilterGroup( UInt16 filterGroup );

			virtual UInt16 GetFilterMask( void ) const;
			virtual void SetFilterMask( UInt16 filterMask );

			virtual const Mix::Dynamics::MATERIAL& GetMaterial( void ) const;
			virtual void SetMaterial( const Mix::Dynamics::MATERIAL& material );

			////////////////////////////////////////////////////////////////////////////////////////////////////
			// Mix::Scene::ICollider
			////////////////////////////////////////////////////////////////////////////////////////////////////

			virtual Boolean IsDefault( void ) const;
			virtual Boolean IsStatic( void ) const;
			virtual Boolean IsKinematic( void ) const;

			////////////////////////////////////////////////////////////////////////////////////////////////////
			// Mix::Scene::IDynamicsObject
			////////////////////////////////////////////////////////////////////////////////////////////////////
	
			virtual Mix::Scene::IDynamicsObject::TYPE GetType( void ) const;

			virtual Boolean GetOwner( Mix::Scene::IRendererObject** ppOwner );
			virtual Mix::Scene::IRendererObject* GetOwnerPtr( void ) const;

			virtual Mix::Matrix4x4 GetWorldMatrix( void ) const;
			virtual Mix::Quaternion GetWorldRotation( void ) const;
			virtual Mix::Vector3 GetWorldPosition( void ) const;

			virtual Boolean HasContactListener( void ) const;
			virtual Boolean ContainsContactListener( Mix::Scene::IContactListener* pListener ) const;
			virtual Boolean AddContactListener( Mix::Scene::IContactListener* pListener );
			virtual Boolean RemoveContactListener( Mix::Scene::IContactListener* pListener );
			virtual void ClearContactListener( void );

			virtual Int32 GetUserIndex( void )  const;
			virtual void SetUserIndex( Int32 index );

			virtual void* GetUserPtr( void ) const;
			virtual void SetUserPtr( void* ptr );
		};

	public:
		static Floor* CreateInstance( void );

	private:
		Floor::InternalCollider* m_pCollider;
		Int32 m_UserIndex;
		void* m_UserPtr;

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

	public:
		Boolean Initialize( const Mix::Vector3& normal, Float32 offset, const wchar_t* pDebugName );

		void Attach( void );
		void Detach( void );

		void AttachDynamics( Mix::Dynamics::IWorld* pWorld, Mix::Dynamics::IObjectListener* pObjectListener );
		void DetachDynamics( Mix::Dynamics::IWorld* pWorld );

		Mix::Dynamics::IObject* GetInternalObjectPtr( void ) const;

	public:
		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IFloor
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual Boolean GetDynamicsObject( Mix::Scene::IDynamicsObject** ppDynamicsObject );

		virtual Mix::Quaternion GetWorldRotation( void ) const;
		virtual void SetWorldRotation( const Mix::Quaternion& rot );

		virtual Int32 GetUserIndex( void )  const;
		virtual void SetUserIndex( Int32 index );

		virtual void* GetUserPtr( void ) const;
		virtual void SetUserPtr( void* pData );

		virtual Float32 Debug_GetDrawInterval( void ) const;
		virtual void Debug_SetDrawInterval( Float32 interval );

		virtual UInt32 Debug_GetDrawExtent( void ) const;
		virtual void Debug_SetDrawExtent( UInt32 extent );

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

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

	public:
		static const wchar_t* FAILED_CREATE;
	};

}}}
