//====== Copyright (c), Valve Corporation, All rights reserved. =======
//
// Purpose: Provides a frame function manager that allows for different parts
//  of a GC to hook into per frame updated
//
//=============================================================================

#ifndef FRAMEFUNCTION_H
#define FRAMEFUNCTION_H
#ifdef _WIN32
#pragma once
#endif

namespace GCSDK
{

//the generic interface for frame functions. These can be derived from and should execute the work in BRun. It returns a boolean indicating whether or not it has
//more work to complete
class CBaseFrameFunction
{
public:

	//the different tiers of functions that can have functions tied to them
	enum EFrameType
	{
		k_EFrameType_RunOnce,					// called once per frame
		k_EFrameType_RunUntilCompleted,			// run tasks that shouldn't wait a frame between execution (gets called at least once per frame, more if work to do & we have time)		
		k_EFrameType_RunUntilCompletedLowPri,	// as above, but only runs if k_EFrameTypeRunUntilCompleted function return they have no remaining work to do
		//must come last
		k_EFrameType_Count
	};

	CBaseFrameFunction( const char *pchName, EFrameType eFrameType );
	virtual ~CBaseFrameFunction();

	// runs the item
	virtual bool BRun( const CLimitTimer &limitTimer ) = 0;

	//called to handle registering for updates and unregistering. Not registered by default
	void Register();
	void Deregister();
	bool IsRegistered() const				{ return m_bRegistered; }

protected:

	//the frame function manager has access to the internals to avoid exposing them to derived classes
	friend class CFrameFunctionMgr;

	//let the frame function manager access internals for profiling
	CUtlString	m_sName;					// function name (for debugging)
	uint64		m_nTrackedTime;				// how much time we have tracked with this frame function
	uint32		m_nNumCalls;				// the number of ticks that this has been associated with
	EFrameType	m_EFrameType;				// what kind of frame function is this
	bool		m_bRegistered;				// are we currently registered?
};


//a utility class that helps handle registering for frame functions and adapts it to a member function call
template < class T >
class CFrameFunction : 
	public CBaseFrameFunction
{
public:
	typedef bool ( T::*func_t )( const CLimitTimer &limitTimer );

	//construct and register all in one
	CFrameFunction( T *pObj, func_t func, const char *pchName, EFrameType eFrameType ) : 
		CBaseFrameFunction( pchName, eFrameType ), m_pObj( NULL ), m_Func( NULL )
	{
		Register( pObj, func );
	}

	//construct, but don't immediately register for updates
	CFrameFunction( const char *pchName, EFrameType eFrameType ) :
		CBaseFrameFunction( pchName, eFrameType ), m_pObj( NULL ), m_Func( NULL )
	{
	}

	void Register( T *pObj, func_t func )
	{
		m_pObj = pObj;
		m_Func = func;
		CBaseFrameFunction::Register();
	}

	virtual bool BRun( const CLimitTimer &limitTimer )
	{
		return (m_pObj->*m_Func)( limitTimer );
	}

	virtual bool BAllocedSeparately() { return false; }
private:
	T *m_pObj;
	func_t m_Func;
};

//the main manager that handles registration of all the frame functions and tracks performance and dispatches
//appropriately
class CFrameFunctionMgr
{
public:

	CFrameFunctionMgr();

	//called to register a main loop function for the specified tier
	void Register( CBaseFrameFunction* pFrameFunc );
	//handles unregistering a main loop function
	void Deregister( CBaseFrameFunction* pFrameFunc );

	//called to execute the main frame. This should preceded individual frame ticks
	void	RunFrame( const CLimitTimer& limitTimer );
	//called within a frame for each tick
	bool	RunFrameTick( const CLimitTimer& limitTimer );

	//called to dump a listing of the performance timings of all the frame functions that are registered
	void	DumpProfile();
	//resets the profile stats
	void	ClearProfile();

private:

	//sort function
	static bool SortFrameFuncByTime( const CBaseFrameFunction* pLhs, const CBaseFrameFunction* pRhs );

	//called to update the frame functions associated with the specified list
	bool RunFrameList( CBaseFrameFunction::EFrameType eType, const CLimitTimer& limitTimer );

	//the listing of subscribed 
	CUtlVector< CBaseFrameFunction* >	m_MainLoopFrameFuncs[ CBaseFrameFunction::k_EFrameType_Count ];
	//the number of frames that we have profiled
	uint32		m_nNumProfileFrames;
	//have we completed all of the high priority work for this frame?
	bool		m_bCompletedHighPri;
};

//the global frame function manager
CFrameFunctionMgr& GFrameFunctionMgr();

} //namespace GCSDK

#endif