//*******************************************************************
//
// File: Tools_CyclicBuffer.h                
//
// Created: 21 Mar 2006
//
// Description: This class is designed to calculate the running average of the last N values.
//				New values will pop old values.
//				It is optimised to do only a small amount of work every time the new value is added.
//
//*******************************************************************

#ifndef _TOOLS_CYCLICBUFFER_H_
#define _TOOLS_CYCLICBUFFER_H_

#if 1 || defined( ASURA_TOOLS)

// other libraries
#include "Core/Asura_Maths.h"

// internal dependencies

// forward declarations

//*******************************************************************
// Constants
//*******************************************************************


//*******************************************************************
// Class Definitions
//*******************************************************************

template< class Tvalue> class Tools_CyclicBuffer
{
	private:
		Tvalue m_tArrayTotal;
		u_int m_uValues;
		u_int m_uValueCount;
		Tvalue m_tValueAverage;
		u_int m_uArrayValueSize;
		Tvalue* m_ptValues;

	public:
		Tvalue GetPresent( void) const;
		Tvalue GetAverage( void) const;

		void GetMinMax( Tvalue &tValueMin, Tvalue &tValueMax) const;
		void ValueAdd( const Tvalue tValueNew);
		Tools_CyclicBuffer( const u_int uArrayValueSize);
		~Tools_CyclicBuffer( void);
};

//*******************************************************************
// Inline Function Definitions
//*******************************************************************

//-------------------------------------------------------------------
// Function:    Tvalue>::GetPresent
//
// Description: Get the last value added to the array
//
// Returns:     The present actual valued
//-------------------------------------------------------------------
template< class Tvalue> inline Tvalue Tools_CyclicBuffer< Tvalue>::GetPresent( void) const 
{ 
	return( this->m_ptValues[ this->m_uValues]);
}

//-------------------------------------------------------------------
// Function:    Tvalue>::GetAverage
//
// Description: Get a average of the array
//
// Returns:     Average value of the Array
//-------------------------------------------------------------------
template< class Tvalue> inline Tvalue Tools_CyclicBuffer< Tvalue>::GetAverage( void) const 
{ 
	return( this->m_tValueAverage);
}

//-------------------------------------------------------------------
// Function:    Tvalue>::GetMinMax
//
// Description: Calculates the Min and Max of the present array values
//				This is not a time optimised calculation. The array is rescanned every time.
//
// Parameters:  tValueMin       - Output of Min value in the array
//              tValueMax       - Output of Max value in the array
//
// Returns:     None
//-------------------------------------------------------------------
template< class Tvalue> inline void Tools_CyclicBuffer< Tvalue>::GetMinMax( Tvalue &tValueMin, Tvalue &tValueMax) const
{
	if( this->m_uValueCount == 0)
	{
		tValueMin = 0;
		tValueMax = 0;
		return;
	}
	
	tValueMin = this->m_ptValues[ 0];
	tValueMax = this->m_ptValues[ 0];
	for( u_int uArray = 1; uArray < this->m_uArrayValueSize; uArray += 1)
	{
		tValueMin = Asura_Maths::Min( tValueMin, this->m_ptValues[ uArray]);
		tValueMax = Asura_Maths::Max( tValueMax, this->m_ptValues[ uArray]);
	}
}

//-------------------------------------------------------------------
// Function:    Tvalue>::ValueAdd
//
// Description: Add a new value to the array
//				If there is not room then an old value will be poped
//
// Parameters:  tValueNew       - New Value
//
// Returns:     None
//-------------------------------------------------------------------
template< class Tvalue> inline void Tools_CyclicBuffer< Tvalue>::ValueAdd( const Tvalue tValueNew)
{
	this->m_uValues = (this->m_uValues + 1) % this->m_uArrayValueSize;
	if( this->m_uArrayValueSize <= this->m_uValueCount)
	{
		this->m_tArrayTotal -= this->m_ptValues[ this->m_uValues];
	}
	else
	{
		this->m_uValueCount += 1;
	}

	this->m_ptValues[ this->m_uValues] = tValueNew;
	this->m_tArrayTotal += tValueNew;
	this->m_tValueAverage = this->m_tArrayTotal / this->m_uValueCount;
}

//-------------------------------------------------------------------
// Function:    Tvalue>::Tools_CyclicBuffer
//
// Description: Create an array of N items
//
// Parameters:  uArrayValueSize - Size of items in the storage array. This memory is dynamically allocated. 
//
// Returns:     None
//-------------------------------------------------------------------
template< class Tvalue> inline Tools_CyclicBuffer< Tvalue>::Tools_CyclicBuffer( const u_int uArrayValueSize)
{
	this->m_tArrayTotal = 0;
	this->m_uValues = 0;
	this->m_uValueCount = 0;
	this->m_tValueAverage = 0;
	this->m_uArrayValueSize = uArrayValueSize;
	this->m_ptValues = new Tvalue[ this->m_uArrayValueSize];

	this->ValueAdd( 0);
}

template< class Tvalue> inline Tools_CyclicBuffer< Tvalue>::~Tools_CyclicBuffer( void)
{
	delete[] this->m_ptValues;
}

//*******************************************************************
//
// (c) 2006 Rebellion (Derby)
//
// Warning: This computer program is protected by copyright law and 
// international treaties. Unauthorized reproduction or distribution
// of this program, or any portion of it, may result in severe civil and
// criminal penalties, and will be prosecuted to the maximum extent 
// possible under the law.
//
//*******************************************************************

#endif //defined( ASURA_TOOLS)

#endif // _TOOLS_CYCLICBUFFER_H_
