/*********************************************************************//**
*		Definice struktury, ktera je databazi entit.
*	Tento objekt dokaze nacist identifikace entit z retezce a pote
*	vytvori objekty dle jejich jmena a rozradi je do prislusnych
*	seznamu dle vlastnosti.
*
*	author: Michal Jirous
*	date: 13.02.2009
*	file: level_entities.cpp
**********************************************************************/

#include "level_entities.h"
#include "game.h"
#include <sstream>
#include "parsing.h"
#include "level_decals.h"

parameters_t parametersMap;

#include "game_musicplayer.h"

/** @param parameters Parametry, ze kterych bude entita vytvorena. */
void EntityInfo::createEntityFromParameters( parameters_t &parameters )
{
	//Pro specialni entity se provadi obsluha zde
	string className = getParameterValue( parameters, "classname" );
	if( className == "worldspawn" )	//global map parameters
	{
		game.setLevelParameters( parameters );
	}
	else if( className == "info_player_start" )
	{
		game.m_pPlayer->setParameters( parameters );
	}
	else if( className == "light" )
	{
		CBaseEntity *newObject = getNewEntity( className );
		if( newObject )
		{
			newObject->setParameters( parameters );
			insertEntity( newObject );
		}

		int style = ((Light*)newObject)->getStyleNum();
		
		if( style > 0 && style < 255 && lightStyles[style] == NULL )	//not switchable
			lightStyles[style] = ((Light*)newObject);
	}
	else if(  className == "env_texture" )
	{
		decalSystem.addStaticTexture( parameters );
	}

	//pro ostatni entity se obsluha presouva na ne samotne
	else if( !className.empty() )
	{
		CBaseEntity *newObject = getNewEntity( className );
 		if( newObject )
		{
			newObject->setParameters( parameters );
			insertEntity( newObject );
		}
	
	}
}


/** @entityString Retezec, ktery obsahuje definice entit. */
void EntityInfo::loadEntities( const char* entityString )
{
	/*====================================
	*	1. Vlozeni hrace
	*====================================*/
	game.m_pPlayer = new CPlayer();	//inicializace hrace
	insertEntity( game.m_pPlayer );

	/*====================================
	*	2. Reset svetel
	*====================================*/
	memset( lightStyles, 0, sizeof(lightStyles) );

	/*====================================
	*	3. Analyza textu
	*====================================*/
	istringstream in;
	in.str( entityString );
	char c;
	while( (c = in.get() ) != -1 )
	{
		if( isspace(c) )
			continue;
		
		if( c == '{' )	//entity start
		{
			parametersMap.clear();
			bool name = true;
			string parameterName, parameterValue;
			
			while( (c = in.get() ) != -1 )
			{
				if( c == '}' )	//end of entity
				{
					createEntityFromParameters( parametersMap );
					break;
				}
			
				if( isspace( c ) )
					continue;

				if( c == '\"' )	//zacatek parametru
				{
					if( name )	//jde o jmeno
					{
						parameterName = parsing::readField( in, '\"' );
						name = false;
					}
					else	//jde o hodnotu
					{
						parameterValue = parsing::readField( in, '\"' );
						parametersMap.insert( make_pair( parameterName, parameterValue ) );
						name = true;
					}
				}
			}
		}
	}
}



#include "soundslib.h"

void EntityInfo::compileAll()
{
	soundLibrary.pushAttrib();
	soundLibrary.setDefaultRelativity( AL_FALSE );
	soundLibrary.setDefaultForceSourceUse( AL_FALSE );


	
	for( list<CBaseEntity*>::iterator iter = m_Entities.begin(); iter != m_Entities.end(); ++iter )
		(*iter)->compile();

	soundLibrary.popAttrib();
}

void EntityInfo::decompileAll()
{
	for( list<CBaseEntity*>::iterator iter = m_Entities.begin(); iter != m_Entities.end(); ++iter )
		(*iter)->decompile();
}

void EntityInfo::unloadEntities()
{
	for( list<CBaseEntity*>::iterator iter = m_Entities.begin(); iter != m_Entities.end(); ++iter )
		delete *iter;

	game.m_pPlayer = NULL;
	m_Entities.clear();
	m_CollisionEntities.clear();
	m_RunnableEntities.clear();
	m_Render.clear();
	m_ForceColliding.clear();
	m_PhysicModels.clear();
	//m_BlendingCare.clear();

	m_NamesDatabase.clear();


	
}

/** @param entity Entita, ktera ma byt ulozena do seznamu v databazi. */
void EntityInfo::insertEntity( CBaseEntity* entity )
{
	if( !entity )
		return;

	int parameters = entity->getProperties();

	m_Entities.push_back( entity );

	if( parameters & ENT_PARM_COLLIDING || parameters & ENT_PARM_SHOOTABLE || parameters & ENT_PARM_INTERACTIVE)
		m_CollisionEntities.push_back( entity );
	if( parameters & ENT_PARM_RUNNABLE )
		m_RunnableEntities.push_back( entity );
	if( parameters & ENT_PARM_DYNAMIC_MODEL_USAGE )
		m_PhysicModels.push_back( reinterpret_cast<CBasePhysics*>(entity) );
	if( parameters & ENT_PARM_FORCE_MOVING )
		m_ForceColliding.push_back( reinterpret_cast<CBaseMoveable*>(entity) );

	if( parameters & ENT_PARM_RENDER )
		m_Render.push_back( entity );

	/* Pokud ma entita i jmeno, tak ji musime vlozit do databaze se jmeny entit. */
	if( !entity->m_sName.empty() )
	{
		entityList_t *entityList = getEntitiesByName( entity->m_sName );
		if( !entityList )
		{
			std::pair<entityNamesMap_t::iterator,bool> iter = m_NamesDatabase.insert( make_pair(entity->m_sName, entityList_t()) );
			if( iter.second )
			{
				iter.first->second.push_back( entity );			
			}
		}
		else
			entityList->push_back( entity );

	}
}

/** @param name Hledane jmeno entit.
*	@return Seznam entit s timto jmenem.
*/
entityList_t *EntityInfo::getEntitiesByName( std::string name )
{
	entityNamesMap_t::iterator iter = m_NamesDatabase.find( name );
	if( iter != m_NamesDatabase.end() )
		return &iter->second;
	return NULL;

}
