//===========================================================================//
// File:	Application.hpp
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
// 08/25/97  ECH  Infrastructure changes.                                    //
//---------------------------------------------------------------------------//
// Copyright (C) 1995-97, Virtual World Entertainment, Inc.                  //
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include "AdeptHeaders.hpp"

#include "RendererManager.hpp"
#include "Controls.hpp"
#include "Mission.hpp"
#include "EntityManager.hpp"
#include "ApplicationTask.hpp"
#include "EventStatistics.hpp"
#include "Map.hpp"
#include "Connection.hpp"
#include "Application.hpp"
#include "Tool.hpp"
#include "Entity.hpp"
#include "mover.hpp"
#include "Player.hpp"
#include <Compost\TerrainTextureLogistic.hpp>
#include "CollisionGrid.hpp"
#include "NameTable.hpp"
#include "AudioRenderer.hpp"
#include "CameraComponent.hpp"
#include "NetStatCollector.hpp"
#include "GameSpy\GameSpy.h"

#include "ResourceImagePool.hpp"
#include <MLR\MLRTexturePool.hpp>
#include <MLR\MLRTexture.hpp>

#include <dplay.h> // jcem for mission replay
#include <gameos\mreplay.h> // jcem for mission replay

extern DWORD gCurrentHeapStackLevel;


int Application::TraceLogSize = 0;

bool Application::BuildOK = true;
bool Application::RunOK = true;
bool Application::TestClasses = false;

#ifdef LAB_ONLY
bool Application::ReportNotResourced = false;
#endif


#define QUICK_SAVE_KEY KEY_GRAVE
#define QUICK_LOAD_KEY KEY_BACK
#define PAUSE_KEY KEY_ESCAPE


//
// Profile data variables
//
DECLARE_TIMER(static, PreCollisionPhase);
DECLARE_TIMER(static, Collision);
DECLARE_TIMER(static, PostCollisionPhase);
DECLARE_TIMER(static, ControlsManager);
DECLARE_TIMER(static, BackgroundTasks);
DECLARE_TIMER(static, Sync);
DECLARE_TIMER(static, UpdateEntities);
DECLARE_TIMER(static, UpdateRendererOrigin);
DECLARE_TIMER(static, LoadImages);

DWORD	tBGTasks;



NetMissionParameters::AdeptNetMissionParameters::AdeptNetMissionParameters():
	Plug(DefaultData)
{
	ResetParameters();
}

void NetMissionParameters::AdeptNetMissionParameters::ResetParameters(void)
{
	m_runDedicated = 0;
	m_closedGame = 0;
	m_playerLimit = 16;

	m_visibility = 0;

}


void NetMissionParameters::AdeptNetMissionParameters::SaveParameters(DynamicMemoryStream *stream)
{
	stream->WriteBits(&m_runDedicated, 1);
	stream->WriteBits(&m_closedGame, 1);
	stream->WriteBits(&m_playerLimit, 8);			// 256
	stream->WriteBits(&m_visibility,3);//5
}

void NetMissionParameters::AdeptNetMissionParameters::LoadParameters(MemoryStream *stream)
{
	stream->ReadBits(&m_runDedicated, 1);
	stream->ReadBits(&m_closedGame, 1);
	stream->ReadBits(&m_playerLimit, 8);// 256
	stream->ReadBits(&m_visibility,3);//5

	if (m_runDedicated)
		gos_EnableSetting( gos_Set_LoseFocusBehavior, 3);
	else
		gos_EnableSetting( gos_Set_LoseFocusBehavior, 0);
}


void NetMissionParameters::AdeptNetMissionParameters::SaveParameters(NotationFile *notefile)
{
	Page *page = notefile->SetPage("server");
	page->SetEntry("dedicated", m_runDedicated);
	page->SetEntry("playerlimit", m_playerLimit);
	page->SetEntry("visibility", m_visibility);
}


void NetMissionParameters::AdeptNetMissionParameters::SaveServerParameters(NotationFile *notefile)
{
	Page *page = notefile->SetPage("server");
	page->SetEntry("dedicated", m_runDedicated);
	page->SetEntry("playerlimit", m_playerLimit);
}

void NetMissionParameters::AdeptNetMissionParameters::LoadParameters(NotationFile *notefile)
{
	Page *page = notefile->FindPage("server");

	if (page)
	{
        m_runDedicated = 0; // jcem - no dedicated!!! page->GetEntry("dedicated", &m_runDedicated);
		page->GetEntry("playerlimit", &m_playerLimit);
		page->GetEntry("visibility", &m_visibility);

		if (m_runDedicated)
			gos_EnableSetting( gos_Set_LoseFocusBehavior, 3);
		else
			gos_EnableSetting( gos_Set_LoseFocusBehavior, 0);
	}
}

void NetMissionParameters::AdeptNetMissionParameters::LoadOverideParameters(NotationFile *notefile)
{
	Page *page = notefile->FindPage("server");

	if (page)
	{
		page->GetEntry("visibility", &m_visibility);
	}
}


#ifdef LAB_ONLY
namespace MWGameInfo
{
	Point3D g_LastCameraPos = Point3D::Identity;
	Point3D g_LastLocalPlayerPos = Point3D::Identity;

	int g_currentApplicationPhase = NoPhase;
	int g_currentApplicationState = NoState;

	char *g_applicationPhases[PhaseCount] = 
	{
		"NoPhase",
		"PreCollisionPhase",
		"CollisionPhase",
		"SyncPhase",
		"PostCollisionPhase",
		"NetworkPhase",
		"UpdateRendererPhase",
		"RenderPhase",
		"GameOSPhase"
	};


	char *g_applicationStates[StateCount] = 
	{
		"NoState",
		"WaitingForGameState",
		"LoadingGameState",
		"PreRenderState",
		"RunningGameState",
		"StoppingGameState",
		"RecycleGameState"
	};


	char g_LastFileOpenRequest[MAX_GAME_INFO_STR_LEN*2] = "";

	int g_lastPacketAddress[Packet_History_Count];
	int g_lastPacketType[Packet_History_Count];
	int g_lastPacketSize[Packet_History_Count];
	double g_lastPacketTime[Packet_History_Count];
	bool g_lastPacketInbound[Packet_History_Count];
	int nextPacketHistoryIndex = 0;
}
#endif

	double Adept::g_lastPacketFromPlayer[Maximum_Connection_Numbers];
	double Adept::g_lastPacketToPlayer[Maximum_Connection_Numbers];



//#############################################################################
//#########################    ApplicationEngine    ############################
//#############################################################################

ApplicationStateEngine::ClassData*
	ApplicationStateEngine::DefaultData = NULL;

const StateEngine::StateEntry
	ApplicationStateEngine::StateEntries[]=
{
	STATE_ENTRY(ApplicationStateEngine, Initializing),
	STATE_ENTRY(ApplicationStateEngine, WaitingForGame),
	STATE_ENTRY(ApplicationStateEngine, LoadingGame),
	STATE_ENTRY(ApplicationStateEngine, PreRender),
	STATE_ENTRY(ApplicationStateEngine, RunningGame),
	STATE_ENTRY(ApplicationStateEngine, StoppingGame),
	STATE_ENTRY(ApplicationStateEngine, RecycleGame)
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ApplicationStateEngine::InitializeClass()
{
	Check_Object(StateEngine::DefaultData);
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			ApplicationStateEngineClassID,
			"Adept::ApplicationStateEngine",
			StateEngine::DefaultData,
			ELEMENTS(StateEntries),
			StateEntries,
			NULL, NULL
		);
	Check_Object(DefaultData);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ApplicationStateEngine::TerminateClass()
{
	Check_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ApplicationStateEngine::ApplicationStateEngine(
	ClassData *class_data,
	int state_number,
	Application *the_application
):
	StateEngine(class_data, state_number)
{
	Check_Pointer(this);
	Check_Pointer(the_application);
	owningApplication = the_application;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ApplicationStateEngine::~ApplicationStateEngine()
{
	Check_Object(this);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
	ApplicationStateEngine::RequestState(
		int new_state,
		void* data
	)
{
	Check_Object(this);
	Check_Object(owningApplication);

	//
	//-------------------------
	// Ignore repeated settings
	//-------------------------
	//
	if (currentState == new_state)
	{
		return currentState;
	}

	//
	//----------------------------------------------
	// If we are stopping, ignore any other requests
	//----------------------------------------------
	//
	if (currentState == RecycleGameState && new_state == StoppingGameState)
	{
		owningApplication->QueStopGame(true);
	}


	if (
		(currentState == StoppingGameState || currentState == RecycleGameState ) && 
		new_state != WaitingForGameState
	)
	{
		return currentState;
	}

	//
	//--------------------------------------------------------------------------
	// Make sure to weed out state errors that could only happen from bad coding
	//--------------------------------------------------------------------------
	//
	switch (new_state)
	{
	case InitializingState:
		STOP(("Invalid InitializingState request!"));
		break;

	case WaitingForGameState:
		if (
			currentState != InitializingState && 
			currentState != StoppingGameState && 
			currentState != RecycleGameState
		)
		{
			STOP(("Invalid WaitingForGameState request!"));
		}
		break;

	case LoadingGameState:
		if (currentState != WaitingForGameState)
		{
			STOP(("Invalid LoadingGameState request!"));
		}
		break; 
	}

	//
	//-------------------------------------------------------------------
	// Change the state, and call the appropriate handlers in application
	//-------------------------------------------------------------------
	//
	switch (StateEngine::RequestState(new_state, data))
	{
	case LoadingGameState:
		owningApplication->EnterLoadingGameState(data);
		break;
	case RunningGameState:
		owningApplication->EnterRunningGameState(data);
		break;
	case PreRenderState:
		owningApplication->EnterPreRenderState(data);
		break;

	case StoppingGameState:
		owningApplication->EnterStoppingGameState(data);
		break;

	case RecycleGameState:
		owningApplication->EnterRecyclingGameState(data);
		break;
	}


	#if defined(LAB_ONLY)
		switch(currentState)
		{
		case WaitingForGameState:
			MWGameInfo::g_currentApplicationState = MWGameInfo::WaitingForGameState;
			break;
		case LoadingGameState:
			MWGameInfo::g_currentApplicationState = MWGameInfo::LoadingGameState;
			break;
		case PreRenderState:
			MWGameInfo::g_currentApplicationState = MWGameInfo::PreRenderState;
			break;
		case RunningGameState:
			MWGameInfo::g_currentApplicationState = MWGameInfo::RunningGameState;
			break;
		case StoppingGameState:
			MWGameInfo::g_currentApplicationState = MWGameInfo::StoppingGameState;
			break;
		case RecycleGameState:
			MWGameInfo::g_currentApplicationState = MWGameInfo::RecycleGameState;
			break;
		}
	#endif


	return currentState;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	ApplicationStateEngine::TestInstance()
{
	Verify(IsDerivedFrom(DefaultData));
}

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

//#############################################################################
// Message Support
//
const Receiver::MessageEntry
	Application::MessageEntries[]=
{
	MESSAGE_ENTRY(Application, LoadQuickGame),
	MESSAGE_ENTRY(Application, SaveQuickGame),
	MESSAGE_ENTRY(Application, PauseGame)
};

//#############################################################################
// Virtual Data support
//
Application::ClassData*
	Application::DefaultData = NULL;
int
	Application::s_ScreenWidth = 800;
int
	Application::s_ScreenHeight = 600;
bool
	Application::s_DiskFirst = false;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Application::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			ApplicationClassID,
			"Adept::Application",
			InBox::DefaultData,
			ELEMENTS(MessageEntries),
			MessageEntries
		);
	Check_Object(DefaultData);

//
// Init Statistics
//
	Initialize_Timer(BackgroundTasks, "Background Tasks");
	Initialize_Timer(ControlsManager, "Controls Manager");
	Initialize_Timer(PreCollisionPhase, "PreCollisionPhase");
	Initialize_Timer(Collision, "Collision");
	Initialize_Timer(Sync, "Sync");
	Initialize_Timer(PostCollisionPhase, "PostCollisionPhase");
	Initialize_Timer(UpdateEntities, "Update Entities");
	Initialize_Timer(UpdateRendererOrigin, "Update Renderer Origin");
	Initialize_Timer(LoadImages, "Load Images");
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Application::TerminateClass()
{
	Check_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Application::Application(ClassData *class_data):
	InBox(class_data, Network::ApplicationBoxID)
{
	Check_Pointer(this);

	//
	//----------------------------------
	// Setup some stuff for Initialize()
	//----------------------------------
	//
	backgroundTasks = NULL;
	preCollisionPhase = false;
	gamePause = false;

	// default to on
	serverFlag = true;
	networkingFlag = false;
	

	preRenderDropLocation = LinearMatrix4D::Identity;

	//
	//------------------
	// Set up game state
	//------------------
	//
	applicationState = 
		new ApplicationStateEngine(
			ApplicationStateEngine::DefaultData,
			ApplicationStateEngine::InitializingState,
			this
		);
	Check_Object(applicationState);
	applicationMode = NormalGameMode;


	currentGameNumber = 0;
	
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Application::~Application()
{
	//
	// Verify that these managers have been deleted
	//
	Verify(Map::GetInstance() == NULL);
	Verify(Network::GetInstance() == NULL);
	Verify(ControlsManager::Instance == NULL);
	Verify(ResourceManager::Instance == NULL);
	Verify(EventQueue::Instance == NULL);




	Check_Object(applicationState);
	delete applicationState;
}



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Application::TestInstance()
{
	Verify(IsDerivedFrom(DefaultData));
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Application::Initialize()
{
	Check_Object(this);

	applicationState->RequestState(ApplicationStateEngine::InitializingState);
	Verify(applicationState->GetState() == ApplicationStateEngine::InitializingState);

	//
	//-----------------------
	// Create the event queue
	//-----------------------
	//
	gos_PushCurrentHeap(g_Heap);
	Verify(!EventQueue::Instance);
	EventQueue::Instance =
		GeneralEventQueue::Make(
			EventPrioritiesCount,
			"Adept Event Count",
			"Adept Event Delay"
		);
	Check_Object(EventQueue::Instance);

	//
	//-------------------
	// Make base managers
	//-------------------
	//
	Verify(!ResourceManager::Instance);
	ResourceManager::Instance = new ResourceManager;
	Check_Object(ResourceManager::Instance);

	if (EntityManager::GetInstance() == NULL)
	{
		Verify(!EntityManager::GetInstance());
		GlobalPointers::AddGlobalPointer(new EntityManager, EntityManagerGlobalPointerIndex);
		Check_Object(EntityManager::GetInstance());
	}
	else
	{
		Check_Object(EntityManager::GetInstance());
	}

	Verify(!RendererManager::Instance);
	RendererManager::Instance = new RendererManager;
	Check_Object(RendererManager::Instance);

	backgroundTasks = new BackgroundTasks;
	Check_Object(backgroundTasks);

	Verify(!ControlsManager::Instance);
	ControlsManager::Instance = new ControlsManager();
	Check_Object(ControlsManager::Instance);

	//
	//-----------------------------
	// Set up our keyboard handlers
	//-----------------------------
	//
/*
	ControlsManager::Instance->CreateMapping(
		NULL,
		0,
		this,
		SaveQuickGameMessageID,
		this,
		-1,
		ControlsManager::VirtualButtonGroupID,
		QUICK_SAVE_KEY
	);
	ControlsManager::Instance->CreateMapping(
		NULL,
		0,
		this,
		LoadQuickGameMessageID,
		this,
		-1,
		ControlsManager::VirtualButtonGroupID,
		QUICK_LOAD_KEY
	);
*/
#if 0
	ControlsManager::Instance->CreateMapping(
		NULL,
		0,
		this,
		PauseGameMessageID,
		this,
		-1,
		ControlsManager::VirtualButtonGroupID,
		PAUSE_KEY
	);
#endif

	//
	//------------------------------------
	// Add background tasks, 
	// let the application execute frames,
	// and wait for the game
	//------------------------------------
	//
	LoadBackgroundTasks();

	//
	//------------------------------
	// Now we are waiting for a game
	//------------------------------
	//
	applicationState->RequestState(ApplicationStateEngine::WaitingForGameState);
	gos_PopCurrentHeap();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Application::LoadBackgroundTasks()
{
	Check_Object(this);

	ApplicationTask *application_task;

	gos_PushCurrentHeap(g_Heap);

	Application *app = Application::GetInstance();

	application_task = new ProcessEventTask;
	Check_Object(application_task);
	Check_Object(app->backgroundTasks);
	app->backgroundTasks->AddTask(application_task);

	application_task = new FryDeathRowTask;
	Check_Object(application_task);
	Check_Object(app->backgroundTasks);
	app->backgroundTasks->AddTask(application_task);

	application_task = new RoutePacketsTask;
	Check_Object(application_task);
	Check_Object(app->backgroundTasks);
	app->backgroundTasks->AddTask(application_task);


	application_task = new RouteLocalPacketsTask;
	Check_Object(application_task);
	Check_Object(app->backgroundTasks);
	app->backgroundTasks->AddTask(application_task);


	gos_PopCurrentHeap();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Application::DoGameLogic()
{
	gos_PushCurrentHeap(g_Heap);
	#if defined(_ARMOR)
		DWORD level = gCurrentHeapStackLevel;
	#endif
	LOG_BLOCK("Game Logic");

	Application *app = Application::GetInstance();

	Check_Object(app);

	#if defined(LAB_ONLY)
		MWGameInfo::g_currentApplicationPhase = MWGameInfo::PreCollisionPhase;
	#endif

	//
	//-------------------------
	// GameSpy maintenance
	//-------------------------
	//
	//GameSpy::ProcessGameSpy();



	//
	//-------------------------
	// Run our background tasks
	//-------------------------
	//
	int loop_count = 1;

	if (app->applicationState->GetState() == ApplicationStateEngine::PreRenderState)
	{
		loop_count = 10;
	}

	while (loop_count)
	{
		LOG_BLOCK("Game Logic::Background Tasks");
		Start_Timer(BackgroundTasks);
		app->backgroundTasks->Execute();
		Stop_Timer(BackgroundTasks);
		Verify(gCurrentHeapStackLevel == level);

		--loop_count;
	}
    if (g_pfn_BACKGROUNDTACK)
        (*g_pfn_BACKGROUNDTACK)();
	
	Check_Object(app);

	if (app->QuedForStop())
		app->StopGame();



	//
	//------------------------------------------------
	// Verify this is the Application::Instance to run
	//------------------------------------------------
	//
	if (!
		(app->GetApplicationState() == ApplicationStateEngine::RunningGameState ||
		app->GetApplicationState() == ApplicationStateEngine::PreRenderState)
	)
	{
		Verify(gCurrentHeapStackLevel == level);
		gos_PopCurrentHeap();

		#if defined(LAB_ONLY)
			MWGameInfo::g_currentApplicationPhase = MWGameInfo::GameOSPhase;
		#endif

		return;
	}




	//
	//-----------------
	// Controls Manager
	//-----------------
	//
	if ((app->GetApplicationState() == ApplicationStateEngine::RunningGameState) &&
	   (!app->m_localMissionParameters->m_runDedicated))
	{
		LOG_BLOCK("Game Logic::Controls Manager");
		Start_Timer(ControlsManager);
		Check_Object(ControlsManager::Instance);
		ControlsManager::Instance->Execute();
		Stop_Timer(ControlsManager);
		Verify(gCurrentHeapStackLevel == level);
	}

	//
	//--------------------------------------------------------------------
	// Execute pre-collision game execution, collision, and post-collision
	// game execution
	//--------------------------------------------------------------------
	//
	if (!app->IsPaused())
	{
		Time target = gos_GetElapsedTime();
		{
			LOG_BLOCK("Game Logic::Pre-Collision");
			Start_Timer(PreCollisionPhase);
			app->preCollisionPhase = true;
			Check_Object(EntityManager::GetInstance());
			EntityManager::GetInstance()->PreCollisionExecute(target);
			Stop_Timer(PreCollisionPhase);
			app->preCollisionPhase = false;
			Verify(gCurrentHeapStackLevel == level);

			GlobalPointers::MoveGlobals();
		}

		if (app->applicationState->GetState() != ApplicationStateEngine::PreRenderState)
		{
		#if defined(LAB_ONLY)
			MWGameInfo::g_currentApplicationPhase = MWGameInfo::CollisionPhase;
		#endif

			LOG_BLOCK("Game Logic::Collision");
			Start_Timer(Collision);
			Check_Object(Map::GetInstance());
			CollisionGrid::Instance->FindCollisions(target);
			Stop_Timer(Collision);
			Verify(gCurrentHeapStackLevel == level);
		}

		#if defined(LAB_ONLY)
			MWGameInfo::g_currentApplicationPhase = MWGameInfo::SyncPhase;
		#endif

		{
			LOG_BLOCK("Game Logic::Sync");
			Start_Timer(Sync);
			Check_Object(Mission::GetInstance());
			Mission::GetInstance()->SyncMatrices(true);
			Stop_Timer(Sync);
			Verify(gCurrentHeapStackLevel == level);
		}

		#if defined(LAB_ONLY)
			MWGameInfo::g_currentApplicationPhase = MWGameInfo::PostCollisionPhase;
		#endif

		{
			LOG_BLOCK("Game Logic::Post-Collision");
			Start_Timer(PostCollisionPhase);
			EntityManager::GetInstance()->PostCollisionExecute(target);
			Stop_Timer(PostCollisionPhase);
			Verify(gCurrentHeapStackLevel == level);
		}

		#if defined(LAB_ONLY)
			MWGameInfo::g_currentApplicationPhase = MWGameInfo::NetworkPhase;
		#endif

		// peer to peer messaging...
		{

			LOG_BLOCK("Game Logic::Network::Update Entities");
			Start_Timer(UpdateEntities);
			EntityManager::GetInstance()->StartUpdates();

			EntityManager::GetInstance()->UpdateEntities();
			Verify(gCurrentHeapStackLevel == level);

			// client server updates
			if (app->GetApplicationState() == ApplicationStateEngine::RunningGameState)
			{
				EntityManager::GetInstance()->ServeLocalEntities(target);
				Verify(gCurrentHeapStackLevel == level);
			}


			EntityManager::GetInstance()->EndUpdates();
			Stop_Timer(UpdateEntities);
		}

		// let the network move the time on the 
		// bandwidth stats
		{
			#ifdef GROUP_ADEPT_NETWORK
				LOG_BLOCK("Game Logic::Network::Advance Stats");
			#endif

			Network::GetInstance()->AdvanceStats();
		}
	}

	//
	//-------------------------------------------------------
	// First, update the map to where the player currently is
	//-------------------------------------------------------
	//

	#if defined(LAB_ONLY)
		MWGameInfo::g_currentApplicationPhase = MWGameInfo::UpdateRendererPhase;
	#endif

	if (!app->m_localMissionParameters->m_runDedicated)
	{

		Check_Object(Player::GetInstance());
		Check_Object(Map::GetInstance());
		{
			LOG_BLOCK("Game Logic::Update Renderers");
			Start_Timer(UpdateRendererOrigin);
			Point3D location;
			
			if (app->GetApplicationState() == ApplicationStateEngine::RunningGameState)
			{
				location = Player::GetInstance()->GetEyePoint();
				//SPEW(("jerryeds", "RUN- %f,%f,%f", location.x, location.y, location.z));
			}
			else
			{
				location = app->preRenderDropLocation;
				//SPEW(("jerryeds", "PRE- %f,%f,%f", location.x, location.y, location.z));
			}


			#if defined(LAB_ONLY)
				MWGameInfo::g_LastCameraPos = location;
				MWGameInfo::g_LastLocalPlayerPos = Player::GetInstance()->vehicle->GetLocalToWorld();
			#endif


			Map::GetInstance()->UpdateRenderOrigin(location);
			Stop_Timer(UpdateRendererOrigin);
			Verify(gCurrentHeapStackLevel == level);
		}

		loop_count = 1;
		Time _time_current = gos_GetElapsedTime(); // jcem

		if (app->applicationState->GetState() == ApplicationStateEngine::PreRenderState)
		{
			loop_count = 10;
			_time_current += 0.015f;
		} else {
			_time_current += 0.005f;
		}

		while (loop_count)
		{
			LOG_BLOCK("Game Logic::Load Image");
			Check_Object(MidLevelRenderer::MLRTexturePool::Instance);
			Start_Timer(LoadImages);
			gos_PushCurrentHeap(MidLevelRenderer::TexturePoolHeap);
			
			ChainIteratorOf<MidLevelRenderer::MLRTexture *> textures(&MidLevelRenderer::MLRTexturePool::Instance->unloadedTextures);
			MidLevelRenderer::MLRTexture *texture;
			if ((texture = textures.GetCurrent()) != NULL)
			{
				Check_Object(texture);
				MidLevelRenderer::MLRTexturePool::Instance->LoadImageGOS(texture);
				textures.Remove();
			}
			gos_PopCurrentHeap();
			Stop_Timer(LoadImages);
			--loop_count;
			if (_time_current <= gos_GetElapsedTime())
				break;
		}
		Verify(gCurrentHeapStackLevel == level);

	}

	if (!app->IsPaused())
	{
		if(Compost::TerrainTextureLogistic::Instance && !app->m_localMissionParameters->m_runDedicated)
		{
			if (app->GetApplicationState() == ApplicationStateEngine::RunningGameState)
			{
				LOG_BLOCK("Game Logic::Texture Compositing");
				gos_PushCurrentHeap(Compost::Heap);
				Start_Timer(Compost::Composting_Time);
				CameraComponent *camera = VideoRenderer::Instance->GetSceneCamera();
				Check_Object(camera);
				ElementRenderer::Element* element = camera->GetElement();
				Compost::TerrainTextureLogistic::Instance->SetNewPosition(&element->GetLocalToWorld(), NULL, NULL);
				gos_PopCurrentHeap();
				Stop_Timer(Compost::Composting_Time);
			}
			else
			{
				LOG_BLOCK("Game Logic::Texture Compositing");
				gos_PushCurrentHeap(Compost::Heap);
				Start_Timer(Compost::Composting_Time);
				
				Compost::TerrainTextureLogistic::Instance->SetNewPosition(&app->preRenderDropLocation, NULL, NULL);
				gos_PopCurrentHeap();
				Stop_Timer(Compost::Composting_Time);
			}
		}
	}



	#if defined(LAB_ONLY)
		MWGameInfo::g_currentApplicationPhase = MWGameInfo::GameOSPhase;
	#endif

	gos_PopCurrentHeap();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Application::UpdateDisplay()
{
	LOG_BLOCK("Update Renderers");
	Application *app = Application::GetInstance();

	if (app->m_localMissionParameters->m_runDedicated)
		return;

	gos_PushCurrentHeap(g_LibraryHeap);
	#if defined(_ARMOR)
		DWORD level = gCurrentHeapStackLevel;
	#endif

	Check_Object(app);
	if (
		app->GetApplicationState() !=
			ApplicationStateEngine::RunningGameState
	)
	{
		Verify(gCurrentHeapStackLevel == level);
		gos_PopCurrentHeap();
		return;
	}

	#if defined(LAB_ONLY)
		MWGameInfo::g_currentApplicationPhase = MWGameInfo::RenderPhase;
	#endif

	//
	//-----------------
	// Renderer Manager
	//-----------------
	//
	Check_Object(RendererManager::Instance);
	Time target_time = gos_GetElapsedTime();
	RendererManager::Instance->Execute(target_time);

	Verify(gCurrentHeapStackLevel == level);
	gos_PopCurrentHeap();

	#if defined(LAB_ONLY)
		MWGameInfo::g_currentApplicationPhase = MWGameInfo::GameOSPhase;
	#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Application::StopGame()
{
	Check_Object(this);
	
	applicationState->RequestState(ApplicationStateEngine::StoppingGameState);
	quedStop = false;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Application::Terminate()
{
	Check_Object(this);

	StopNetworking();

	//
	//--------------------
	// Delete the managers
	//--------------------
	//
	Check_Object(ControlsManager::Instance);
	delete ControlsManager::Instance;
	ControlsManager::Instance = NULL;

	Check_Object(backgroundTasks);
	delete backgroundTasks;
	backgroundTasks = NULL;

	Check_Object(EntityManager::GetInstance());
	delete EntityManager::GetInstance();
	GlobalPointers::ClearPointer(EntityManagerGlobalPointerIndex);



	Check_Object(RendererManager::Instance);
	delete RendererManager::Instance;
	RendererManager::Instance = NULL;
	VideoRenderer::Instance = NULL;

	Check_Object(ResourceManager::Instance);
	delete ResourceManager::Instance;
	ResourceManager::Instance = NULL;

	Check_Object(EventQueue::Instance);
	delete[] EventQueue::Instance;
	EventQueue::Instance = NULL;
}


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Application::LoadQuickGameMessageHandler(const ReceiverDataMessageOf<int> *message)
{
	Check_Object(this);
	Check_Object(message);

	STOP(("not implemented"));

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Application::SaveQuickGameMessageHandler(const ReceiverDataMessageOf<int> *message)
{
	Check_Object(this);
	Check_Object(message);

	STOP(("Not implemented"));

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Application::PauseGameMessageHandler(const ReceiverDataMessageOf<int> *message)
{
	Check_Object(this);
	Check_Object(message);

	//
	//------------------------------------------
	// Ignore anything where the key is going up
	//------------------------------------------
	//
	if (message->dataContents < 0)
		return;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Application::EnterLoadingGameState(void *)
{
	Check_Object(this);
}



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void
	Application::EnterRunningGameState(void *)
{
	Check_Object(this);

	//
	//-----------------------
	// Set the resolution
	//-----------------------
	//
	gos_SetScreenMode(s_ScreenWidth, s_ScreenHeight,Environment.bitDepth,Environment.FullScreenDevice);

	//
	//-----------------------
	// Activate the renderers
	//-----------------------
	//
	//Check_Object(RendererManager::Instance);
	//RendererManager::Instance->ActivateRenderers();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void
	Application::EnterPreRenderState(void *)
{
	Check_Object(this);

	//
	//----------------------------------------------------
	// Start game started clock and activate the renderers
	//----------------------------------------------------
	//
	Check_Object(Mission::GetInstance());
	Mission::GetInstance()->SyncMatrices(true);

	//
	//---------------------------------------------
	// Build the tile bound entity damage list
	//---------------------------------------------
	//
	Check_Object(EntityManager::GetInstance());
	EntityManager::GetInstance()->BuildTileBoundDamageList();

	//
	//------------------------
	// Load the initial images
	//------------------------
	//
	Check_Object(MidLevelRenderer::MLRTexturePool::Instance);
	MidLevelRenderer::MLRTexturePool::Instance->LoadImages();

	#if defined(LAB_ONLY)
		CallDebuggerMenuItem("Debugger\\Options\\Reset minimum and maximum values", gosMenu_Activated);
	#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Application::EnterStoppingGameState(void*)
{
	Check_Object(this);
	Check_Object(applicationState);
	Verify(applicationState->GetState() == ApplicationStateEngine::StoppingGameState);

	preRenderDropLocation = LinearMatrix4D::Identity;

	//
	//---------------------
	// Dump analysis sample
	//---------------------
	//
	Check_Object(EntityManager::GetInstance());
	EntityManager::GetInstance()->Reset();

	StopNetworking();

	//
	//-------------------------
	// Deactivate the renderers
	//-------------------------
	//
	Check_Object(RendererManager::Instance);
	if(Compost::TerrainTextureLogistic::Instance != NULL)
	{
		gos_PushCurrentHeap(Compost::Heap);
		Check_Object(Compost::TerrainTextureLogistic::Instance);
		Compost::TerrainTextureLogistic::Instance->Restart();
		gos_PopCurrentHeap();
	}
	RendererManager::Instance->DeactivateRenderers();
	gos_RecreateTextureHeaps();

	//
	//-------------------------------------------------
	// Make sure that it is really legal to do this now
	//-------------------------------------------------
	//
	applicationState->RequestState(ApplicationStateEngine::WaitingForGameState);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Application::EnterRecyclingGameState(void*)
{
	Check_Object(this);
	Check_Object(applicationState);
	Verify(applicationState->GetState() == ApplicationStateEngine::RecycleGameState);

	preRenderDropLocation = LinearMatrix4D::Identity;

	//
	//---------------------
	// Dump analysis sample
	//---------------------
	//
	Check_Object(EntityManager::GetInstance());
	EntityManager::GetInstance()->Reset();

	RecycleNetworking();

	//
	//-------------------------
	// Deactivate the renderers
	//-------------------------
	//
	Check_Object(RendererManager::Instance);
	if(Compost::TerrainTextureLogistic::Instance != NULL)
	{
		gos_PushCurrentHeap(Compost::Heap);
		Check_Object(Compost::TerrainTextureLogistic::Instance);
		Compost::TerrainTextureLogistic::Instance->Restart();
		gos_PopCurrentHeap();
	}
	RendererManager::Instance->DeactivateRenderers();



	//
	//-------------------------------------------------
	// Make sure that it is really legal to do this now
	//-------------------------------------------------
	//
	applicationState->RequestState(ApplicationStateEngine::WaitingForGameState);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void
	Application::RecycleNetworking()
{
	//reset network stuff.	
	

	if (Network::GetInstance())
	{
		Network::GetInstance()->Recycle();
	}

}



//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//

void
	Application::StopNetworking()
{
	//reset network stuff.	
	serverFlag = true;
	networkingFlag = false;
	
	
	//
	//---------------------------------
	// Have the host manager close game
	//---------------------------------
	//
	if (Network::GetInstance())
	{
		
		Check_Object(Network::GetInstance());
		delete Network::GetInstance();
		GlobalPointers::ClearPointer(NetworkGlobalPointerIndex);
	}

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void __stdcall
	Application::GetFileForGOS(
		const char* file_name,
		BYTE** memory,
		DWORD* size
	)
{
#ifdef LAB_ONLY
	strcpy(MWGameInfo::g_LastFileOpenRequest, "GetFileForGOS:    ");
	strcpy(MWGameInfo::g_LastFileOpenRequest + 15, file_name);
#endif

	//
	//--------------------------------------------------------------------
	// If we are told to look on disk first, see if we can find it on disk
	//--------------------------------------------------------------------
	//
	FileStream::IsRedirected = false;
#if 1 // jcem - defined(LAB_ONLY)
	if (s_DiskFirst)
	{
		if (gos_DoesFileExist(file_name))
		{
			gos_PushCurrentHeap(FileStream::s_Heap);
			gos_GetFile(file_name, memory, size);
			gos_PopCurrentHeap();
		}

		//
		//-----------------------------------
		// Otherwise, it must be in resources
		//-----------------------------------
		//
		else
		{
			if (ResourceManager::Instance)
			{
				Resource resource(file_name);
				if (!resource.DoesResourceExist())
					STOP(("Couldn't find %s!", file_name));
				resource.LoadData();
				*memory = static_cast<BYTE*>(resource.GetPointer());
				*size = resource.GetSize();
				resource.AbandonData();
			}
			else
				STOP(("Couldn't find %s!", file_name));
		}
	}

	//
	//---------------------------------------------------------------------
	// First look in the resources for the file.  If we find it, load it up
	// and then forget about it - GOS will delete the memory for us
	//---------------------------------------------------------------------
	//
	else
	{
#endif
		if (ResourceManager::Instance)
		{
			Resource resource(file_name);
			if (resource.DoesResourceExist())
			{
				resource.LoadData();
				*memory = static_cast<BYTE*>(resource.GetPointer());
				*size = resource.GetSize();
				resource.AbandonData();
			}

			//
			//---------------------------
			// Otherwise, let GOS open it
			//---------------------------
			//
			else
			{
				gos_PushCurrentHeap(FileStream::s_Heap);
#ifdef LAB_ONLY
				{
					if (Application::ReportNotResourced && stricmp(file_name, "options.ini") && 
							stricmp(".nfo", file_name + strlen(file_name) - 4) && stricmp(".mw4", file_name + strlen(file_name) - 4) &&
							strnicmp(file_name,"Content\\Textures\\customdecals",29) &&
							stricmp(file_name, "servercycle.txt") )
					{
						PAUSE(("Warning (hit continue): File '%s' not resourcified and is being loaded straight from disk.", file_name));
					}
				}
#endif
				gos_GetFile(file_name, memory, size);
				gos_PopCurrentHeap();
			}
		}
		else
		{
			gos_PushCurrentHeap(FileStream::s_Heap);
			gos_GetFile(file_name, memory, size);
#ifdef LAB_ONLY
			{
				if (Application::ReportNotResourced && stricmp(file_name, "options.ini") && 
							stricmp(".nfo", file_name + strlen(file_name) - 4) && stricmp(".mw4", file_name + strlen(file_name) - 4) &&
							strnicmp(file_name,"Content\\Textures\\customdecals",29) &&
							stricmp(file_name, "servercycle.txt") )
				{
					PAUSE(("Warning (hit continue): File '%s' not resourcified and is being loaded straight from disk.", file_name));
				}
			}
#endif
			gos_PopCurrentHeap();
		}
#if 1 // jcem - defined(LAB_ONLY)
	}
#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool __stdcall
	Application::FindFileForGOS(const char* file_name)
{
	FileStream::IsRedirected = false;
#ifdef LAB_ONLY
	strcpy(MWGameInfo::g_LastFileOpenRequest, "FindFileForGOS:    ");
	strcpy(MWGameInfo::g_LastFileOpenRequest + 16, file_name);
#endif

	//
	//---------------------------------
	// Look on disk first if we have to
	//---------------------------------
	//
#if defined(LAB_ONLY)
	if (s_DiskFirst)
	{
		if (!gos_DoesFileExist(file_name))
		{
			if (ResourceManager::Instance)
			{
				Resource resource(file_name);
				return resource.DoesResourceExist();
			}
			else
				return false;
		}
	}

	//
	//---------------------------------
	// Look in the resource files first
	//---------------------------------
	//
	else
	{
#endif
		if (ResourceManager::Instance)
		{
			Resource resource(file_name);
			if (!resource.DoesResourceExist())
				return gos_DoesFileExist(file_name);
		}
		else
			return gos_DoesFileExist(file_name);
#if defined(LAB_ONLY)
	}
#endif

	//
	//-------------------------------------------------
	// The first test was successful so return it found
	//-------------------------------------------------
	//
	return true;
}
