#pragma once

#include "Mix/Scene/IPlanter.h"
#include "Mix/Private/Container.h"
#include "Mix/Private/Scene/Common/RendererTypes.h"
#include "Mix/Private/Scene/Common/WidgetTypes.h"
#include "Mix/Private/Scene/Common/RendererObject.h"
#include "Mix/Private/Scene/Common/OctreeObject.h"
#include "Mix/Private/Scene/Common/FlowerPackage.h"

namespace Mix{ namespace Scene{ namespace Common{

	class Planter : public Mix::Scene::IPlanter, public Mix::Scene::Common::RendererObject
	{
	private:
		enum PRIVATE_VALUE
		{
			QUADS_DEF_SIZE		= 64,
			QUADS_RESIZE_STEP	= 4,
		};

		struct INTERNAL_UNIT
		{
			const Mix::Scene::Common::FlowerPackage::INTERNAL_MODEL* pModel;
			Mix::Scene::IPlanter::UNIT src;
			Mix::Matrix4x4 worldMat;
			UInt32 quadStart;
		};

		typedef Mix::STL::Vector<Mix::Memory::SECTION_SCENE, INTERNAL_UNIT> UnitList;
		typedef Mix::STL::Vector<Mix::Memory::SECTION_SCENE, Mix::Scene::Common::WIDGET_SPHERE_SUBSET> SubsetList;

	public:
		static Planter* CreateInstance( Mix::Scene::IFlowerPackage* pFlowerPackage,
										UInt32 numUnit, const Mix::Scene::IPlanter::UNIT* units,
										const Mix::Matrix4x4& worldMat,
										const wchar_t* pDebugName );

	private:
		Mix::Scene::Common::FlowerPackage* m_pFlowerPackage;
		Mix::Matrix4x4 m_WorldMat;

		Planter::UnitList m_UnitList;

		UInt32 m_Status;
		Mix::DynamicContainerT<Mix::Scene::Common::WIDGET_QUAD, Mix::Memory::SECTION_SCENE> m_Quads;
		Planter::SubsetList m_SubsetList;
		Mix::Geometry::AABB m_Bounds;
		Mix::Scene::Common::PlanterObject* m_pOctObj;

		Boolean m_bLocalLighting;

		Boolean m_bDraw;
		UInt32 m_TRPriority;
		Mix::Scene::WATER_CONTAINS_RESULT m_WCResult;

#ifdef _DEBUG
		Mix::StringW m_DebugName;
#endif //_DEBUG

	protected:
		Planter(	Mix::Scene::IFlowerPackage* pFlowerPackage,
					UInt32 numUnit, const Mix::Scene::IPlanter::UNIT* units,
					const Mix::Matrix4x4& worldMat,
					const wchar_t* pDebugName );

		virtual ~Planter( void );

	private:
		void UpdateUnitsTransform( void );
		void UpdateQuads( void );
		void UpdateQuads( UInt32 index );
		void FlashSubsets( void );

	public:
		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::Common::Planter
		////////////////////////////////////////////////////////////////////////////////////////////////////

		void Attach( Mix::Scene::Common::PlanterObject* pOctObj );
		void Detach( void );

		Boolean InternalRefresh( Float32 foStartZ, Float32 foMidZ, Float32 foEndZ, Float32 z );

		UInt32 GetSubsetCount( void ) const;
		Mix::Scene::Common::WIDGET_SPHERE_SUBSET* GetSubsets( void );

		void OnMaterialChanged( void );
		void OnFlowerModelModified( UInt32 index );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IPlanter
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual const Mix::Matrix4x4& GetWorldMatrix( void ) const;
		virtual void SetWorldMatrix( const Mix::Matrix4x4& worldMat );

		virtual UInt32 GetUnitCount( void ) const;
		virtual const Mix::Scene::IPlanter::UNIT& GetUnit( UInt32 index ) const;
		virtual Boolean SetUnit( UInt32 index, const Mix::Scene::IPlanter::UNIT& unit );
		virtual Boolean AddUnit( const Mix::Scene::IPlanter::UNIT& unit );
		virtual Boolean RemoveUnit( UInt32 index );
		virtual void ClearUnits( void );

		virtual void Refresh( void );

		virtual const Mix::Geometry::AABB& GetBounds( void ) const;

		virtual Boolean IsIgnored( void ) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IWidget
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual Boolean CanLocalLighting( void ) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 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 UInt32 DEF_STATUS;

	public:
		static const wchar_t* FAILED_CREATE;
		static const wchar_t* FAILED_SET_MATERIAL;
	};

}}}
