#pragma once

#include "Mix/Geometry/AABB.h"
#include "Mix/Scene/ITerrainModel.h"
#include "Mix/Private/Scene/Common/RendererObject.h"
#include "Mix/Private/Scene/Common/Model.h"

namespace Mix{ namespace Scene{ namespace Common{

	class TerrainNode;
	class TerrainCollider;

	class TerrainModel : public Mix::Scene::ITerrainModel, public Mix::Scene::Common::RendererObject, public Mix::Scene::Common::Model
	{
	private:
		typedef Mix::STL::Vector<Mix::Memory::SECTION_SCENE, Mix::Scene::Common::TerrainNode*> NodeList;

	private:
		Mix::StringW m_Name;

		TerrainModel::NodeList m_NodeList;

		Mix::Vector3 m_WorldPos;
		Mix::Matrix4x4 m_WorldMatrix;

		Mix::Scene::Common::TerrainCollider* m_pCollider;

		Int32 m_UserIndex;
		void* m_pUserPtr;

		Boolean m_bDraw;
		Boolean m_bLocalLighting;
		UInt32 m_TRPriority;
		Mix::Scene::WATER_CONTAINS_RESULT m_DefWCResult;

	public:
		static TerrainModel* CreateInstance( const wchar_t* pName ); 

	private:
		TerrainModel( const wchar_t* pName );
		virtual ~TerrainModel( void );

		void UpdateNodeBounds( Mix::Scene::Common::TerrainNode* pNode );

	public:
		void Attach( void );
		void Detach( void );

		const Mix::Matrix4x4& GetWorldMatrix( void ) const;

		Mix::Scene::Common::TerrainNode** AllocateNodeList( size_t count );
		Mix::Scene::Common::TerrainNode* GetRootNodePtr( void ) const;

		Boolean CreateCollider( Mix::Dynamics::IStaticMesh* pStaticMesh );

	public:
		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::Common::Model
		////////////////////////////////////////////////////////////////////////////////////////////////////

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

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::ITerrainModel
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual const wchar_t* GetName( void ) const;

		virtual void SetWorldPosition( const Mix::Vector3& pos );
		virtual const Mix::Vector3& GetWorldPosition( void ) const;

		virtual Boolean ExistsCollider( void ) const;
		virtual Boolean GetCollider( Mix::Scene::ITerrainCollider** ppCollider );

		virtual Boolean Clone( Mix::Scene::ITerrainModel** ppTerrainModel, UInt32 flags );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IModel
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual UInt32 GetMaterialSlotCount( void ) const;
		virtual const wchar_t* GetMaterialSlotName( UInt32 slotIndex ) const;
		virtual UInt32 GetMaterialSlotIndex( const wchar_t* pMaterialSlotName );
		virtual Boolean GetMaterialByIndex( UInt32 slotIndex, Mix::Scene::IMaterial** ppMaterial );
		virtual Boolean GetMaterialByName( const wchar_t* pSlotName, Mix::Scene::IMaterial** ppMaterial );
		virtual Boolean SetMaterialByIndex( UInt32 slotIndex, Mix::Scene::IMaterial* pMaterial );
		virtual Boolean SetMaterialByName( const wchar_t* pSlotName, Mix::Scene::IMaterial* pMaterial );

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

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

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IEntity
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual Boolean IsDraw( void ) const;
		virtual void SetDraw( Boolean state );

		virtual Boolean IsLocalLighting( void ) const;
		virtual void SetLocalLighting( Boolean state );

		virtual UInt32 GetTransparencyPriority( void ) const;
		virtual void SetTransparencyPriority( UInt32 priority );

		virtual Mix::Scene::WATER_CONTAINS_RESULT GetDefaultWaterContainsResult( void ) const;
		virtual void SetDefaultWaterContainsResult( Mix::Scene::WATER_CONTAINS_RESULT result );

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

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

	private:
		static const wchar_t* FAILED_CLONE;
	};

}}}
