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

#ifndef AI_SENTENCE_H
#define AI_SENTENCE_H

#include "ai_component.h"
#include "ai_basenpc.h"
#include "SoundEmitterSystem/isoundemittersystembase.h"


//-----------------------------------------------------------------------------
// Sentence helper class used by humanoids sometimes. To use:
// 1) Include it into the leaf class
// 2) Use DEFINE_EMBEDDED to save/load its state
// 3) Call Init in the CreateComponents method
// 4) Use Speak() when it's time to speak
// 5) Add m_Sentences.UpdateSentenceQueue(); to the PrescheduleThink method of an NPC
//		 to get queued sentence support working
//-----------------------------------------------------------------------------
enum SentenceCriteria_t
{
	SENTENCE_CRITERIA_ALWAYS = 0,
	SENTENCE_CRITERIA_NORMAL,		// Obeys gag rules
	SENTENCE_CRITERIA_IN_SQUAD,
	SENTENCE_CRITERIA_SQUAD_LEADER,
};

enum SentencePriority_t
{
	SENTENCE_PRIORITY_INVALID = -1,
	SENTENCE_PRIORITY_NORMAL = 0,
	SENTENCE_PRIORITY_MEDIUM = 1,
	SENTENCE_PRIORITY_HIGH = 2,
};


//-----------------------------------------------------------------------------
// This is the met of the class
//-----------------------------------------------------------------------------
abstract_class CAI_SentenceBase : public CAI_Component 
{
	DECLARE_CLASS_NOBASE( CAI_SentenceBase );
	DECLARE_SIMPLE_DATADESC();

public:
	CAI_SentenceBase();

	void SetVoicePitch( int voicePitch );
	int GetVoicePitch() const;

	// Check for queued-up-sentences + speak them
	void UpdateSentenceQueue();

	// Returns the sentence index played, which can be used to determine
	// the sentence length of time using engine->SentenceLength
	int Speak( const char *pSentence, SentencePriority_t nSoundPriority = SENTENCE_PRIORITY_NORMAL, SentenceCriteria_t nCriteria = SENTENCE_CRITERIA_IN_SQUAD );

	// Returns the sentence index played, which can be used to determine
	// the sentence length of time using engine->SentenceLength. If the sentence
	// was queued, then -1 is returned, which is the same result as if the sound wasn't played
	int SpeakQueued( const char *pSentence, SentencePriority_t nSoundPriority = SENTENCE_PRIORITY_NORMAL, SentenceCriteria_t nCriteria = SENTENCE_CRITERIA_IN_SQUAD );

	// Clears the sentence queue
	void ClearQueue();

protected:
	virtual float GetVolume() = 0;
	virtual soundlevel_t GetSoundLevel() = 0;

private:
	// Speech criteria
	bool MatchesCriteria( SentenceCriteria_t nCriteria );

	// Play the actual sentence
	int PlaySentence( const char *pSentence );

	// Debug output
	void SentenceMsg( const char *pStatus, const char *pSentence );

	int		m_voicePitch;
	int		m_nQueuedSentenceIndex;
	float	m_flQueueTimeout;
	int		m_nQueueSoundPriority;
};


//-----------------------------------------------------------------------------
// NOTE: This is a template class so each user has a different set of globals
//-----------------------------------------------------------------------------
template< class NPC_CLASS >
class CAI_Sentence : public CAI_SentenceBase 
{
	DECLARE_CLASS_NOFRIEND( CAI_Sentence, CAI_SentenceBase );

public:
	void Init( NPC_CLASS *pOuter, const char *pGameSound );

protected:
	virtual float GetVolume() { return m_sentenceVolume; }
	virtual soundlevel_t GetSoundLevel() { return m_sentenceSoundlevel; }

private:
	static float m_sentenceVolume;
	static soundlevel_t m_sentenceSoundlevel;
	static int m_voicePitchMin;
	static int m_voicePitchMax;
};


//-----------------------------------------------------------------------------
// Voice pitch
//-----------------------------------------------------------------------------
inline void CAI_SentenceBase::SetVoicePitch( int voicePitch )
{ 
	m_voicePitch = voicePitch; 
}

inline int CAI_SentenceBase::GetVoicePitch() const
{ 
	return m_voicePitch; 
}


//-----------------------------------------------------------------------------
// Set up the class's sentence information
//-----------------------------------------------------------------------------
template< class NPC_CLASS >
void CAI_Sentence< NPC_CLASS >::Init( NPC_CLASS *pOuter, const char *pGameSound )
{
	SetOuter( pOuter );

	if ( m_voicePitchMin <= 0 || m_voicePitchMax <= 0 )
	{
		// init the sentence parameters using a dummy gamesounds entry
		CSoundParameters params;
		if ( GetOuter()->GetParametersForSound( pGameSound, params, NULL ) )
		{
			m_sentenceVolume = params.volume;
			m_sentenceSoundlevel = params.soundlevel;
			m_voicePitchMin = params.pitchlow;
			m_voicePitchMax = params.pitchhigh;
		}
	}
	
	// Select a voice pitch
	if ( random->RandomInt(0,1) )
	{
		SetVoicePitch( random->RandomInt( m_voicePitchMin, m_voicePitchMax ) );
	}
	else
	{
		SetVoicePitch( 100 );
	}
}


//-----------------------------------------------------------------------------
// Global instantiation
//-----------------------------------------------------------------------------
template< class NPC_CLASS > float CAI_Sentence< NPC_CLASS >::m_sentenceVolume = 1.0f;
template< class NPC_CLASS > soundlevel_t CAI_Sentence< NPC_CLASS >::m_sentenceSoundlevel = SNDLVL_NORM;
template< class NPC_CLASS > int CAI_Sentence< NPC_CLASS >::m_voicePitchMin = 0;
template< class NPC_CLASS > int CAI_Sentence< NPC_CLASS >::m_voicePitchMax = 0;



#endif	// AI_SENTENCE_H