#include "registry.h"
#include "renderer.h"
#include "controls.h"
#include "update.h"
#include "mission.h"
#include "player.h"
#include "director.h"
#include "appmgr.h"
#include "audrend.h"
#include "vidrend.h"
#include "gaugrend.h"
#include "hostmgr.h"
#include "interest.h"
#include "nttmgr.h"
#include "apptask.h"
#include "console.h"
#include "appmsg.h"
#include "evtstat.h"

#if defined(TRACE_FOREGROUND_PROCESSING)
	BitTrace Foreground_Processing("Foreground Processing");
#endif

#if defined(TRACE_UPDATE_MANAGER)
	BitTrace Update_Manager("Update Manager");
#endif

#if defined(TRACE_RENDERER_MANAGER)
	BitTrace Renderer_Manager("Renderer Manager");
#endif

Application *application = NULL;
int Exit_Code = 0;
Logical Application::suppressGauges = False;

//#############################################################################
//###########################    Application    ###############################
//#############################################################################

//#############################################################################
// Message Support
//
const Receiver::HandlerEntry
	Application::MessageHandlerEntries[]=
{
	MESSAGE_ENTRY(Application, StateQuery),
	MESSAGE_ENTRY(Application, CheckLoad),
	MESSAGE_ENTRY(Application, RunMission),
	MESSAGE_ENTRY(Application, StopMission),
	MESSAGE_ENTRY(Application, ResumeMission),
	MESSAGE_ENTRY(Application, SuspendMission),
	MESSAGE_ENTRY(Application, KeyCommand),
	MESSAGE_ENTRY(Application, LoadMission),
	MESSAGE_ENTRY(Application, AbortMission)
};

Application::MessageHandlerSet& Application::GetMessageHandlers()
{
	static Application::MessageHandlerSet messageHandlers(ELEMENTS(Application::MessageHandlerEntries), Application::MessageHandlerEntries, NetworkClient::GetMessageHandlers());
	return messageHandlers;
}

//#############################################################################
// Virtual Data support
//
Derivation* Application::GetClassDerivations()
{
	static Derivation classDerivations(NetworkClient::GetClassDerivations(), "Application");
	return &classDerivations;
}

Application::SharedData
	Application::DefaultData(
		Application::GetClassDerivations(),
		Application::GetMessageHandlers()
	);

//
//#############################################################################
// TestInstance
//#############################################################################
//
Logical
	Application::TestInstance() const
{
	if (!IsDerivedFrom(*GetClassDerivations()))
	{
		return False;
	}
	Check(&applicationState);
	if (eventQueue)
	{
		Check(eventQueue);
	}
	if (networkManager)
	{
		Check(networkManager);
	}
	if (entityManager)
	{
		Check(entityManager);
	}
	if (registry)
	{
		Check(registry);
	}
	if	(hostManager)
	{
		Check(hostManager);
	}
	if (interestManager)
	{
		Check(interestManager);
	}
	if (updateManager)
	{
		Check(updateManager);
	}
	if (rendererManager)
	{
		Check(rendererManager);
	}
	if (controlsManager)
	{
		Check(controlsManager);
	}
	if (intercomManager)
	{
		Check(intercomManager);
	}
	if (resourceFile)
	{
		Check(resourceFile);
	}
	if (viewpointEntity)
	{
		Check(viewpointEntity);
	}
	if (currentMission)
	{
		Check(currentMission);
	}
	if (backgroundTasks)
	{
		Check(backgroundTasks);
	}
	if (audioRenderer)
	{
		Check(audioRenderer);
	}
	if (videoRenderer)
	{
		Check(videoRenderer);
	}
	if (gaugeRenderer)
	{
		Check(gaugeRenderer);
	}
	return True;
}

//
//#############################################################################
// Application
//#############################################################################
//
Application::Application(
	ResourceFile *resource_file,
	ApplicationID application_ID,
	ClassID class_ID,
	SharedData &shared_data
):
	NetworkClient(class_ID, shared_data, ApplicationClientID),
	applicationState(ApplicationStateCount)
{
	Check(&shared_data);
	Check(resource_file);

	applicationID = application_ID;

	//
	// Create the event queue
	//
	eventQueue = GeneralEventQueue::Make(
		EVENT_PRIORITIES_COUNT,
		"MUNGA Event Count"
	);
	Check(eventQueue);

	//
	// Remember the resource file
	//
	resourceFile = resource_file;
	missionPlayer = NULL;

	//
	// NULL managers not yet created
	//
	networkManager = NULL;
	registry = NULL;
	controlsManager = NULL;
	intercomManager = NULL;
	backgroundTasks = NULL;
	interestManager = NULL;
	audioRenderer = NULL;
	videoRenderer = NULL;
	gaugeRenderer = NULL;

	//
	// NULL pointers to other objects not yet created
	//
	viewpointEntity = NULL;
	currentMission = NULL;

	//
	// Create base level managers
	//
	entityManager = new EntityManager;
	Register_Object(entityManager);
	hostManager = new HostManager;
	Register_Object(hostManager);
	updateManager = new UpdateManager;
	Register_Object(updateManager);
	rendererManager = new RendererManager;
	Register_Object(rendererManager);
	backgroundTasks = new BackgroundTasks;
	Register_Object(backgroundTasks);

	//
	// Set up game state
	//
	executeFrames = False;
	applicationState.SetState(InitializingState);
	currentMission = NULL;
	secondsRemainingInGame	=	0.0f;
	spoolFile = NULL;
	routePacketFinished = False;
   lastCreationMessage = Now();

	//
	// HACK - Init analysis bits
	//
	#if defined(TRACE_ON)
		trace_manager.ResetTraces();
	#endif
}

//
//#############################################################################
// GetApplicationManager
//#############################################################################
//
ApplicationManager*
	Application::GetApplicationManager()
{
	PlugIteratorOf<ApplicationManager*> manager_link(this);
	ApplicationManager *mgr;
	while ((mgr = manager_link.ReadAndNext()) != NULL)
	{
		if (mgr->GetClassID() == ApplicationManagerClassID)
		{
			return mgr;
		}
	}
	return NULL;
}

Scalar
	Application::GetApplicationLoopFrameRate()
{
	ApplicationManager *mgr = GetApplicationManager();
	Check(mgr);
	return mgr->GetFrameRate();
}

//
//#############################################################################
// Initialize
//#############################################################################
//
void
	Application::Initialize()
{
	Check(this);

	//
	//----------------------------
	// Create the interest Manager
	//----------------------------
	//
	interestManager = MakeInterestManager();
	Register_Object(interestManager);

	//
	//--------------------------------------------------------------------------
	// Create the network manager
	//--------------------------------------------------------------------------
	//
	networkManager = MakeNetworkManager();
	Register_Object(networkManager);

	//
	//--------------------------------------------------------------------------
	// Create the registry, load static object streams
	//--------------------------------------------------------------------------
	//
	registry = MakeRegistry();
	if (registry)
	{
		Register_Object(registry);
		registry->LoadStaticObjectStreamResource();
	}

	//
	//--------------------------------------------------------------------------
	// Create the mode manager
	//--------------------------------------------------------------------------
	//
	modeManager = MakeModeManager();
	Register_Object(modeManager);

	//
	//--------------------------------------------------------------------------
	// Create the controls manager
	//--------------------------------------------------------------------------
	//
	controlsManager = MakeControlsManager();
	Register_Object(controlsManager);

	//
	//--------------------------------------------------------------------------
	// Create the intercom manager
	//--------------------------------------------------------------------------
	//
	intercomManager = MakeIntercomManager();
	Register_Object(intercomManager);

	//
	//--------------------------------------------------------------------------
	// Add background tasks
	//--------------------------------------------------------------------------
	//
	LoadBackgroundTasks();
	executeFrames = True;
	applicationState.SetState(WaitingForEgg);

	//
	//--------------------------------------------------------------------------
	// Create the audio renderer
	//--------------------------------------------------------------------------
	//
	Verify(audioRenderer == NULL);
	if ((audioRenderer = MakeAudioRenderer()) != NULL)
	{
		Register_Object(audioRenderer);
		audioRenderer->Initialize();
	}

	//
	//--------------------------------------------------------------------------
	// Create the video renderer
	//--------------------------------------------------------------------------
	//
	Verify(videoRenderer == NULL);
	if ((videoRenderer = MakeVideoRenderer()) != NULL)
	{
		Register_Object(videoRenderer);
	}

	//
	//--------------------------------------------------------------------------
	// Create the gauge renderer
	//--------------------------------------------------------------------------
	//
	Verify(gaugeRenderer == NULL);

	if (Application::GetVideoRenderer() != NULL)
	{
		int *secondaryIndex = Application::GetVideoRenderer()->GetSecondaryIndex();
		int *aux1Index = Application::GetVideoRenderer()->GetAux1Index();
		int *aux2Index = Application::GetVideoRenderer()->GetAux2Index();
		if ((gaugeRenderer = MakeGaugeRenderer(secondaryIndex, aux1Index, aux2Index)) != NULL)
		{
			Register_Object(gaugeRenderer);
		}
	}
}

//
//#############################################################################
// LoadBackgroundTasks
//#############################################################################
//
void
	Application::LoadBackgroundTasks()
{
	Check(this);

	ApplicationTask *application_task;

	application_task = new RoutePacketTask;
	Register_Object(application_task);
	backgroundTasks->AddTask(application_task);

	application_task = new ProcessEventTask;
	Register_Object(application_task);
	backgroundTasks->AddTask(application_task);

	application_task = new AudioRendererTask;
	Register_Object(application_task);
	backgroundTasks->AddTask(application_task);

	application_task = new GaugeRendererTask;
	Register_Object(application_task);
	backgroundTasks->AddTask(application_task);

	application_task = new NetworkManagerTask;
	Register_Object(application_task);
	backgroundTasks->AddTask(application_task);

	application_task = new CompleteCyclesTask;
	Register_Object(application_task);
	backgroundTasks->AddTask(application_task);

	application_task = new FryDeathRowTask;
	Register_Object(application_task);
	backgroundTasks->AddTask(application_task);
}

//
//#############################################################################
// MakeInterestManager
//#############################################################################
//
InterestManager*
	Application::MakeInterestManager()
{
	return new InterestManager;
}

//
//#############################################################################
// MakeNetworkManager
//#############################################################################
//
NetworkManager*
	Application::MakeNetworkManager()
{
	return new NetworkManager(NetworkManager::DefaultData);
}

//
//#############################################################################
// MakeRegistry
//#############################################################################
//
Registry*
	Application::MakeRegistry()
{
	Fail("Application::MakeRegistry - Should never reach here");
	return NULL;
}

//
//#############################################################################
// MakeModeManager
//#############################################################################
//
ModeManager*
	Application::MakeModeManager()
{
	Fail("Application::MakeModeManager - Should never reach here");
	return NULL;
}

//
//#############################################################################
// MakeControlsManager
//#############################################################################
//
ControlsManager*
	Application::MakeControlsManager()
{
	Fail("Application::MakeControlsManager - Should never reach here");
	return NULL;
}

//
//#############################################################################
// MakeIntercomManager
//#############################################################################
//
IcomManager*
	Application::MakeIntercomManager()
{
	Fail("Application::MakeIntercomManager - Should never reach here");
	return NULL;
}

//
//#############################################################################
// ExecuteForeground
//#############################################################################
//
Logical
	Application::ExecuteForeground(
		Time start_of_frame,
		Scalar frame_duration
	)
{
	SET_FOREGROUND_PROCESSING();

	Check(this);
	Verify(application == this);

	if (!executeFrames)
	{
		CLEAR_FOREGROUND_PROCESSING();
		return executeFrames;
	}

	Time
		frame_ticks;
	frame_ticks = frame_duration;

	//
	//--------------------------------------------------------------------------
	// Controls Manager
	//
	// Poll all devices, update all control variables.
	//
	// This is executed before the update manager so that the
	// models have valid control values.  It is not necessary for
	// the controls to operate at the frame rate of this loop.  If
	// the controls manager can run run at a lower rate it can
	// throttle itself internally.
	//--------------------------------------------------------------------------
	//
	Check(controlsManager);
Time startControls = Now();
	controlsManager->Execute();
Time endControls = Now();

	if (GetApplicationState() == WaitingForEgg)
	{
		// since we're idling, let the renderers clear the screens
		videoRenderer->ExecuteIdle();
		CLEAR_FOREGROUND_PROCESSING();
		return executeFrames;
	}

	//
	//--------------------------------------------------------------------------
	// Update Manager
	//
	// Execute replicants.
	// Execute master entities if they are interesting here or
	//		elsewhere.
	//	Inform interest manager of possible interest zone change.
	// If the master entity has provided and update message then
	//		send it to replicants.
	//
	// This is executed before the interest manager so that the
	// interest manager can merge all interest zone changes before
	// broadcasting interest arena deltas and building interesting
	// entity lists.
	//
	// This is executed before the renderers so that the watchers
	// have executed on the model and are ready for use by the
	// renderers.
	//--------------------------------------------------------------------------
	//
	SET_UPDATE_MANAGER();

Time startUpdate = Now();
	Check(updateManager);
	updateManager->Execute(start_of_frame);
Time endUpdate = Now();

	CLEAR_UPDATE_MANAGER();

	//
	//--------------------------------------------------------------------------
	// Interest Manager
	//
	// Update the net interest arena.
	// Calculate which interest zones should be released and which
	// 	interest zones should be loaded
	// Send a becoming uninteresting and becoming interesting
	//		message to the entity.
	// Broadcast the interest arena change
	//
	// The renderer manager call, update interest origins will
	// update only those interest origins required by the renderers
	// executing this frame.
	//
	//	This is executed before the renderer manager so that when
	// the renderers execute they execute upon interest lists that
	// are valid as of the end of a model/update frame.
	//
	// In theory the interest manager does not have to run every
	// frame.  If throttled less, this would cause fuzz at interest
	// zone borders, which may or may not be acceptable depending
	// on the size of the interest arena.
	//--------------------------------------------------------------------------
	//
Time startInterest = Now();
	Check(rendererManager);
	rendererManager->UpdateInterestOrigins(start_of_frame);
	Check(interestManager);
	interestManager->Execute();
Time endInterest = Now();

	//
	//--------------------------------------------------------------------------
	// Renderer Manager
	//
	// Execute renderers.
	// Get interest list from interest manager.
	// Poll watchers.
	//
	// It is not necessary for all renderers to operate at the frame
	// rate of this loop.  If a renderer can run at a lower rate it
	// does so via the renderer manager which will govern if a
	// renderer executes this frame.
	//--------------------------------------------------------------------------
	//
	SET_RENDERER_MANAGER();
Time startRender = Now();
	Check(rendererManager);
	rendererManager->Execute(start_of_frame, frame_ticks, frame_ticks);
Time endRender = Now();
	CLEAR_RENDERER_MANAGER();

	//
	//--------------------------------------------------------------------------
	// Intercom Manager
	//--------------------------------------------------------------------------
	//
Time startIntercom = Now();
	Check(intercomManager);
	intercomManager->Execute();
Time endIntercom = Now();

	//
	//--------------------------------------------------------------------------
	// Execution statistics
	//--------------------------------------------------------------------------
	//
	if (GetApplicationState() == RunningMission)
	{
		secondsRemainingInGame =
			currentMission->GetGameLength() - (Now() - gameStarted);
	}
	routePacketFinished = False;

	CLEAR_FOREGROUND_PROCESSING();

	return executeFrames && !Exit_Code;
}

//
//#############################################################################
// ExecuteBackgroundTask
//#############################################################################
//
#define QUIET_TIME_OUT 3.0f
void
	Application::ExecuteBackgroundTask()
{
	Check(this);

	//
	//------------------------------------------------------------------------
	// If we are processing the map's creation messages, don't allow any other
	// processing to happen until nothing appears for the timeout period
	//------------------------------------------------------------------------
	//
	if (GetApplicationState() == CreatingMission)
	{
		Check(networkManager);

		if (networkManager->RoutePacket())
		{
			return;
		}

		if (ProcessOneEvent(DefaultEventPriority))
		{
			return;
		}

		if (ProcessOneEvent(LowEventPriority))
		{
			lastCreationMessage = Now();
		}
		else
		{
			Scalar wait = Now() - lastCreationMessage;
			if (wait > QUIET_TIME_OUT)
			{
				applicationState.SetState(LoadingMission);
				networkManager->Marker("MUNGA MARKER - Starting renderer load...\n");
				networkManager->Mode(NetworkManager::UnreliableMode);
				#if defined(LAB_ONLY)
					DEBUG_STREAM << "Starting renderer load...\n" << std::flush;
				#endif
			}
		}
		return;
	}

	//
	// If there exists a high priority event, execute it
	//
	if (ProcessOneEvent(HighEventPriority))
	{
		return;
	}

	//
	// if
	//		we are not finished routing packets this frames or
	//		we are not running the game
	// then
	//		attempt to route a network packet
	// we are finished routing packets for this frame
	//
	if (
		!routePacketFinished ||
		applicationState.GetState() != RunningMission
	)
	{
		Check(networkManager);
		if (networkManager->RoutePacket())
		{
			return;
		}
	}
	routePacketFinished = True;

	//
	// Execute lower priority tasks
	//
	Check(backgroundTasks);
	backgroundTasks->Execute();
}

//
//#############################################################################
// Stop
//#############################################################################
//
void
	Application::Stop()
{
	Check(this);

	//
	// Dump analysis sample
	//
	#if defined(USE_TIME_ANALYSIS)
		DEBUG_STREAM << "\nGame timing statistics:\n" << std::flush;
		trace_manager.SnapshotTimingAnalysis(True);
	#endif
	#if defined(USE_TRACE_LOG)
		trace_manager.SaveTraceLog("trace.log");
	#endif
	#if defined(USE_EVENT_STATISTICS)
		event_statistics_manager.Report();	
	#endif
	
	//
	// Set state variables to end game status
	//
	executeFrames = False;
	DEBUG_STREAM << std::flush << std::flush;
	applicationState.SetState(StoppingMission);
}

//
//#############################################################################
// Shutdown
//#############################################################################
//
Logical
	Application::Shutdown(int remainingApps)
{
	Check(this);

	//
	//--------------------------------------------------------------------------
	// Shutdown gauge renderer
	//--------------------------------------------------------------------------
	//
	if (gaugeRenderer != NULL)
	{
		Check(gaugeRenderer);
		gaugeRenderer->Shutdown();
		gaugeRenderer->UnlinkFromEntity();
	}
	//
	//--------------------------------------------------------------------------
	// Shutdown video renderer
	//--------------------------------------------------------------------------
	//
	if (videoRenderer != NULL)
	{
		Check(videoRenderer);
		videoRenderer->Shutdown();
		videoRenderer->UnlinkFromEntity();
	}
	//
	//--------------------------------------------------------------------------
	// Shutdown audio renderer
	//--------------------------------------------------------------------------
	//
	if (audioRenderer != NULL)
	{
		Check(audioRenderer);
		audioRenderer->Shutdown();
		audioRenderer->UnlinkFromEntity();
	}

	//
	//--------------------------------------------------------------------------
	// Delete the viewpoint entity
	//--------------------------------------------------------------------------
	//
	if (viewpointEntity != NULL)
	{
		Unregister_Object(viewpointEntity);
		delete viewpointEntity;
		viewpointEntity = NULL;
	}

	//
	//--------------------------------------------------------------------------
	// Shutdown the interest manager
	//--------------------------------------------------------------------------
	//
	Check(interestManager);
	interestManager->Shutdown();

	//
	//--------------------------------------------------------------------------
	// Shutdown the host manager
	//--------------------------------------------------------------------------
	//
	Check(hostManager);
	hostManager->Shutdown();

	//
	//--------------------------------------------------------------------------
	// Shutdown the network manager
	//--------------------------------------------------------------------------
	//
	Check(networkManager);
	networkManager->Shutdown();

	//
	//--------------------------------------------------
	// Delete the current mission if it has been created
	//--------------------------------------------------
	//
	if (currentMission)
	{
		Unregister_Object(currentMission);
		delete currentMission;
		currentMission = NULL;
	}

	//
	//---------------------------------
	// Allow the process to start again
	//---------------------------------
	//
	executeFrames = True;
	applicationState.SetState(WaitingForEgg);
#if 0
	return !Exit_Code;
#else
	return False;
#endif
}

//
//#############################################################################
// Terminate
//#############################################################################
//
void
	Application::Terminate()
{
	Check(this);

	//
	//--------------------------------------------------------------------------
	// Delete the gauge renderer
	//--------------------------------------------------------------------------
	//
	if (gaugeRenderer != NULL)
	{
		Unregister_Object(gaugeRenderer);
		delete gaugeRenderer;
		gaugeRenderer = NULL;
	}

	//
	//--------------------------------------------------------------------------
	// Delete the video renderer
	//--------------------------------------------------------------------------
	//
	if (videoRenderer != NULL)
	{
		Unregister_Object(videoRenderer);
		delete videoRenderer;
		videoRenderer = NULL;
	}

	//
	//--------------------------------------------------------------------------
	// Delete the audio renderer
	//--------------------------------------------------------------------------
	//
	if (audioRenderer != NULL)
	{
		Unregister_Object(audioRenderer);
		delete audioRenderer;
		audioRenderer = NULL;
	}

	//
	//-----------------------------------------------------------------------
	// Delete the intercom manager
	//-----------------------------------------------------------------------
	//
	if (intercomManager != NULL)
	{
		Unregister_Object(intercomManager);
		delete intercomManager;
		intercomManager = NULL;
	}

	//
	//-----------------------------------------------------------------------
	// Delete the controls manager
	//-----------------------------------------------------------------------
	//
	if (controlsManager != NULL)
	{
		Unregister_Object(controlsManager);
		delete controlsManager;
		controlsManager = NULL;
	}

	//
	//------------------------
	// Delete the mode manager
	//------------------------
	//
	if (modeManager)
	{
		Unregister_Object(modeManager);
		delete modeManager;
		modeManager = NULL;
	}

	//
	//-----------------------------------------------------------------------
	// Delete the registry
	//-----------------------------------------------------------------------
	//
	if (registry != NULL)
	{
		Unregister_Object(registry);
		delete registry;
		registry = NULL;
	}

	//
	//-----------------------------------------------------------------------
	// Delete the network manager
	//-----------------------------------------------------------------------
	//
	if (networkManager != NULL)
	{
		Unregister_Object(networkManager);
		delete networkManager;
		networkManager = NULL;
	}

	//
	//----------------------------
	// Delete the interest manager
	//----------------------------
	//
	if (interestManager != NULL)
	{
		Unregister_Object(interestManager);
		delete interestManager;
		interestManager = NULL;
	}
}

//
//#############################################################################
// ~Application
//#############################################################################
//
Application::~Application()
{
	//
	// Verify that these managers have been deleted
	//
	Verify(interestManager == NULL);
	Verify(networkManager == NULL);
	Verify(registry == NULL);
	Verify(controlsManager == NULL);
	Verify(intercomManager == NULL);
	Verify(audioRenderer == NULL);
	Verify(videoRenderer == NULL);
	Verify(gaugeRenderer == NULL);

	//
	// Verify that the mission has been deleted
	//
	Verify(currentMission == NULL);

	//
	// Verify that the viewpoint entity has been deleted
	//
	Verify(viewpointEntity == NULL);

	//
	// Destroy these managers
	//
	Unregister_Object(backgroundTasks);
	delete backgroundTasks;
	backgroundTasks = NULL;

	Unregister_Object(rendererManager);
	delete rendererManager;
	rendererManager = NULL;

	Unregister_Object(updateManager);
	delete updateManager;
	updateManager = NULL;

	Unregister_Object(hostManager);
	delete hostManager;
	hostManager = NULL;

	Unregister_Object(entityManager);
	delete entityManager;
	entityManager = NULL;

	resourceFile = NULL;

	//
	// Destroy the event queue
	// HACK - the event queue is transparently created as an array,
   // therefore must be deleted as one
	//
	Unregister_Object(eventQueue);
	delete[] eventQueue;
	eventQueue = NULL;
}

//
//#############################################################################
// StateQueryMessageHandler
//#############################################################################
//
void
	Application::StateQueryMessageHandler(
#if DEBUG_LEVEL>0
		StateQueryMessage *message
#else
		StateQueryMessage *
#endif
	)
{
	Check(this);
	Check(message);
	Verify(message->messageID == StateQueryMessageID);

	//
	//--------------------------------------------------------------------------
	// Send the console our application state
	//--------------------------------------------------------------------------
	//
	Host *console_host;

	Check(GetHostManager());
	if ((console_host = GetHostManager()->GetConsoleHost()) != NULL)
	{
		Check(console_host);

		unsigned int appState = applicationState.GetState();

		ConsoleApplicationStateResponseMessage
			response_message(
				0, // GetHostManager()->GetLocalHostID(),
				applicationState.GetState(),
            GetApplicationID()
			);

		SendMessage(
			console_host->GetHostID(),
			ConsoleClientID,
			&response_message
		);
	}
}

//
//#############################################################################
// CreateMission
//#############################################################################
//
void
	Application::CreateMission(NotationFile *egg_notation_file)
{
	Check(this);
	Check(egg_notation_file);

	//
	//--------------------------------------------------------------------------
	// Create mission from egg notation file
	//--------------------------------------------------------------------------
	//
	currentMission = MakeMission(egg_notation_file, resourceFile);
	Register_Object(currentMission);
	secondsRemainingInGame = currentMission->GetGameLength();

	//
	//----------------------------------------------------------------------
	// Now, start up the network connect process.  The network must have at
	// least established the local host before returning, so that the player
	// data load can work
	//----------------------------------------------------------------------
	//
	NetworkManager *net_mgr = GetNetworkManager();
	Check(net_mgr);
	net_mgr->StartConnecting(currentMission);
	currentMission->SetPlayerData(egg_notation_file);

	InterestManager *interest_mgr = GetInterestManager();
	Check(interest_mgr);
   interest_mgr->LoadInterestArenas(currentMission);
}

//
//#############################################################################
// MakeMission
//#############################################################################
//
Mission*
	Application::MakeMission(
		NotationFile*,
		ResourceFile*
	)
{
	Fail("Application::MakeMisson - Should never reach here");
	return NULL;
}

//
//#############################################################################
// LoadMissionMessageHandler
//#############################################################################
//
void
	Application::LoadMissionMessageHandler(Message *)
{
	Check(this);
	//
	//--------------------------------------------------------------------------
	// Load the interest manager
	//--------------------------------------------------------------------------
	//
	#ifdef USE_TIME_ANALYSIS
		trace_manager.StartTimingAnalysis();
	#endif
	Check(interestManager);
	interestManager->LoadMission(currentMission);

	//
	//--------------------------------------------------------------------------
	// Make the player
	//--------------------------------------------------------------------------
	//
	Registry* registry = GetRegistry();
	Check(registry);
	missionPlayer = registry->MakePlayer(currentMission);
	Register_Object(missionPlayer);

	//
	//--------------------------------------------------------------------------
	// Set application state to loading
	//--------------------------------------------------------------------------
	//
	applicationState.SetState(CreatingMission);
	#if defined(LAB_ONLY)
		DEBUG_STREAM << "Starting entity creation...\n" << std::flush;
	#endif
}

//
//#############################################################################
// MakeAndLinkViewpointEntity
//#############################################################################
//
Entity*
	Application::MakeAndLinkViewpointEntity(Entity::MakeMessage* message)
{
	Check(this);
	Check(message);

	//
	//--------------------------------------------------------------------------
	// Create the viewpoint entity
	//--------------------------------------------------------------------------
	//
	#if DEBUG_LEVEL>0
		HostManager *host = GetHostManager();
		Check(host);
		Verify(message->entityID.GetHostID() == host->GetLocalHostID());
	#endif

	Verify(viewpointEntity == NULL);
	viewpointEntity = MakeViewpointEntity(message);

	//
	//--------------------------------------------------------------------------
	// Post a message to check the status of the load
	//--------------------------------------------------------------------------
	//
	CheckLoadMessage check_load_message;
	Post(DefaultEventPriority, this, &check_load_message);

	//
	//--------------------------------------------------------------------------
	// Load audio renderer
	//--------------------------------------------------------------------------
	//
	if (audioRenderer != NULL)
	{
		Check(audioRenderer);
		audioRenderer->LinkToEntity(viewpointEntity);
		audioRenderer->LoadMission(GetCurrentMission());
		audioRenderer->SetRendererStatusToRunning();
	}

	//
	//--------------------------------------------------------------------------
	// Load video renderer
	//--------------------------------------------------------------------------
	//
	if (videoRenderer != NULL)
	{
		Check(videoRenderer);
		videoRenderer->LinkToEntity(viewpointEntity);
		videoRenderer->LoadMission(GetCurrentMission());
		videoRenderer->SetRendererStatusToRunning();
	}

	//
	//--------------------------------------------------------------------------
	// Load gauge renderer
	//--------------------------------------------------------------------------
	//
	if (gaugeRenderer != NULL)
	{
		Check(gaugeRenderer);
		gaugeRenderer->LinkToEntity(viewpointEntity);
		gaugeRenderer->LoadMission(GetCurrentMission());
		gaugeRenderer->SetRendererStatusToRunning();
	}

	return viewpointEntity;
}

//
//#############################################################################
// MakeViewpointEntity
//#############################################################################
//
Entity*
	Application::MakeViewpointEntity(Entity::MakeMessage*)
{
	Fail("Application::MakeViewpointEntity - Should never reach here");
	return NULL;
}

//
//#############################################################################
// MakeAudioRenderer
//#############################################################################
//
AudioRenderer*
	Application::MakeAudioRenderer()
{
	Fail("Application::MakeAudioRenderer - Should never reach here");
	return NULL;
}

//
//#############################################################################
// MakeVideoRenderer
//#############################################################################
//
VideoRenderer*
	Application::MakeVideoRenderer()
{
	Fail("Application::MakeVideoRenderer - Should never reach here");
	return NULL;
}

//
//#############################################################################
// MakeGaugeRenderer
//#############################################################################
//
GaugeRenderer*
	Application::MakeGaugeRenderer(int *secondaryIndex, int *aux1Index, int *aux2Index)
{
	Fail("Application::MakeGaugeRenderer - Should never reach here");
	return NULL;
}

//
//#############################################################################
// CheckLoadMessageHandler
//#############################################################################
//
void
	Application::CheckLoadMessageHandler(
		CheckLoadMessage *message
	)
{
	Check(this);
	Check(message);
	Verify(message->messageID == CheckLoadMessageID);

	//
	//--------------------------------------------------------------------------
	// If the application is already running then ignore this message
	//--------------------------------------------------------------------------
	//
	switch (applicationState.GetState())
	{
	case CreatingMission:
	case LoadingMission:
	case WaitingForLaunch:
		if (eventQueue->IsPriorityEmpty(MinEventPriority))
		{
			Host *console_host;

			if (applicationState.GetState() == LoadingMission)
			{
				ResourceFile *res_file = GetResourceFile();
				Check(res_file);
				res_file->ReleaseUnlockedResources();
				#if defined(LAB_ONLY)
					DEBUG_STREAM << "Waiting for translocation!\n" << std::flush;
				#endif
				#if defined(USE_TIME_ANALYSIS)
					DEBUG_STREAM << "Loading time usage:\n" << std::flush;
					trace_manager.SnapshotTimingAnalysis(True);
				#endif
			}
			applicationState.SetState(WaitingForLaunch);
			Check(GetHostManager());

			static bool hasConsolidated = false;

			if (!hasConsolidated)
			{
				 //Consolidate level geometry here
				 VideoRenderer *renderer = Application::GetVideoRenderer();
				 renderer->ConsolidateStaticObjects();
				 hasConsolidated = true;
			}

			console_host = GetHostManager()->GetConsoleHost();
			if (
				!gConsoleMarshalsLaunch &&
				(
					(console_host == NULL) ||
					(
						console_host != NULL &&
						console_host->GetConnectStatus() != Host::OnLineConnectionStatus
					)
				)
			)
			{
				//
				// In the absence of the console just post the message to
				// run. An IN-PROCESS console (hosted network race) has no
				// connection to this pod but still owns the launch - the
				// gConsoleMarshalsLaunch flag holds us at WaitingForLaunch
				// until every pod in the mesh is staged.
				//
				RunMissionMessage run_mission_message;
				Post(DefaultEventPriority, this, &run_mission_message);
				Tell("Sent ready message to ourselves\n");
			}
		}

		//
		//-----------------------------------------------------------------------
		// Post this message again until the application is running
		//-----------------------------------------------------------------------
		//
		Time post_time;

		post_time = Now();
		#if DEBUG_LEVEL<3
			post_time += 1.0f;
		#else
			post_time += 5.0;
		#endif

		Post(DefaultEventPriority, this, message, post_time);
		break;
	}
}

//
//#############################################################################
// RunMissionMessageHandler
//#############################################################################
//
void
	Application::RunMissionMessageHandler(
#if DEBUG_LEVEL>0
		RunMissionMessage *message
#else
		RunMissionMessage *
#endif
	)
{
	Check(this);
	Check(message);
	Verify(message->messageID == RunMissionMessageID);

	//
	//--------------------------------------------------------------------------
	// If the application is already running then ignore this message
	//--------------------------------------------------------------------------
	//
	switch (GetApplicationState())
	{
	case RunningMission:
		return;

	case LaunchingMission:
		//
		// Start analysis sample
		//
		#if defined(USE_TRACE_LOG)
			{
				char *log_size_str = getenv("LOGSIZE");
				if (log_size_str)
				{
					size_t log_size = atoi(log_size_str);
					if (log_size > 0)
					{
						trace_manager.CreateTraceLog(log_size,True);
					}
				}
			}
		#endif
		#ifdef USE_TIME_ANALYSIS
			trace_manager.StartTimingAnalysis();
		#endif

		Tell("Application::RunMissionMessageHandler - running mission\n");
		applicationState.SetState(RunningMission);
		gameStarted = Now();
		break;

	case WaitingForLaunch:
		{
			Tell("Application::RunMissionMessageHandler - Translocation\n");
			applicationState.SetState(LaunchingMission);
			Player *player = GetMissionPlayer();
			Check(player);
			Player::MissionStartingMessage
				launch(
					Player::MissionStartingMessageID,
					sizeof(Player::MissionStartingMessage)
				);
			player->Dispatch(&launch);
			break;
		}

	default:
		Fail("Application::RunMissionMessageHandler - Not ready to run!\n");
		break;
	}
}

//
//#############################################################################
// SuspendMissionMessageHandler
//#############################################################################
//
void
	Application::SuspendMissionMessageHandler(
#if DEBUG_LEVEL>0
		SuspendMissionMessage *message
#else
		SuspendMissionMessage *
#endif
	)
{
	Check(this);
	Check(message);
	Verify(message->messageID == SuspendMissionMessageID);

	//
	//--------------------------------------------------------------------------
	// The application should be either running or already suspended
	//--------------------------------------------------------------------------
	//
	switch (GetApplicationState())
	{
	case RunningMission:
		{
			Player::MissionEndingMessage
				player_message(
					Player::MissionEndingMessageID,
					sizeof(Player::MissionEndingMessage)
				);
			Player *player;

			Tell("Application::SuspendMissionMessageHandler - Suspending\n");
			applicationState.SetState(SuspendingMission);

			player = GetMissionPlayer();
			Check(player);
			player->Dispatch(&player_message);
		}
		break;

	case SuspendingMission:
		//
		// Already suspended
		//
		break;

	default:
		//
		// Any other state is an error
		//
		Fail("Application::SuspendMissionMessageHandler - Illegal state");
		break;
	}
}

//
//#############################################################################
// ResumeMissionMessageHandler
//#############################################################################
//
void
	Application::ResumeMissionMessageHandler(
#if DEBUG_LEVEL>0
		ResumeMissionMessage *message
#else
		ResumeMissionMessage *
#endif
	)
{
	Check(this);
	Check(message);
	Verify(message->messageID == ResumeMissionMessageID);

	//
	//--------------------------------------------------------------------------
	// The application should be in the suspended state or resuming
	//--------------------------------------------------------------------------
	//
	switch (GetApplicationState())
	{
	case SuspendingMission:
		{
			Player::MissionStartingMessage
				launch(
					Player::MissionStartingMessageID,
					sizeof(Player::MissionStartingMessage)
				);
			Player *player;

			Tell("Application::ResumeMissionMessageHandler - Resuming mission\n");
			applicationState.SetState(ResumingMission);
			player = GetMissionPlayer();
			Check(player);
			player->Dispatch(&launch);
		}
		break;

	case ResumingMission:
		Tell("Application::ResumeMissionMessageHandler - Running mission\n");
		applicationState.SetState(RunningMission);
		gameStarted = Now();
		break;

	default:
		Fail("Application::ResumeMissionMessageHandler - Illegal state\n");
   	break;
	}
}

//
//#############################################################################
// StopMissionMessageHandler
//#############################################################################
//
void
	Application::StopMissionMessageHandler(
#if DEBUG_LEVEL>0
		StopMissionMessage *message
#else
		StopMissionMessage *
#endif
	)
{
	Check(this);
	Check(message);
	Verify(message->messageID == StopMissionMessageID);

	//
	//--------------------------------------------------------------------------
	// If the application is already stopping then ignore the message
	//--------------------------------------------------------------------------
	//
	switch (GetApplicationState())
	{
	case StoppingMission:
		return;

	case EndingMission:
	case AbortingMission:
		Stop();
		break;

	default:
		{
			applicationState.SetState(EndingMission);
			Player *player = GetMissionPlayer();
			if (player)
			{
				networkManager->Mode(NetworkManager::ReliableMode);
				Check(player);
				Player::MissionEndingMessage
					launch(
						Player::MissionEndingMessageID,
						sizeof(Player::MissionEndingMessage)
					);
				player->Dispatch(&launch);
			}
			else
			{
				Stop();
			}
			break;
		}
	}
}

//
//#############################################################################
// StopMissionMessageHandler
//#############################################################################
//
void
	Application::AbortMissionMessageHandler(
#if DEBUG_LEVEL>0
		AbortMissionMessage *message
#else
		AbortMissionMessage *
#endif
	)
{
	Check(this);
	Check(message);
	Verify(message->messageID == AbortMissionMessageID);

	//
	//--------------------------------------------------------------------------
	// If the application is already stopping then ignore the message
	//--------------------------------------------------------------------------
	//
	switch (GetApplicationState())
	{
	case StoppingMission:
		return;

	case EndingMission:
	case AbortingMission:
		Stop();
		break;

	default:
		{
			applicationState.SetState(AbortingMission);
			Player *player = GetMissionPlayer();
			if (player)
			{
				Check(player);
				Player::MissionEndingMessage
					launch(
						Player::MissionEndingMessageID,
						sizeof(Player::MissionEndingMessage)
					);
				player->Dispatch(&launch);
			}
			else
			{
				Stop();
			}
			break;
		}
	}
}

//
//#############################################################################
// KeyCommandMessageHandler
//#############################################################################
//
void
	Application::KeyCommandMessageHandler(
		ReceiverDataMessageOf<ControlsKey> *message
	)
{
	Check(this);
	Check(message);
	switch (message->dataContents)
	{
	case '&':
		if (GetApplicationState() != StoppingMission)
		{
			Exit_Code = 1;
			Stop();
			DEBUG_STREAM << "Mission stopped by keystroke!\n" << std::flush;
			if (GetApplicationState() == WaitingForEgg)
			{
				applicationState.SetState(EndingMission);
			}
		}
		break;

	#if defined(USE_TRACE_LOG)
		case ' ':
			trace_manager.MarkTraceLog();
			break;
		case '/':
			trace_manager.ResumeTraceLogging();
			break;
		case '\\':
			trace_manager.SuspendTraceLogging();
			break;
	#endif
	}
}

//~~~~~~~~~~~~~~~~~~~~~~ Application__CheckLoadMessage ~~~~~~~~~~~~~~~~~~~~~~~~

Application__CheckLoadMessage::Application__CheckLoadMessage():
	NetworkClient::Message(
		Application::CheckLoadMessageID,
		sizeof(Application__CheckLoadMessage)
	)
{
}

#ifdef TEST_CLASS
#	include "app.tcp"
#endif
