#include "munga.h"
#pragma hdrstop

#include "update.h"
#include "app.h"
#include "hostmgr.h"
#include "interest.h"
#include "entity.h"

#if defined(TRACE_UPDATE_REPLICANTS)
	static BitTrace Update_Replicants("Update Replicants");
	#define SET_UPDATE_REPLICANTS() Update_Replicants.Set()
	#define CLEAR_UPDATE_REPLICANTS() Update_Replicants.Clear()
#else
	#define SET_UPDATE_REPLICANTS()
	#define CLEAR_UPDATE_REPLICANTS()
#endif

#if defined(TRACE_UPDATE_MASTERS)
	static BitTrace Update_Masters("Update Masters");
	#define SET_UPDATE_MASTERS() Update_Masters.Set()
	#define CLEAR_UPDATE_MASTERS() Update_Masters.Clear()
#else
	#define SET_UPDATE_MASTERS()
	#define CLEAR_UPDATE_MASTERS()
#endif

MemoryBlock *SimulationEncore::GetAllocatedMemory()
{
	static MemoryBlock allocatedMemory(sizeof(SimulationEncore), 10, 10, "Simulation Encores");
	return &allocatedMemory;
}

SimulationEncore::SimulationEncore(
	Simulation *sim,
	Simulation::Encore callback
)
{
	encoreSimulation = sim;
	encoreCallback = callback;
	runWatchers = True;
}

SimulationEncore::~SimulationEncore()
{
}

//
//#############################################################################
//#############################################################################
//
UpdateManager::UpdateManager():
	simulationEncores(NULL)
{
}

//
//#############################################################################
//#############################################################################
//
UpdateManager::~UpdateManager()
{
	ChainIteratorOf<SimulationEncore*> encores(simulationEncores);
	SimulationEncore *encore;
	while ((encore = encores.ReadAndNext()) != NULL)
	{
		Unregister_Object(encore);
		delete encore;
	}
}

//
//#############################################################################
//#############################################################################
//
Logical
	UpdateManager::TestInstance() const
{
	Node::TestInstance();
	return True;
}

//
//#############################################################################
//#############################################################################
//
void
	UpdateManager::Execute(Time target_render_time)
{
	Check(this);

	//
	//--------------------------------------------------------------------------
	// Execute the replicants and masters that are interesting and dynamic
	//--------------------------------------------------------------------------
	//
	Check(application);
	Check(application->GetHostManager());

	HostManager::DynamicReplicantEntityIterator
		replicant_entity_iterator(application->GetHostManager());
	HostManager::DynamicMasterEntityIterator
		master_entity_iterator(application->GetHostManager());

	//
	//--------------------------------------------------------------------------
	// Execute the replicants
	//--------------------------------------------------------------------------
	//
	SET_UPDATE_REPLICANTS();

	Entity
		*replicant;

	while ((replicant = replicant_entity_iterator.ReadAndNext()) != NULL)
	{
		Check(replicant);
		// BT bring-up trace (env BT_NET_TRACE): replicant scheduling visibility.
		if (getenv("BT_NET_TRACE"))
		{
			static int s_replTrace = 0;
			if (s_replTrace++ < 400 && (int)replicant->GetEntityID() >= 20)
			{
				DEBUG_STREAM << "[upd-repl] entity " << replicant->GetEntityID()
					<< " executable=" << (int)replicant->IsReplicantExecutable()
					<< "\n" << std::flush;
			}
		}
		if (replicant->IsReplicantExecutable())
		{
			replicant->Execute(target_render_time);
		}
	}

	CLEAR_UPDATE_REPLICANTS();

	//
	//--------------------------------------------------------------------------
	// Execute the master entities, if they need to be updated then send
	// update messages, and notify the interest manager of moved entities
	//--------------------------------------------------------------------------
	//
	SET_UPDATE_MASTERS();

	Entity
		*entity;
	Entity::UpdateMessage
		*update_message;

	while ((entity = master_entity_iterator.ReadAndNext()) != NULL)
	{
		Check(entity);

		//
		//-----------------------------------------------------------------------
		// If the entity is not interesting then skip it
		//-----------------------------------------------------------------------
		//
		if (!entity->IsInteresting() || !entity->IsNonReplicantExecutable())
		{
			continue;
		}

		//
		//-----------------------------------------------------------------------
		// Run the execute method
		//-----------------------------------------------------------------------
		//
		update_message = entity->Execute(target_render_time);

		//
		//-----------------------------------------------------------------------
		// Update the interest zone id
		//-----------------------------------------------------------------------
		//
		Check(application);
		Check(application->GetInterestManager());
		application->GetInterestManager()->EntityUpdateInterestZone(entity);

		//
		//-----------------------------------------------------------------------
		// If update message is not null then send the change
		//-----------------------------------------------------------------------
		//
		if (update_message != NULL)
		{
			Check(update_message);

			Check(application);
			application->GetInterestManager()->EntityUpdateReplicants(
				entity,
				update_message
			);
		}
	}

	//
	//--------------------------------------------------------------------------
	// Lastly, run through and do any requested encores
	//--------------------------------------------------------------------------
	//
	ChainIteratorOf<SimulationEncore*>
		encores(simulationEncores);
	SimulationEncore
		*encore;

	while ((encore = encores.ReadAndNext()) != NULL)
	{
		Check(encore);
		Check(encore->encoreSimulation);
		(encore->encoreSimulation->*encore->encoreCallback)();
		if (encore->runWatchers)
		{
			encore->encoreSimulation->ExecuteWatchers();
			encore->encoreSimulation->ClearWatcherDelay();
		}
		Unregister_Object(encore);
		delete encore;
	}
	CLEAR_UPDATE_MASTERS();
}

//
//#############################################################################
//#############################################################################
//
void
	UpdateManager::RequestEncore(
		Simulation *simulation,
		Simulation::Encore encore
	)
{
	//
	//----------------------------------------------------------------------
	// Make sure that we only run the watcher on a given simulation once per
	// frame
	//----------------------------------------------------------------------
	//
	ChainIteratorOf<SimulationEncore*> encores(simulationEncores);
	SimulationEncore *i;
	while ((i = encores.ReadAndNext()) != NULL)
	{
		if (i->encoreSimulation == simulation && i->runWatchers)
		{
			i->runWatchers = False;
			break;
		}
	}

	SimulationEncore *request = new SimulationEncore(simulation, encore);
   Register_Object(request);
	simulationEncores.Add(request);
}
