//========= Copyright (c), Valve LLC, All rights reserved. ============
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================


#include "stdafx.h"
#include "steamextra/gamecoordinator/igamecoordinatorhost.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

//-----------------------------------------------------------------------------
// Maximum length of a sprintf'ed logging message.
//-----------------------------------------------------------------------------
const int MAX_LOGGING_MESSAGE_LENGTH = 2048;

namespace GCSDK
{

int g_nMaxSpewLevel = 4;
int g_nMaxLogLevel = 4;

//-----------------------------------------------------------------------------
// Purpose: Sends an event back to the GC host for logging
// Input:	pchGroupName - group to log to
//			spewType - the type of the message
//			iLevel - level of spew ( 0..4 )
//			iLevelLog - level for logging
//			pchMsg - printf format
//-----------------------------------------------------------------------------
void EmitBaseMessageV( const char *pchGroupName, SpewType_t spewType, int iSpewLevel, int iLevelLog, const char *pchMsg, va_list vaArgs )
{
	VPROF_BUDGET( "GCHost", VPROF_BUDGETGROUP_STEAM );

	char pchBuf[ MAX_LOGGING_MESSAGE_LENGTH ];
	Q_vsnprintf( pchBuf, MAX_LOGGING_MESSAGE_LENGTH, pchMsg, vaArgs );

#ifdef GC
// !FIXME! DOTAMERGE
//	// If this is coming from the context of a job, then allow that job to
//	// override our emit via a specified handler.
//	if ( g_pJobCur )
//	{
//		IJobEmitSpewHandler *pHandler = g_pJobCur->GetEmitSpewHandler();
//		if ( pHandler )
//		{
//			bool bOutputSpew = pHandler->OnEmitSpew( pchGroupName, spewType, iSpewLevel, iLevelLog, pchBuf );
//			if ( !bOutputSpew )
//			{
//				return;
//			}
//		}
//	}

	{
		VPROF_BUDGET( "GCHost - EmitMessage", VPROF_BUDGETGROUP_STEAM );
		// !FIXME! DOTAMERGE
		//GGCInterface()->EmitSpew( pchGroupName, spewType, iSpewLevel, iLevelLog, pchBuf );
		GGCHost()->EmitMessage( pchGroupName, spewType, iSpewLevel, iLevelLog, pchBuf );
	}
#else
	// TODO: Actually log it
	DevMsg( "%s", pchBuf );
#endif
}

//similar to the above, but takes in a group, and handles filtering messages out that are disabled, and extracting other info from the group
void EmitBaseMessageV( const CGCEmitGroup& Group, SpewType_t spewType, int iConsoleLevel, int iLogLevel, const char *pchMsg, va_list vaArgs )
{
	int iClampConsoleLevel	= ( iConsoleLevel <= MIN( Group.GetConsoleLevel(), g_nMaxSpewLevel ) ) ? SPEW_ALWAYS : SPEW_NEVER;
	int iClampLogLevel		= ( iLogLevel <= MIN( Group.GetLogLevel(), g_nMaxLogLevel ) ) ? LOG_ALWAYS : LOG_NEVER;
	if( ( iClampConsoleLevel != SPEW_NEVER ) || ( iClampLogLevel != LOG_NEVER ) )
		EmitBaseMessageV( Group.GetName(), spewType, iClampConsoleLevel, iClampLogLevel, pchMsg, vaArgs );
}

//------------------------------
// AssertError

void CGCEmitGroup::Internal_AssertError( const char *pchMsg, ... ) const
{
	va_list args;
	va_start( args, pchMsg );
	AssertErrorV( pchMsg, args );
	va_end( args );
}

void CGCEmitGroup::AssertErrorV( const char *pchMsg, va_list vaArgs ) const
{
	EmitBaseMessageV( *this, SPEW_ASSERT, 1, 1, pchMsg, vaArgs );
}

//------------------------------
// Error

void CGCEmitGroup::Internal_Error( const char *pchMsg, ... ) const
{
	va_list args;
	va_start( args, pchMsg );
	ErrorV( pchMsg, args );
	va_end( args );
}

void CGCEmitGroup::ErrorV( const char *pchMsg, va_list vaArgs ) const
{
	EmitBaseMessageV( *this, SPEW_ERROR, 1, 1, pchMsg, vaArgs );
}

//------------------------------
// Warning

void CGCEmitGroup::Internal_Warning( const char *pchMsg, ... ) const
{
	va_list args;
	va_start( args, pchMsg );
	WarningV( pchMsg, args );
	va_end( args );
}

void CGCEmitGroup::WarningV( const char *pchMsg, va_list vaArgs ) const
{
	EmitBaseMessageV( *this, SPEW_WARNING, 2, 2, pchMsg, vaArgs );
}

//------------------------------
// Msg

void CGCEmitGroup::Internal_Msg( const char *pchMsg, ... ) const
{
	va_list args;
	va_start( args, pchMsg );
	MsgV( pchMsg, args );
	va_end( args );
}

void CGCEmitGroup::MsgV( const char *pchMsg, va_list vaArgs ) const
{
	EmitBaseMessageV( *this, SPEW_MESSAGE, 3, 3, pchMsg, vaArgs );
}

//------------------------------
// Verbose

void CGCEmitGroup::Internal_Verbose( const char *pchMsg, ... ) const
{
	va_list args;
	va_start( args, pchMsg );
	VerboseV( pchMsg, args );
	va_end( args );
}

void CGCEmitGroup::VerboseV( const char *pchMsg, va_list vaArgs ) const
{
	EmitBaseMessageV( *this, SPEW_MESSAGE, 4, 4, pchMsg, vaArgs );
}


//------------------------------
// Verbose

void CGCEmitGroup::Internal_BoldMsg( const char *pchMsg, ... ) const
{
	va_list args;
	va_start( args, pchMsg );
	BoldMsgV( pchMsg, args );
	va_end( args );
}

void CGCEmitGroup::BoldMsgV( const char *pchMsg, va_list vaArgs ) const
{
	// !FIXME! DOTAMERGE
	//EmitBaseMessageV( *this, SPEW_BOLD_MESSAGE, 1, 1, pchMsg, vaArgs );
	EmitBaseMessageV( *this, SPEW_MESSAGE, 1, 1, pchMsg, vaArgs );
}


//------------------------------
// General Emit


void CGCEmitGroup::Internal_Emit( EMsgLevel eLvl, PRINTF_FORMAT_STRING const char *pchMsg, ... ) const
{
	va_list args;
	va_start( args, pchMsg );
	EmitV( eLvl, pchMsg, args );
	va_end( args );
}

void CGCEmitGroup::EmitV( EMsgLevel eLvl, PRINTF_FORMAT_STRING const char *pchMsg, va_list vaArgs ) const
{
	switch( eLvl )
	{
	case kMsg_Error:	ErrorV( pchMsg, vaArgs );		break;
	case kMsg_Warning:	WarningV( pchMsg, vaArgs );		break;
	case kMsg_Msg:		MsgV( pchMsg, vaArgs );			break;
	case kMsg_Verbose:	VerboseV( pchMsg, vaArgs );		break;
	default:
		AssertMsg1( false, "Unexpected error level of %d provided to GCEmitGroup::Emit", eLvl );
		break;
	}
}



//---------------------------------------------------------------------
// Legacy Interface
//---------------------------------------------------------------------

void EGInternal_EmitInfo( const CGCEmitGroup& Group, int iLevel, int iLevelLog, const char *pchMsg, ... )
{
	va_list args;
	va_start( args, pchMsg );
	EmitBaseMessageV( Group, SPEW_MESSAGE, iLevel, iLevelLog, pchMsg, args );
	va_end( args );
}

void EmitInfoV( const CGCEmitGroup& Group, int iLevel, int iLevelLog, const char *pchMsg, va_list vaArgs )
{
	EmitBaseMessageV( Group, SPEW_MESSAGE, iLevel, iLevelLog, pchMsg, vaArgs );
}

void EmitWarning( const CGCEmitGroup& Group, int iLevel, const char *pchMsg, ... )
{
	va_list args;
	va_start( args, pchMsg );
	EmitBaseMessageV( Group, SPEW_WARNING, iLevel, iLevel, pchMsg, args );
	va_end( args );
}

void EmitError( const CGCEmitGroup& Group, const char *pchMsg, ... )
{
	va_list args;
	va_start( args, pchMsg );
	EmitBaseMessageV( Group, SPEW_ERROR, 1, 1, pchMsg, args );
	va_end( args );
}

// Emit an assert-like error, generating a minidump
void EmitAssertError( const CGCEmitGroup& Group, const char *pchMsg, ... )
{
	va_list args;
	va_start( args, pchMsg );
	EmitBaseMessageV( Group, SPEW_ASSERT, 1, 1, pchMsg, args );
	va_end( args );
}

//legacy group types
DECLARE_GC_EMIT_GROUP( SPEW_SYSTEM_MISC, system );
DECLARE_GC_EMIT_GROUP( SPEW_JOB, job );
DECLARE_GC_EMIT_GROUP( SPEW_CONSOLE, console );
DECLARE_GC_EMIT_GROUP( SPEW_GC, gc );
DECLARE_GC_EMIT_GROUP( SPEW_SQL, sql );
DECLARE_GC_EMIT_GROUP( SPEW_NETWORK, network );
DECLARE_GC_EMIT_GROUP( SPEW_SHAREDOBJ, sharedobj );
DECLARE_GC_EMIT_GROUP( SPEW_MICROTXN, microtxn );
DECLARE_GC_EMIT_GROUP( SPEW_PROMO, promo );
DECLARE_GC_EMIT_GROUP( SPEW_PKGITEM, pkgitem );
DECLARE_GC_EMIT_GROUP( SPEW_ECONOMY, econ );
DECLARE_GC_EMIT_GROUP( SPEW_THREADS, threads );

} // namespace GCSDK