
///////////////////////////////////////////////////////////////////////////////
//
// File   : Asura_Streaming_JobQueue.cpp
// Author : Andy Tate
// Date   : 4-May-2006
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

// RJT NOTE: Required for GCC builds as the file list generation doesn't account for VC project exclusion from build
#ifdef ASURA_USE_STREAMING

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////

#include "Core/Asura.h"

// This file's header...
#include "Streaming/Jobs/Asura_Streaming_JobQueue.h"

// Asura independent header-files...
#include "Core/Asura_Multithread.h"
#include "Core/Asura_Timers.h"
#include "Streaming/Jobs/Asura_Streaming_Job.h"

// Asura platform header-files...

// Game independent header-files...

// Game platform header-files...

// Tools header-files...


////////////////////////////////////////////////////////////////////////////////
// Constant declarations...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Static variable declarations...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Private functions...
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Streaming_JobQueue::UpdateJob
// Author       : Andy Tate
// Date         : 4-May-2006
//
// Description  : 
//
// Parameters   : A pointer to the current job to update and a reference to a
//				  pointer to the last job we updated.
//
// Return value : "true" if still the job has finished, "false" if not.
////////////////////////////////////////////////////////////////////////////////

bool Asura_Streaming_JobQueue::UpdateJob (float& fTimeAllowed,
										  Asura_Streaming_Job* pxCurrentJob,
										  Asura_Streaming_Job*& pxLastJob)
{
	// Do we have a new job to update?
	if(pxLastJob != pxCurrentJob)
	{
		// Do we have a current job?
		if(pxLastJob != NULL)
		{
			pxLastJob->EndUpdate();
		}

		// Begin our new update...
		pxLastJob	= pxCurrentJob;
		pxCurrentJob->BeginUpdate();
	}

	// Update this job...
	if(pxCurrentJob->Update(fTimeAllowed))
	{
		// Job's finished - remove it from the queue...
		pxCurrentJob->EndUpdate();
		pxLastJob	= NULL;
		return(true);
	}
	else
	{
		return(false);
	}
}

/// End of function 'Asura_Streaming_JobQueue::UpdateJob'. ///


////////////////////////////////////////////////////////////////////////////////
// Protected functions...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Public functions...
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Streaming_JobQueue::~Asura_Streaming_JobQueue
// Author       : Andy Tate
// Date         : 4-May-2006
////////////////////////////////////////////////////////////////////////////////

Asura_Streaming_JobQueue::~Asura_Streaming_JobQueue ()
{
	ListElement*	pxCurrentElt	= m_xQueue.Front();

	// Loop until we're done...
	while(pxCurrentElt != NULL)
	{
		Asura_Streaming_Job*	pxCurrentJob	= pxCurrentElt->Data();
		ListElement*			pxNextElt		= pxCurrentElt->Next();

		// Remove the job from the queue...
		delete(pxCurrentJob);
		m_xQueue.Remove(pxCurrentElt);

		// Step onto the next list-element...
		pxCurrentElt	= pxNextElt;
	}
}

/// End of function 'Asura_Streaming_JobQueue::~Asura_Streaming_JobQueue'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Streaming_JobQueue::AddJobToStart
// Author       : Andy Tate
// Date         : 4-May-2006
////////////////////////////////////////////////////////////////////////////////

bool Asura_Streaming_JobQueue::AddJobToStart (Asura_Streaming_Job* pxJob)
{
	ListElement*	pxEltAdded	= m_xQueue.Push_Front(pxJob);

	// Did we add this job?
	return(pxEltAdded != NULL);
}

/// End of function 'Asura_Streaming_JobQueue::AddJobToStart'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Streaming_JobQueue::AddJobToEnd
// Author       : Andy Tate
// Date         : 4-May-2006
////////////////////////////////////////////////////////////////////////////////

bool Asura_Streaming_JobQueue::AddJobToEnd (Asura_Streaming_Job* pxJob)
{
	ListElement*	pxEltAdded	= m_xQueue.Push_Back(pxJob);

	// Did we add this job?
	return(pxEltAdded != NULL);
}

/// End of function 'Asura_Streaming_JobQueue::AddJobToEnd'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Streaming_JobQueue::RemoveJob
// Author       : Andy Tate
// Date         : 4-May-2006
////////////////////////////////////////////////////////////////////////////////

bool Asura_Streaming_JobQueue::RemoveJob (Asura_Streaming_Job* pxJob)
{
	ListElement*	pxEltToRemove	= m_xQueue.Find(pxJob);

	// Did we find this job?
	if(pxEltToRemove == NULL)
	{
		return(false);
	}
	else
	{
		delete(pxJob);
		m_xQueue.Remove(pxEltToRemove);
		return(true);
	}
}

/// End of function 'Asura_Streaming_JobQueue::RemoveJob'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Streaming_JobQueue::Update
// Author       : Andy Tate
// Date         : 4-May-2006
//
// Description  : Handles the update of the streaming job.
//
// Parameters	: The number of seconds we've got to perform the update.
//
// Return value : "true" if we've finished updating, "false" if this job should
//				  still be handled next time.
////////////////////////////////////////////////////////////////////////////////

bool Asura_Streaming_JobQueue::Update (float& fTimeAllowed)
{
	Asura_Streaming_Job*	pxJobInProgress	= NULL;
	ListElement*			pxCurrentElt	= m_xQueue.Front();
	bool					bFinished		= (pxCurrentElt == NULL);

	// Do we need to perform an update?
	while(!bFinished && (fTimeAllowed > 0.001f))
	{
		Asura_Streaming_Job*	pxCurrentJob	= pxCurrentElt->Data();
		ListElement*			pxNextElt		= pxCurrentElt->Next();
		const float 			fStartTime		= Asura_Timers::GetTimeInFrame();

		float					fTimeTaken;

		// Update the current job...
		if(UpdateJob(fTimeAllowed, pxCurrentJob, pxJobInProgress))
		{
			// Job's finished - remove it from the queue...
			delete(pxCurrentJob);
			m_xQueue.Remove(pxCurrentElt);

			// Step onto the next list-element...
			pxCurrentElt	= pxNextElt;
			bFinished		= (pxCurrentElt == NULL);
		}
		else
		{
			// Job's still in progress...
			bFinished	= false;
		}

		// Update the time...
		fTimeTaken		 = Asura_Timers::GetTimeInFrame() - fStartTime;
		fTimeAllowed	-= fTimeTaken;

		// Ensure that we don't sit in this loop permanently...
		Asura_Thread_System::YieldCurrentThread();
	}

	// Do we have a job to finish?
	if(pxJobInProgress != NULL)
	{
		pxJobInProgress->EndUpdate();
	}

	return(bFinished);
}

/// End of function 'Asura_Streaming_JobQueue::Update'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_Streaming_JobQueue::UpdateAll
// Author       : Andy Tate
// Date         : 28-Jul-2006
////////////////////////////////////////////////////////////////////////////////

void Asura_Streaming_JobQueue::UpdateAll (void)
{
	float	fTimeAllowed	= Asura_Maths::LargeFloat;

	// Keep updating until we're done...
	while(!Update(fTimeAllowed))
	{
		fTimeAllowed	= Asura_Maths::LargeFloat;
	}
}

/// End of function 'Asura_Streaming_JobQueue::UpdateAll'. ///

#endif	// ASURA_USE_STREAMING

/// End of file. ///
