//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
//=============================================================================//

#include "cbase.h"
#include "shareddefs.h"
#include "materialsystem/imesh.h"
#include "materialsystem/imaterial.h"
#include "view.h"
#include "iviewrender.h"
#include "view_shared.h"
#include "texture_group_names.h"
#include "tier0/icommandline.h"
#include "KeyValues.h"
#include "ScreenSpaceEffects.h"
#include "materialsystem/imaterialsystemhardwareconfig.h"

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

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
class C_EnvScreenOverlay : public C_BaseEntity
{
	DECLARE_CLASS( C_EnvScreenOverlay, C_BaseEntity );
public:
	DECLARE_CLIENTCLASS();

	void	PreDataUpdate( DataUpdateType_t updateType );
	void	PostDataUpdate( DataUpdateType_t updateType );

	void	HandleOverlaySwitch( void );
	void	StartOverlays( void );
	void	StopOverlays( void );
	void	StartCurrentOverlay( void );
	void	ClientThink( void );

protected:
	char	m_iszOverlayNames[ MAX_SCREEN_OVERLAYS ][255];
	float	m_flOverlayTimes[ MAX_SCREEN_OVERLAYS ];
	float	m_flStartTime;
	int     m_iDesiredOverlay;
	bool	m_bIsActive;
	bool	m_bWasActive;
	int		m_iCachedDesiredOverlay;
	int		m_iCurrentOverlay;
	float	m_flCurrentOverlayTime;
};

IMPLEMENT_CLIENTCLASS_DT( C_EnvScreenOverlay, DT_EnvScreenOverlay, CEnvScreenOverlay )
	RecvPropArray( RecvPropString( RECVINFO( m_iszOverlayNames[0]) ), m_iszOverlayNames ),
	RecvPropArray( RecvPropFloat( RECVINFO( m_flOverlayTimes[0] ) ), m_flOverlayTimes ),
	RecvPropFloat( RECVINFO( m_flStartTime ) ),
	RecvPropInt( RECVINFO( m_iDesiredOverlay ) ),
	RecvPropBool( RECVINFO( m_bIsActive ) ),
END_RECV_TABLE()

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : updateType - 
//-----------------------------------------------------------------------------
void C_EnvScreenOverlay::PreDataUpdate( DataUpdateType_t updateType )
{
	BaseClass::PreDataUpdate( updateType );

	m_bWasActive = m_bIsActive;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_EnvScreenOverlay::PostDataUpdate( DataUpdateType_t updateType )
{
	BaseClass::PostDataUpdate( updateType );

	// If we have a start time now, start the overlays going
	if ( m_bIsActive && m_flStartTime > 0 && view->GetScreenOverlayMaterial() == NULL )
	{
		StartOverlays();
	}
	
	if ( m_flStartTime == -1 )
	{
		 StopOverlays();
	}

	HandleOverlaySwitch();

	if ( updateType == DATA_UPDATE_CREATED &&
		CommandLine()->FindParm( "-makereslists" ) )
	{
		for ( int i = 0; i < MAX_SCREEN_OVERLAYS; ++i )
		{
			if ( m_iszOverlayNames[ i ] && m_iszOverlayNames[ i ][ 0 ] )
			{
				materials->FindMaterial( m_iszOverlayNames[ i ], TEXTURE_GROUP_CLIENT_EFFECTS, false );
			}
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_EnvScreenOverlay::StopOverlays( void )
{
	SetNextClientThink( CLIENT_THINK_NEVER );

	if ( m_bWasActive && !m_bIsActive )
	{
		view->SetScreenOverlayMaterial( NULL );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_EnvScreenOverlay::StartOverlays( void )
{
	m_iCurrentOverlay = 0;
	m_flCurrentOverlayTime = 0;
	m_iCachedDesiredOverlay	= 0;
	SetNextClientThink( CLIENT_THINK_ALWAYS );

	StartCurrentOverlay();
	HandleOverlaySwitch();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_EnvScreenOverlay::HandleOverlaySwitch( void )
{
	if( m_iCachedDesiredOverlay != m_iDesiredOverlay )
	{
		m_iCurrentOverlay = m_iDesiredOverlay;
		m_iCachedDesiredOverlay = m_iDesiredOverlay;
		StartCurrentOverlay();
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_EnvScreenOverlay::StartCurrentOverlay( void )
{
	if ( m_iCurrentOverlay == MAX_SCREEN_OVERLAYS || !m_iszOverlayNames[m_iCurrentOverlay] || !m_iszOverlayNames[m_iCurrentOverlay][0] )
	{
		// Hit the end of our overlays, so stop.
		m_flStartTime = 0;
		StopOverlays();
		return;
	}

	if ( m_flOverlayTimes[m_iCurrentOverlay] == -1 )
		 m_flCurrentOverlayTime = -1;
	else
		 m_flCurrentOverlayTime = gpGlobals->curtime + m_flOverlayTimes[m_iCurrentOverlay];

	// Bring up the current overlay
	IMaterial *pMaterial = materials->FindMaterial( m_iszOverlayNames[m_iCurrentOverlay], TEXTURE_GROUP_CLIENT_EFFECTS, false );
	if ( !IsErrorMaterial( pMaterial ) )
	{
		view->SetScreenOverlayMaterial( pMaterial );
	}
	else
	{
		Warning("env_screenoverlay couldn't find overlay %s.\n", m_iszOverlayNames[m_iCurrentOverlay] );
		StopOverlays();
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_EnvScreenOverlay::ClientThink( void )
{
	// If the current overlay's run out, go to the next one
	if ( m_flCurrentOverlayTime != -1 && m_flCurrentOverlayTime < gpGlobals->curtime )
	{
		m_iCurrentOverlay++;
		StartCurrentOverlay();
	}
}

// Effect types
enum 
{
	SCREENEFFECT_EP2_ADVISOR_STUN,
	SCREENEFFECT_EP1_INTRO,
	SCREENEFFECT_EP2_GROGGY,
};

// ============================================================================
//  Screenspace effect
// ============================================================================

class C_EnvScreenEffect : public C_BaseEntity
{
	DECLARE_CLASS( C_EnvScreenEffect, C_BaseEntity );
public:
	DECLARE_CLIENTCLASS();

	virtual void ReceiveMessage( int classID, bf_read &msg );

private:
	float	m_flDuration;
	int		m_nType;
};

IMPLEMENT_CLIENTCLASS_DT( C_EnvScreenEffect, DT_EnvScreenEffect, CEnvScreenEffect )
	RecvPropFloat( RECVINFO( m_flDuration ) ),
	RecvPropInt( RECVINFO( m_nType ) ),
END_RECV_TABLE()

//-----------------------------------------------------------------------------
// Purpose: 
// Input  : classID - 
//			&msg - 
//-----------------------------------------------------------------------------
void C_EnvScreenEffect::ReceiveMessage( int classID, bf_read &msg )
{
	// Make sure our IDs match
	if ( classID != GetClientClass()->m_ClassID )
	{
		// Message is for subclass
		BaseClass::ReceiveMessage( classID, msg );
		return;
	}

	int messageType = msg.ReadByte();
	switch( messageType )
	{
		// Effect turning on
		case 0: // FIXME: Declare
			{		
				// Create a keyvalue block to set these params
				KeyValues *pKeys = new KeyValues( "keys" );
				if ( pKeys == NULL )
					return;

				if ( m_nType == SCREENEFFECT_EP1_INTRO )
				{
					if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 )
					{
						return;
					}

					// Set our keys
					pKeys->SetFloat( "duration", m_flDuration );
					pKeys->SetInt( "fadeout", 0 );

					g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "episodic_intro", pKeys );
					g_pScreenSpaceEffects->EnableScreenSpaceEffect( "episodic_intro" );
				}
				else if ( m_nType == SCREENEFFECT_EP2_ADVISOR_STUN )
				{
					// Set our keys
					pKeys->SetFloat( "duration", m_flDuration );

					g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "episodic_stun", pKeys );
					g_pScreenSpaceEffects->EnableScreenSpaceEffect( "episodic_stun" );
				}
				else if ( m_nType == SCREENEFFECT_EP2_GROGGY )
				{
					if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 )
						return;

					// Set our keys
					pKeys->SetFloat( "duration", m_flDuration );
					pKeys->SetInt( "fadeout", 0 );

					g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "ep2_groggy", pKeys );
					g_pScreenSpaceEffects->EnableScreenSpaceEffect( "ep2_groggy" );
				}
                
				pKeys->deleteThis();
			}
			break;

		// Effect turning off
		case 1:	// FIXME: Declare
			
			if ( m_nType == SCREENEFFECT_EP1_INTRO )
			{
				if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 )
				{
					return;
				}
				// Create a keyvalue block to set these params
				KeyValues *pKeys = new KeyValues( "keys" );
				if ( pKeys == NULL )
					return;

				// Set our keys
				pKeys->SetFloat( "duration", m_flDuration );
				pKeys->SetInt( "fadeout", 1 );

				g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "episodic_intro", pKeys );
			}
			else if ( m_nType == SCREENEFFECT_EP2_ADVISOR_STUN )
			{
				g_pScreenSpaceEffects->DisableScreenSpaceEffect( "episodic_stun" );
			}
			else if ( m_nType == SCREENEFFECT_EP2_GROGGY )
			{
				if( g_pMaterialSystemHardwareConfig->GetDXSupportLevel() < 80 )
				{
					return;
				}
				// Create a keyvalue block to set these params
				KeyValues *pKeys = new KeyValues( "keys" );
				if ( pKeys == NULL )
					return;

				// Set our keys
				pKeys->SetFloat( "duration", m_flDuration );
				pKeys->SetInt( "fadeout", 1 );

				g_pScreenSpaceEffects->SetScreenSpaceEffectParams( "ep2_groggy", pKeys );
			}

			break;
	}
}
