//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
//=============================================================================//

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

// X360 optimizes out the extra memory needed by the editors in these types
#ifndef _X360
#define PHONEME_EDITOR 1
#endif

#include "utlvector.h"

class CUtlBuffer;

#define CACHED_SENTENCE_VERSION			1
#define CACHED_SENTENCE_VERSION_ALIGNED	4

//-----------------------------------------------------------------------------
// Purpose: A sample point
//-----------------------------------------------------------------------------
// Can't do this due to backward compat issues
//#ifdef _WIN32
//#pragma pack (1)
//#endif

struct CEmphasisSample
{
	float		time;
	float		value;

	void SetSelected( bool isSelected );
#if PHONEME_EDITOR
	// Used by editors only
	bool		selected;
#endif
};

class CBasePhonemeTag
{
public:
	CBasePhonemeTag();
	CBasePhonemeTag( const CBasePhonemeTag& from );

	CBasePhonemeTag &operator=( const CBasePhonemeTag &from )	{ memcpy( this, &from, sizeof(*this) ); return *this; }

	float GetStartTime() const				{ return m_flStartTime; }
	void SetStartTime( float startTime )	{ m_flStartTime = startTime; }
	void AddStartTime( float startTime )	{ m_flStartTime += startTime; }

	float GetEndTime() const				{ return m_flEndTime; }
	void SetEndTime( float endTime )		{ m_flEndTime = endTime; }
	void AddEndTime( float startTime )		{ m_flEndTime += startTime; }

	int GetPhonemeCode() const				{ return m_nPhonemeCode; }
	void SetPhonemeCode( int phonemeCode )	{ m_nPhonemeCode = phonemeCode; }

private:
	float			m_flStartTime;
	float			m_flEndTime;
	unsigned short	m_nPhonemeCode;
};

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
class CPhonemeTag : public CBasePhonemeTag
{
	typedef CBasePhonemeTag BaseClass;
public:

					CPhonemeTag( void );
					CPhonemeTag( const char *phoneme );
					CPhonemeTag( const CPhonemeTag& from );
					~CPhonemeTag( void );

	void			SetTag( const char *phoneme );
	char const		*GetTag() const;

	unsigned int	ComputeDataCheckSum();
#if PHONEME_EDITOR
	bool			m_bSelected;
	unsigned int	m_uiStartByte;
	unsigned int	m_uiEndByte;
#endif
	void SetSelected( bool isSelected );
	bool GetSelected() const;
	void SetStartAndEndBytes( unsigned int start, unsigned int end );
	unsigned int GetStartByte() const;
	unsigned int GetEndByte() const;

private:
	char			*m_szPhoneme;

};

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
class CWordTag
{
public:
					CWordTag( void );
					CWordTag( const char *word );
					CWordTag( const CWordTag& from );
					~CWordTag( void );

	void			SetWord( const char *word );
	const char		*GetWord() const;

	int				IndexOfPhoneme( CPhonemeTag *tag );

	unsigned int	ComputeDataCheckSum();

	float			m_flStartTime;
	float			m_flEndTime;

	CUtlVector	< CPhonemeTag *> m_Phonemes;
#if PHONEME_EDITOR
	bool			m_bSelected;
	unsigned int	m_uiStartByte;
	unsigned int	m_uiEndByte;
#endif
	void SetSelected( bool isSelected );
	bool GetSelected() const;
	void SetStartAndEndBytes( unsigned int start, unsigned int end );
	unsigned int GetStartByte() const;
	unsigned int GetEndByte() const;

private:
	char			*m_pszWord;
};

// A sentence can be closed captioned
// The default case is the entire sentence shown at start time
// 
// "<persist:2.0><clr:255,0,0,0>The <I>default<I> case"
// "<sameline>is the <U>entire<U> sentence shown at <B>start time<B>"

// Commands that aren't closed at end of phrase are automatically terminated
//
// Commands
// <linger:2.0>	The line should persist for 2.0 seconds beyond m_flEndTime
// <sameline>		Don't go to new line for next phrase on stack
// <clr:r,g,b,a>	Push current color onto stack and start drawing with new
//  color until we reach the next <clr> marker or a <clr> with no commands which
//  means restore the previous color
// <U>				Underline text (start/end)
// <I>				Italics text (start/end)
// <B>				Bold text (start/end)
// <position:where>	Draw caption at special location ??? needed
// <cr>				Go to new line

// Close Captioning Support
// The phonemes drive the mouth in english, but the CC text can
//  be one of several languages
enum
{
	CC_ENGLISH = 0,
	CC_FRENCH,
	CC_GERMAN,
	CC_ITALIAN,
	CC_KOREAN,
	CC_SCHINESE,  // Simplified Chinese
	CC_SPANISH,
	CC_TCHINESE,  // Traditional Chinese
	CC_JAPANESE,
	CC_RUSSIAN,
	CC_THAI,
	CC_PORTUGUESE,
	// etc etc

	CC_NUM_LANGUAGES
};

//-----------------------------------------------------------------------------
// Purpose: A sentence is a box of words, and words contain phonemes
//-----------------------------------------------------------------------------
class CSentence
{
public:
	static char const	*NameForLanguage( int language );
	static int			LanguageForName( char const *name );
	static void 		ColorForLanguage( int language, unsigned char& r, unsigned char& g, unsigned char& b );

	// Construction
					CSentence( void );
					~CSentence( void );

	// Assignment operator
	CSentence& operator =(const CSentence& src );

	void			Append( float starttime, const CSentence& src );

	void			SetText( const char *text );
	const char		*GetText( void ) const;

	void			InitFromDataChunk( void *data, int size );
	void			InitFromBuffer( CUtlBuffer& buf );
	void			SaveToBuffer( CUtlBuffer& buf );

	//				This strips out all of the stuff used by the editor, leaving just one blank work, no sentence text, and just
	//					the phonemes without the phoneme text...(same as the cacherestore version below)
	void			MakeRuntimeOnly();

	// This is a compressed save of just the data needed to drive phonemes in the engine (no word / sentence text, etc )
	void			CacheSaveToBuffer( CUtlBuffer& buf, int version );
	void			CacheRestoreFromBuffer( CUtlBuffer& buf );

	// Add word/phoneme to sentence
	void			AddPhonemeTag( CWordTag *word, CPhonemeTag *tag );
	void			AddWordTag( CWordTag *tag );

	void			Reset( void );

	void			ResetToBase( void );

	void			MarkNewPhraseBase( void );

	int				GetWordBase( void );

	int				CountPhonemes( void );

	// For legacy loading, try to find a word that contains the time
	CWordTag		*EstimateBestWord( float time );

	CWordTag		*GetWordForPhoneme( CPhonemeTag *phoneme );

	void			SetTextFromWords( void );

	float			GetIntensity( float time, float endtime );
	void			Resort( void );
	CEmphasisSample *GetBoundedSample( int number, float endtime );
	int				GetNumSamples( void );
	CEmphasisSample	*GetSample( int index );

	// Compute start and endtime based on all words
	void			GetEstimatedTimes( float& start, float &end );

	void			SetVoiceDuck( bool shouldDuck ) { m_bShouldVoiceDuck = shouldDuck; }
	bool			GetVoiceDuck() const { return m_bShouldVoiceDuck; }

	unsigned int	ComputeDataCheckSum();

	void			SetDataCheckSum( unsigned int chk );
	unsigned int	GetDataCheckSum() const;

	int				GetRuntimePhonemeCount() const;
	const CBasePhonemeTag *GetRuntimePhoneme( int i ) const;
	void			ClearRuntimePhonemes();
	void			AddRuntimePhoneme( const CPhonemeTag *src );

	void			CreateEventWordDistribution( char const *pszText, float flSentenceDuration );
	static int		CountWords( char const *pszText );
	static bool		ShouldSplitWord( char in );

public:
#if PHONEME_EDITOR
	char			*m_szText;

	CUtlVector< CWordTag * >	m_Words;
#endif
	CUtlVector	< CBasePhonemeTag *> m_RunTimePhonemes;

#if PHONEME_EDITOR
	int				m_nResetWordBase;
#endif
	// Phoneme emphasis data
	CUtlVector< CEmphasisSample > m_EmphasisSamples;

#if PHONEME_EDITOR
	unsigned int	m_uCheckSum;
#endif
	bool			m_bIsValid : 8;
	bool			m_bStoreCheckSum : 8;
	bool			m_bShouldVoiceDuck : 8;
	bool			m_bIsCached : 8;

private:
	void			ParseDataVersionOnePointZero( CUtlBuffer& buf );
	void			ParsePlaintext( CUtlBuffer& buf );
	void			ParseWords( CUtlBuffer& buf );
	void			ParseEmphasis( CUtlBuffer& buf );
	void			ParseOptions( CUtlBuffer& buf );
	void			ParseCloseCaption( CUtlBuffer& buf );

	void			ResetCloseCaptionAll( void );

	friend class PhonemeEditor;
};

//#ifdef _WIN32
//#pragma pack ()
//#endif

#endif // SENTENCE_H
