
///////////////////////////////////////////////////////////////////////////////
//
// File   : Asura_ProcessChunkTimingList.cpp
// Author : Andy Tate
// Date   : 25-Jul-2006
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

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

#include "Core/Asura.h"

// This file's header...
#include "ChunkSystem/Asura_ProcessChunkTimingList.h"

// Asura independent header-files...
#include "Core/Asura_Maths.h"
#include "Debugging/Asura_Logfile.h"

// Stdlib independent.
#ifndef ASURA_NO_DEBUG_OUTPUT
#include <stdlib.h>
#endif


////////////////////////////////////////////////////////////////////////////////
// Structure declarations...
////////////////////////////////////////////////////////////////////////////////

struct OutputData
{
	union
	{
		ASURA_CHUNKID	m_ID;
		char			m_TextID[4];
	};
	float	m_fTimeTaken;
};


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

Asura_TickCount					Asura_ProcessChunkTimingList::s_xStartTickCount;
Asura_TemplateHashTree<float>	Asura_ProcessChunkTimingList::s_xDurationTree;

#ifndef ASURA_NO_DEBUG_OUTPUT
static OutputData*				g_pxOutputData	= NULL;
#endif

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

#ifndef ASURA_NO_DEBUG_OUTPUT
////////////////////////////////////////////////////////////////////////////////
// Function     : OutputDataFill_TraverseCallback
// Author       : Andy Tate
// Date         : 25-Jul-2006
////////////////////////////////////////////////////////////////////////////////

static void OutputDataFill_TraverseCallback (Asura_Hash_ID uHash,
											 float* pfTime)
{
	// Store this data...
	g_pxOutputData->m_ID			= static_cast<ASURA_CHUNKID>(uHash);
	g_pxOutputData->m_fTimeTaken	= *pfTime;

	// Increment the pointer...
	g_pxOutputData++;
}

/// End of function 'OutputDataFill_TraverseCallback'. ///
#endif // #ifndef ASURA_NO_DEBUG_OUTPUT

#ifndef ASURA_NO_DEBUG_OUTPUT
////////////////////////////////////////////////////////////////////////////////
// Function     : OutputDataSortByLongestTime_QSortCallback
// Author       : Andy Tate
// Date         : 25-Jul-2006
////////////////////////////////////////////////////////////////////////////////

static int OutputDataSortByLongestTime_QSortCallback (const void* p1,
													  const void* p2)
{
	const OutputData*	pxOutputData1	= static_cast<const OutputData*>(p1);
	const OutputData*	pxOutputData2	= static_cast<const OutputData*>(p2);
	const float			fTime1			= pxOutputData1->m_fTimeTaken;
	const float			fTime2			= pxOutputData2->m_fTimeTaken;

	// Compare...
	if(fTime1 < fTime2)
	{
		return(1);
	}
	else if (fTime1 > fTime2)
	{
		return(-1);
	}
	else
	{
		return(0);
	}
}

/// End of function 'OutputDataSortByLongestTime_QSortCallback'. ///
#endif // #ifndef ASURA_NO_DEBUG_OUTPUT



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

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ProcessChunkTimingList::BeginTiming
// Author       : Andy Tate
// Date         : 25-Jul-2006
////////////////////////////////////////////////////////////////////////////////

void Asura_ProcessChunkTimingList::BeginTiming (void)
{
	// Store the current ticks...
	s_xStartTickCount	= Asura_Timers::GetCurTicks();
}

/// End of function 'Asura_ProcessChunkTimingList::BeginTiming'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ProcessChunkTimingList::EndTiming
// Author       : Andy Tate
// Date         : 25-Jul-2006
////////////////////////////////////////////////////////////////////////////////

void Asura_ProcessChunkTimingList::EndTiming (const ASURA_CHUNKID eChunkID)
{
	const Asura_TickCount	xTicksTaken	= Asura_Timers::GetElapsedTicks(s_xStartTickCount);
	const float				fTimeTaken	= Asura_Timers::TicksToSeconds(xTicksTaken);
	float*					pfTime		= s_xDurationTree.GetDataByHash(eChunkID);

	// Is this ID in our hash-tree?
	if(pfTime == NULL)
	{
		// No - better add it then...
		pfTime	= s_xDurationTree.AddNode(eChunkID);
		*pfTime	= fTimeTaken;
	}
	else if(*pfTime < fTimeTaken)
	{
		*pfTime	= fTimeTaken;
	}
}

/// End of function 'Asura_ProcessChunkTimingList::EndTiming'. ///



////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_ProcessChunkTimingList::OutputToDebugger
// Author       : Andy Tate
// Date         : 25-Jul-2006
////////////////////////////////////////////////////////////////////////////////

void Asura_ProcessChunkTimingList::OutputToDebugger (const char* szFilename)
{
#ifndef ASURA_NO_DEBUG_OUTPUT
	const u_int	uNumEntries		= s_xDurationTree.GetNumberOfNodes();
	OutputData*	pxOutputData	= new OutputData [uNumEntries];

	// Fill-in the output data...
	g_pxOutputData	= pxOutputData;

	s_xDurationTree.Traverse(OutputDataFill_TraverseCallback);
	qsort(pxOutputData, uNumEntries, sizeof(OutputData), OutputDataSortByLongestTime_QSortCallback);

	// Output the text...
	Asura_OutputToDebugger_Retail(("--------------------------------------------------------------------------------\n"));
	Asura_OutputToDebugger_Retail(("Chunk timings for \"%s\":\n", szFilename));
	Asura_OutputToDebugger_Retail(("--------------------------------------------------------------------------------\n"));
	for(u_int u = 0; u < uNumEntries; u++)
	{
		OutputData&	xOutputData	= pxOutputData[u];

		Asura_OutputToDebugger_Retail(("Chunk %c%c%c%c - Longest time = %f\n", xOutputData.m_TextID[0], xOutputData.m_TextID[1], xOutputData.m_TextID[2], xOutputData.m_TextID[3], Asura_Maths::FtoD(xOutputData.m_fTimeTaken)));
	}
	Asura_OutputToDebugger_Retail(("--------------------------------------------------------------------------------\n"));

	// Tidy-up...
	delete[](pxOutputData);
	g_pxOutputData	= NULL;
#endif // #ifndef(ASURA_NO_DEBUG_OUTPUT)
}

/// End of function 'Asura_ProcessChunkTimingList::OutputToDebugger'. ///


/// End of file. ///
