#pragma once

#include <vector>

#include "Mix/Timer.h"
#include "Mix/Geometry/AABB.h"
#include "Mix/Geometry/Frustum.h"
#include "Mix/Scene/ILeavingParticle.h"
#include "Mix/Scene/IParticleSystem.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 Material;

	class LeavingParticle : public Mix::Scene::ILeavingParticle, public Mix::Scene::Common::RendererObject, public Mix::Scene::Common::InternalParticle
	{
	private:
		enum STATUS
		{
			REQ_PLAY	= 0,
			PLAY		= 1,
			REQ_STOP	= 2,
			STOP		= 3,
		};

	public:
		static LeavingParticle* CreateInstance( Mix::Scene::IMaterial* pMaterial, Mix::Scene::IParticleSystem* pSystem, const wchar_t* pDebugName );

	private:
		Mix::Scene::IParticleSystem* m_pSystem;
		Mix::Scene::IParticleGenerator* m_pGenerator;
		Mix::Scene::IParticleProcessor* m_pProcessor;

		Boolean m_bBillboard;
		Boolean m_bSimWorldSpace;

		LeavingParticle::STATUS m_Status;

		Boolean m_bGenLoop;
		Float32 m_GenTime;
		Float32 m_GenTimeCounter;

		UInt32 m_RevisionCounter;

		Mix::Matrix4x4 m_WorldMat;
		Mix::Vector3 m_WorldPos;

		Mix::Scene::Common::WIDGET_AABB_SUBSET m_Subset;

		Mix::Scene::ILeavingParticle::STATE m_State;
		Float32 m_FarRatio;

		Boolean m_bLocalLighting;

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

		Mix::Scene::Common::LeavingParticleObject* m_pOctObj;

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

	private:
		LeavingParticle( Mix::Scene::IMaterial* pMaterial, Mix::Scene::IParticleSystem* pSystem, const wchar_t* pDebugName );
		virtual ~LeavingParticle( void );

	public:
		Boolean Initialize( void );

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

		Boolean InternalRefresh( const Mix::Vector3& eyePos, const Mix::Matrix4x4& bbMat );
		Mix::Scene::Common::WIDGET_AABB_SUBSET* GetSubsetPtr( void );

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

	public:
		////////////////////////////////////////////////////////////////////////////////////////////////////
		// Mix::Scene::ILeavingParticle
		////////////////////////////////////////////////////////////////////////////////////////////////////

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

		virtual Boolean IsPlay( void ) const;
		virtual void Play( Boolean bLoop );
		virtual void Play( Boolean bLoop, Float32 dt, UInt32 stepCount );
		virtual void Stop( Boolean bForce );

		virtual const Mix::Scene::ILeavingParticle::STATE& GetState( void ) const;

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

		virtual Boolean IsVisible( void ) const;
		virtual Boolean IsVisible( UInt32 id ) const;
		virtual Boolean IsIgnored( void ) const;

		virtual Boolean Clone( Mix::Scene::ILeavingParticle** ppParticle, UInt32 flags );

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 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;
	};

}}}
