//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Real-Time Hierarchical Telemetry Profiling
//
// $NoKeywords: $
//=============================================================================//

#ifndef VPROF_TELEMETRY_H
#define VPROF_TELEMETRY_H

#if !defined( MAKE_VPC )

#if !defined( RAD_TELEMETRY_DISABLED ) && ( defined( IS_WINDOWS_PC ) || defined( _LINUX ) )
// Rad Telemetry profiling is enabled on Win32 and Win64.
#define RAD_TELEMETRY_ENABLED
#endif

#endif // !MAKE_VPC


#if !defined( RAD_TELEMETRY_ENABLED )

//
// Kill all tmZone() macros, etc.
//
#include "tmapi_dummy.h"

inline void TelemetryTick() {}
inline void TelemetrySetLevel( unsigned int Level ) {}
#define TelemetrySetLockName( _ctx, _location, _description ) 

class CTelemetryLock
{
public:
	CTelemetryLock(void *plocation, const char *description) {}
	~CTelemetryLock() {}
	void Locked() {}
	void Unlocked() {}
};

class CTelemetrySpikeDetector
{
public:
	CTelemetrySpikeDetector( const char *msg, uint32 threshold = 50 ) {}
	~CTelemetrySpikeDetector() { }
};

#else

//
// Telemetry is enabled. Include the telemetry header.
//
#include "../../thirdparty/telemetry/include/telemetry.h"
// Different versions of radbase.h define RADCOPYRIGHT to different values. So undef that here.
#undef RADCOPYRIGHT

struct TelemetryData
{
	HTELEMETRY tmContext[32];
	float flRDTSCToMilliSeconds;	// Conversion from tmFastTime() (rdtsc) to milliseconds.
	uint32 FrameCount;				// Count of frames to capture before turning off.
	char ServerAddress[128];		// Server name to connect to.
	int playbacktick;				// GetPlaybackTick() value from demo file (or 0 if not playing a demo).
	uint32 DemoTickStart;			// Start telemetry on demo tick #
	uint32 DemoTickEnd;				// End telemetry on demo tick #
	uint32 Level;					// Current Telemetry level (Use TelemetrySetLevel to modify)
};
PLATFORM_INTERFACE TelemetryData g_Telemetry;

PLATFORM_INTERFACE void TelemetryTick();
PLATFORM_INTERFACE void TelemetrySetLevel( unsigned int Level );

#define TELEMETRY_LEVEL0	g_Telemetry.tmContext[0]	// high level tmZone()
#define TELEMETRY_LEVEL1	g_Telemetry.tmContext[1]	// lower level tmZone(), tmZoneFiltered()
#define TELEMETRY_LEVEL2	g_Telemetry.tmContext[2]	// VPROF_0
#define TELEMETRY_LEVEL3	g_Telemetry.tmContext[3]	// VPROF_1
#define TELEMETRY_LEVEL4	g_Telemetry.tmContext[4]	// VPROF_2
#define TELEMETRY_LEVEL5	g_Telemetry.tmContext[5]	// VPROF_3
#define TELEMETRY_LEVEL6	g_Telemetry.tmContext[6]	// VPROF_4

#define TelemetrySetLockName( _ctx, _location, _description ) \
	do  													  \
	{   													  \
		static bool s_bNameSet = false; 					  \
		if( _ctx && !s_bNameSet )							  \
		{   												  \
			tmLockName( _ctx, _location, _description ); 	  \
			s_bNameSet = true;  							  \
		}   												  \
	} while( 0 )

class CTelemetryLock
{
public:
	CTelemetryLock(void *plocation, const char *description)
	{
		m_plocation = (const char *)plocation;
		m_description = description;
		TelemetrySetLockName( TELEMETRY_LEVEL1, m_plocation, m_description );
		tmTryLock( TELEMETRY_LEVEL1, m_plocation, "%s", m_description );
	}
	~CTelemetryLock()
	{
		Unlocked();
	}
	void Locked()
	{
		tmEndTryLock( TELEMETRY_LEVEL1, m_plocation, TMLR_SUCCESS );
		tmSetLockState( TELEMETRY_LEVEL1, m_plocation, TMLS_LOCKED, "%s Locked", m_description );
	}
	void Unlocked()
	{
		if( m_plocation )
		{
			tmSetLockState( TELEMETRY_LEVEL1, m_plocation, TMLS_RELEASED, "%s Released", m_description );
			m_plocation = NULL;
		}
	}

public:
	const char *m_plocation;
	const char *m_description;
};

class CTelemetrySpikeDetector
{
public:
	// Spews Telemetry message when threshold hit (in milliseconds.)
	CTelemetrySpikeDetector( const char *msg, float threshold = 5 ) :
		m_message( msg ), m_threshold( threshold ), time0( tmFastTime() ) {}
	~CTelemetrySpikeDetector()
	{
		float time = ( tmFastTime() - time0 ) * g_Telemetry.flRDTSCToMilliSeconds;
		if( time >= m_threshold )
		{
			tmMessage( TELEMETRY_LEVEL0, TMMF_ICON_NOTE | TMMF_SEVERITY_WARNING, "(source/spike)%s %.2fms %t", m_message, time, tmSendCallStack( TELEMETRY_LEVEL0, 0 ) );
		}
	}

private:
	TmU64 time0;
	float m_threshold;
	const char *m_message;
};

#endif // RAD_TELEMETRY_ENABLED

#endif // VPROF_TELEMETRY_H
