
#include "../hud.h"
#include "../cl_util.h"
#include "../parsemsg.h"
#include "r_studioint.h"
#include "com_model.h"
#include "fxsys.h"
#include "fxparticlesystemmanager.h"

CFXParticleSystemManager g_FXPsysManager;

// Constructor
CFXParticleSystemManager::CFXParticleSystemManager()
{
}


// Get particle system from implementation
CFXParticleSystem *CFXParticleSystemManager::getPSysFromImplementation( std::string strImplementation )
{	CFXParticleSystem *pSystem = NULL;

	// Radiate type system
	if(strImplementation == FXPEMITTER_RADIATE)
	{	pSystem = new CFXParticleSystem(new CFXParticleEmitterRadiate());
	}
	// Radiate in a ring formation (donut?)
	else if(strImplementation == FXPEMITTER_RING_RADIATE)
	{	pSystem = new CFXParticleSystem(new CFXParticleEmitterRingRadiate());
	}
	// Rise particles (rocks, etc)
	else if(strImplementation == FXPEMITTER_RISE)
	{	pSystem = new CFXParticleSystem(new CFXParticleEmitterRise());
	}
	// Scatter (hl2 style explosion)
	else if(strImplementation == FXPEMITTER_SCATTER)
	{	pSystem = new CFXParticleSystem(new CFXParticleEmitterScatter());
	}

	return pSystem;
}

// Create particle system
CFXParticleSystem *CFXParticleSystemManager::createParticleSystem( std::string strSystem, cl_entity_t *pEntity )
{	// find particle system
	CFXStorage *pElement = g_ParseMain.getParseFX()->findScriptElement(strSystem);
	if(pElement)
	{	// Get implementation for associated particle system/emitter
		CFXParticleSystem *pSystem = getPSysFromImplementation( pElement->getImplementation() );
		if(pSystem)
		{	pSystem->setSystemName(strSystem);
			pSystem->parseData(pElement);
			// If entity is specified, set and do a bone accessor lookup
			if(pEntity)
			{	pSystem->setEntity(pEntity);
				pSystem->postCreate();
			}
		}
		return pSystem;
	}
	// Error
	else
	{	std::string strError = "ERROR: Particle System \"";
		strError += strSystem + "\" cannot be loaded!\n";
		ConsolePrint(strError.c_str());
	}
	return NULL;
}

// Create managed particle system
CFXParticleSystem *CFXParticleSystemManager::createManagedParticleSystem( std::string strSystem, cl_entity_t *pEntity )
{	return addToList(createParticleSystem(strSystem, pEntity));
}

// Add to list
CFXParticleSystem *CFXParticleSystemManager::addToList( CFXParticleSystem *pSystem )
{	if(!pSystem)
	{	return NULL;
	}
	m_ParticleSystems.push_back(pSystem);
	return pSystem;
}

// Remove
std::list<CFXParticleSystem*>::iterator CFXParticleSystemManager::Remove( std::list<CFXParticleSystem*>::iterator iterRemove )
{	delete (*iterRemove);
	return m_ParticleSystems.erase( iterRemove );
}

// Remove (by system pointer)
void CFXParticleSystemManager::Remove( CFXParticleSystem *pSystem )
{	std::list<CFXParticleSystem*>::iterator iterRemove;
	ForEachIn(iterRemove,m_ParticleSystems)
	{	if((*iterRemove) == pSystem)
		{	Remove(iterRemove);
			return;
		}
	}
}

// Remove (by entity index and system name)
void CFXParticleSystemManager::Remove( int iEntityIndex, std::string strSystem, bool bDieOut )
{	std::list<CFXParticleSystem*>::iterator iterRemove;
	ForEachIn(iterRemove,m_ParticleSystems)
	{	CFXParticleSystem *pRemove = (*iterRemove);
		if(pRemove->getEntity() && (pRemove->getEntity()->index == iEntityIndex) &&
			(pRemove->getSystemName() == strSystem))
		{	if(bDieOut)
				(*iterRemove)->setDieOut(true);
			else
				Remove(iterRemove);
			return;
		}
	}
}

// Remove (remove all that are attached to this entity)
void CFXParticleSystemManager::Remove( int iEntityIndex, bool bDieOut )
{	std::list<CFXParticleSystem*>::iterator iterRemove = m_ParticleSystems.begin();
	while(iterRemove != m_ParticleSystems.end())
	{	if((*iterRemove)->getEntity() && ((*iterRemove)->getEntity()->index == iEntityIndex))
		{	if(bDieOut)
			{	(*iterRemove)->setDieOut(true);
				++iterRemove;
			}
			else
			{	iterRemove = Remove(iterRemove);
			}
		}
		else
			++iterRemove;
	}
}

// Reset
void CFXParticleSystemManager::Reset( void )
{	std::list<CFXParticleSystem*>::iterator iterSystems;
	ForEachIn(iterSystems,m_ParticleSystems)
	{	delete (*iterSystems);
	}
	m_ParticleSystems.clear();
}

// Think
void CFXParticleSystemManager::Think( void )
{	std::list<CFXParticleSystem*>::iterator iterSystems = m_ParticleSystems.begin();
	while(iterSystems != m_ParticleSystems.end())
	{	(*iterSystems)->Think();

		// Handle particle systems that die out
		if((*iterSystems)->getDieOut())
		{	if((*iterSystems)->getParticleCount() <= 0)
			{	iterSystems = Remove(iterSystems);
			}
		}
		++iterSystems;
	}
}

// Render
void CFXParticleSystemManager::Render( void )
{	std::list<CFXParticleSystem*>::iterator iterSystems;
	ForEachIn(iterSystems,m_ParticleSystems)
	{	(*iterSystems)->Render();
	}
}