#pragma once

#include <vector>

#include "Mix/Scene/IParticleSystem.h"
#include "Mix/Scene/IParticleGenerator.h"
#include "Mix/Scene/IParticleProcessor.h"

class SoulParticleSystem : public Mix::Scene::IParticleSystem
{
private:
	static const Mix::Vector3 GENE_VEC_ONE;

	static const Float32 GENE_MIN_LIFE;
	static const Float32 GENE_MAX_LIFE;
	static const Float32 GENE_DIFF_LIFE;

	static const Float32 GENE_MIN_LOCAL_RANGE;
	static const Float32 GENE_MAX_LOCAL_RANGE;
	static const Float32 GENE_DIFF_LOCAL_RANGE;

	static const Float32 GENE_MIN_HALF_SIZE;
	static const Float32 GENE_MAX_HALF_SIZE;
	static const Float32 GENE_DIFF_HALF_SIZE;

	static const Mix::Vector4 PROC_BASE_COLOR;

	static const Float32 PROC_LAG_INTERVAL;
	static const Float32 PROC_LAG_HS_COIFFE;
	static const Float32 PROC_LAG_ALPHA_COIFFE;

#ifdef _DEBUG
	static const Float32 DEBUG_TRACK_INTERVAL;
#endif //_DEBUG

	enum PRIVATE_VALUE
	{
		MAX_CTRL_POS = 4,
		MAX_LAG = 4,
	};

	struct DATA
	{
		Float32 life;
		Float32 invLifeMax;

		Mix::Vector3 ctrlPos[SoulParticleSystem::MAX_CTRL_POS];

		Float32 halfSize;

		Float32 lagTime;
		Int32 lagHead;
		Int32 lagTail;
		Int32 lagNum;
		Mix::Vector3 lags[SoulParticleSystem::MAX_LAG];
	};

	class InternalGenerator : public Mix::Scene::IParticleGenerator
	{
	public:
		static InternalGenerator* CreateInstance( void );

	public:
		InternalGenerator( void );
		virtual ~InternalGenerator( void );

		virtual void Internal_GetData( UInt32 dataSize, void* pData );

#ifdef _DEBUG
		virtual void Debug_Draw( const Mix::Matrix4x4& worldMat, Mix::Graphics::Utility::IPerspectiveRenderer* pPersRenderer );
#endif //_DEBUG
	};

	class InternalProcessor : public Mix::Scene::IParticleProcessor
	{
	private:
		std::vector<SoulParticleSystem::DATA> m_Dats;
		std::vector<Mix::Scene::IParticleProcessor::FACE> m_Faces;

	public:
		static InternalProcessor* CreateInstance( void );

	public:
		InternalProcessor( void );
		virtual ~InternalProcessor( void );

		virtual UInt32 Internal_GetCount( void ) const;

		virtual void Internal_Clear( void );
		virtual UInt32 Internal_Add( Mix::Scene::IParticleGenerator* pGenerator, UInt32 genCount );
		virtual UInt32 Internal_Add( const Mix::Matrix4x4& worldMat, Mix::Scene::IParticleGenerator* pGenerator, UInt32 genCount );

		virtual Boolean Internal_Update( Float32 dt );

		virtual Boolean Internal_Duplicate( Mix::Scene::IParticleProcessor** ppProcessor, const wchar_t* pDebugName );

		virtual UInt32 Internal_GetFaceNum( void ) const;
		virtual const Mix::Scene::IParticleProcessor::FACE* Internal_GetFaces( void ) const;

#ifdef _DEBUG
		virtual void Debug_Draw( const Mix::Matrix4x4& worldMat, Mix::Graphics::Utility::IPerspectiveRenderer* pPersRenderer );
#endif //_DEBUG

	private:
		static const wchar_t* MSG_NOT_IMPL;
	};

public:
	static SoulParticleSystem* CreateInstance( void );

private:
	Mix::Scene::IParticleSystem::CONFIG m_Config;
	SoulParticleSystem::InternalGenerator* m_pGenerator;

public:
	SoulParticleSystem( void );
	virtual ~SoulParticleSystem( void );

	virtual const Mix::Scene::IParticleSystem::CONFIG& GetConfig( void ) const;

	virtual void Internal_GetGenerator( Mix::Scene::IParticleGenerator** ppGenerator );
	virtual Boolean Internal_CreateProcessor( Mix::Scene::IParticleProcessor** ppProcessor );

	virtual Float32 Internal_GetGenerateInterval( void ) const;
	virtual UInt32 Internal_GetGenerateCount( void ) const;
};
