#include <munga.hpp>
#pragma hdrstop

#if !defined(APPMGR_HPP)
#	include <appmgr.hpp>
#endif

ApplicationManager::ApplicationManager(Scalar frame_rate):
	Node(ApplicationManagerClassID),
	runningApplications(this)
{
	frameRate = frame_rate;
	frameDuration = 1.0f/frameRate;
	Check_Fpu();
}

ApplicationManager::~ApplicationManager()
{
}

void
	ApplicationManager::StartApplication(Application *new_app)
{
	Check(this);
	Check(new_app);

	runningApplications.Add(new_app);
	application = new_app;
	new_app->Initialize();
}

//
//#############################################################################
// RunMissions
//#############################################################################
//
void
	ApplicationManager::RunMissions()
{
	Check(this);

	SChainIteratorOf<Application*> current_application(runningApplications);

Start_Of_Frame:
	current_application.First();
	Time end_of_frame = Now();
	end_of_frame += frameDuration;
	#if defined(LAB_ONLY)
		int bad_count = 0;
	#endif

	if (frameDuration > 0.1f)
	{
		Fail("frameDuration has grown!\n");
	}

	//
	//----------------------------------
	// Run all relevant foreground loops
	//----------------------------------
	//
	while ((application = current_application.ReadAndNext()) != NULL)
	{
		Check(application);
		if (!application->ExecuteForeground(end_of_frame, frameDuration))
		{
			if (!application->Shutdown())
			{
				application->Terminate();
				Unregister_Object(application);
				delete application;
			}
		}
	}

	//
	//-----------------------------------------------------------------------
	// Run all relevant background loops until it is time for the next frame.
	// If no applications remain, exit the whole loop
	//-----------------------------------------------------------------------
	//
	current_application.First();
	application = current_application.GetCurrent();
	if (!application)
	{
		return;
	}

	//
	//------------------------------------------------------------------
	// Give each application a chance to do at least one background task
	//------------------------------------------------------------------
	//
Background_Loop:
	do {
		Check(application);
		application->ExecuteBackgroundTask();

		//
		// Move to the next application
		//
		current_application.Next();
		application = current_application.GetCurrent();
	} while (application);

	//
	//---------------------------------------------------------------------
	// If time remains before the next frame is due, do another pass on the
	// background tasks
	//---------------------------------------------------------------------
	//
	Time t2 = Now();
	if (t2 < end_of_frame)
	{
		current_application.First();
		application = current_application.GetCurrent();
		#if defined(LAB_ONLY)
			if (end_of_frame - t2 > 0.1f)
			{
				DEBUG_STREAM << t2 << ',' << end_of_frame << endl;
				if (++bad_count == 1000)
				{
					Fail("End-of-frame cannot be correctly calculated!");
				}
			}
		#endif
		goto Background_Loop;
	}
	goto Start_Of_Frame;
}

