#pragma once

#include "Mix/Scene/IScatterParticle.h"
#include "Mix/Geometry/AABB.h"
#include "Mix/Private/Container.h"
#include "Mix/Private/Scene/Common/WidgetTypes.h"
#include "Mix/Private/Scene/Common/RendererObject.h"
#include "Mix/Private/Scene/Common/InternalParticle.h"
#include "Mix/Private/Scene/Common/OctreeObject.h"

namespace Mix{ namespace Scene{ namespace Common{

	class Octree;

#ifdef _DEBUG
	class ScatterParticle;
#endif //_DEBUG

	class ScatterParticleUnit
	{
	private:
		Boolean bBillboard;
		Mix::Matrix4x4 worldMat;
		Mix::Scene::IParticleProcessor* pProcessor;
		Mix::Scene::Common::WIDGET_SPHERE_SUBSET subset;
		Mix::Scene::Common::ScatterParticleUnitObject* pOctObj;

		Boolean bLocalLighting;

		Boolean bDraw;
		Mix::Scene::WATER_CONTAINS_RESULT defWCR;

		//作業用
		UInt32 faceNum;
		const Mix::Scene::IParticleProcessor::FACE* faces;
		UInt32 quadOffset;

		//リンク
		ScatterParticleUnit* pPrev;
		ScatterParticleUnit* pNext;

#ifdef _DEBUG
		void* pDebList; // UNIT_LIST のポインタ
		Mix::Scene::IParticleGenerator* pDebGenerator;
		Mix::Scene::Common::ScatterParticle* pDebOwner;
#endif //_DEBUG

	private:
		MIX_DECLARE_ALLOCATOR();

		ScatterParticleUnit( void );
		~ScatterParticleUnit( void );

	public:
		Boolean InternalRefresh( const Mix::Matrix4x4& bbMat );
		const Mix::Geometry::Sphere& GetBounds( void ) const;
		Mix::Scene::Common::WIDGET_SPHERE_SUBSET* GetSubsetPtr( void );
		Boolean CanLocalLighting( void ) const;
		Boolean IsDraw( void ) const;
		Mix::Scene::WATER_CONTAINS_RESULT GetDefaultWaterContainsResult( void ) const;

#ifdef _DEBUG
		UInt32 Debug_GetVertexStride( void ) const;
#endif //_DEBUG

		friend class ScatterParticle;
	};

	class ScatterParticle : public Mix::Scene::IScatterParticle, public Mix::Scene::Common::RendererObject, public Mix::Scene::Common::InternalParticle
	{
	private:
		struct UNIT_LIST
		{
			ScatterParticleUnit* pTop;
			ScatterParticleUnit* pBottom;
			UInt32 count;
		};

		static void UnitList_Init( UNIT_LIST& list );
		static void UnitList_Add( UNIT_LIST& list, ScatterParticleUnit* pUnit );
		static void UnitList_Remove( UNIT_LIST& list, ScatterParticleUnit* pUnit );

	public:
		static ScatterParticle* CreateInstance( Mix::Scene::IMaterial* pMaterial,
												Mix::Scene::IParticleSystem* pSystem,
												UInt32 defUnitCapacity,
												UInt32 defQuadCapacity,
												UInt32 quadResizeStep,
												const wchar_t* pDebugName );

#ifdef _DEBUG
		static void Debug_Draw( Mix::Graphics::Utility::IPerspectiveRenderer* pPerspectiveRenderer, UInt32 flags, ScatterParticleUnit* pUnit );
#endif //_DEBUG

	private:
		Mix::Scene::Common::Octree* m_pOctree;
		Mix::Scene::IParticleSystem* m_pSystem;
		Mix::Scene::IParticleGenerator* m_pGenerator;

		Boolean m_bBillboard;

		ScatterParticle::UNIT_LIST m_UnitList;
		ScatterParticle::UNIT_LIST m_UnitPool;

		IScatterParticle::STATE m_State;

		Boolean m_bLocalLighting;

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

#ifdef _DEBUG
		Float32 m_DebugDrawAxisScaling;
#endif //_DEBUG

	private:
		ScatterParticle(	Mix::Scene::IMaterial* pMaterial,
							Mix::Scene::IParticleSystem* pSystem,
							UInt32 defUnitCapacity,
							UInt32 defQuadCapacity,
							UInt32 quadResizeStep,
							const wchar_t* pDebugName );

		virtual ~ScatterParticle( void );

		ScatterParticleUnit* AddUnit( const Mix::Matrix4x4& worldMat );
		ScatterParticleUnit* RemoveUnit( ScatterParticleUnit* pUnit );

		void FlashUnits( void );

	public:
		void Attach( Mix::Scene::Common::Octree* pOctree );
		void Detach( void );

#ifdef _DEBUG
		UInt32 Debug_GetVertexStride( void ) const;
#endif //_DEBUG

	public:
		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IScatterParticle
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual void Clear( void );
		virtual void Emit( const Mix::Matrix4x4& worldMat );
		virtual void Emit( const Mix::Matrix4x4& worldMat, UInt32 quadNum );
		virtual const Mix::Scene::IScatterParticle::STATE& GetState( void ) const;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::IParticle
		////////////////////////////////////////////////////////////////////////////////////////////////////

		virtual void Update( Float32 dt );

		virtual void Refresh( void );

		virtual void Refresh1( void );
		virtual void Refresh2( void );

		virtual Float32 Debug_GetDrawAxisScaling( void ) const;
		virtual void Debug_SetDrawAxisScaling( Float32 scaling );

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

		virtual void GetMaterial( Mix::Scene::IMaterial** ppMaterial );
		virtual Boolean SetMaterial( Mix::Scene::IMaterial* pMaterial );

		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;

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

}}}
