//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================//

#ifndef SOURCESDK_CS2_KEYVALUES_H
#define SOURCESDK_CS2_KEYVALUES_H

#ifdef _WIN32
#pragma once
#endif

#ifndef NULL
#ifdef __cplusplus
#define NULL    0
#else
#define NULL    ((void *)0)
#endif
#endif

#include "../../../../AfxHookSource/SourceSdkShared.h"
//#include "utlvector.h"
//#include "Color.h"
//#include "exprevaluator.h"
#include "../vstdlib/IKeyValuesSystem.h"

namespace SOURCESDK {
namespace CS2 {

class IFileSystem;
class CUtlBuffer;
//class Color;
class KeyValues;
//class IKeyValuesDumpContext;
//class IKeyValuesErrorSpew;
//typedef void *FileHandle_t;

typedef size_t uintp;

// single byte identifies a xbox kv file in binary format
// strings are pooled from a searchpath/zip mounted symbol table
#define SOURCESDK_CS2_KV_BINARY_POOLED_FORMAT 0xAA


#define SOURCESDK_CS2_FOR_EACH_SUBKEY( kvRoot, kvSubKey ) \
	for ( KeyValues * kvSubKey = kvRoot->GetFirstSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextKey() )

#define SOURCESDK_CS2_FOR_EACH_TRUE_SUBKEY( kvRoot, kvSubKey ) \
	for ( KeyValues * kvSubKey = kvRoot->GetFirstTrueSubKey(); kvSubKey != NULL; kvSubKey = kvSubKey->GetNextTrueSubKey() )

#define SOURCESDK_CS2_FOR_EACH_VALUE( kvRoot, kvValue ) \
	for ( KeyValues * kvValue = kvRoot->GetFirstValue(); kvValue != NULL; kvValue = kvValue->GetNextValue() )
/*
DECLARE_POINTER_HANDLE( HTemporaryKeyValueAllocationScope );

class CTemporaryKeyValues
{
	CTemporaryKeyValues() : m_pKeyValues(nullptr), m_hScope() {}
	~CTemporaryKeyValues()
	{
		// GAMMACASE: TODO: Complete with actual KeyValuesSystem call once it's reversed too.
#if 0
		KeyValuesSystem()->ReleaseTemporaryAllocationScope( m_hScope );
#endif
	}

private:
	KeyValues *m_pKeyValues;
	HTemporaryKeyValueAllocationScope m_hScope;
};*/

#pragma pack(push,1)
class CKeyValues_Data
{
public:
	// Data type
	enum types_t
	{
		TYPE_NONE = 0,
		TYPE_STRING,
		TYPE_INT,
		TYPE_FLOAT,
		TYPE_PTR,
		TYPE_WSTRING,
		TYPE_COLOR,
		TYPE_UINT64,
		TYPE_COMPILED_INT_BYTE,			// hack to collapse 1 byte ints in the compiled format
		TYPE_COMPILED_INT_0,			// hack to collapse 0 in the compiled format
		TYPE_COMPILED_INT_1,			// hack to collapse 1 in the compiled format
		TYPE_NUMTYPES,
	};

//private:
protected:
	IKeyValuesSystem *KVSystem() const;

	Color ResolveColorValue() const;
	float ResolveFloatValue() const;
	int ResolveIntValue() const;
	uint64 ResolveUint64Value() const;
	const char *ResolveStringValue() const;
	const wchar_t *ResolveWStringValue() const;
	KeyValues *ResolveSubKeyValue() const;

	void Internal_ClearAll();
	void Internal_ClearData();

	void Internal_CopyData( const CKeyValues_Data &kv );
	void Internal_CopyName( const CKeyValues_Data &kv );

	bool Internal_IsEqual( CKeyValues_Data *pOther );

	const char *Internal_GetName() const;

	KeyValues *Internal_GetSubKey() const;
	void Internal_SetSubKey( KeyValues *subkey );

	HKeySymbol Internal_GetNameSymbol() const;
	HKeySymbol Internal_GetNameSymbolCaseSensitive() const;

	void Internal_SetName( char const *szName );
	void Internal_SetNameFrom( CKeyValues_Data const &pOther );

	Color Internal_GetColor( Color defaultClr ) const;
	float Internal_GetFloat() const;
	int Internal_GetInt() const;
	uint64 Internal_GetUint64() const;
	char const *Internal_GetString( const char *defaultValue, char *szBuf, size_t maxlen );
	const wchar_t *Internal_GetWString( const wchar_t *defaultValue, wchar_t *szBuf, size_t maxlen );
	void *Internal_GetPtr() const;
	
	void Internal_SetColor( Color value );
	void Internal_SetFloat( float value );
	void Internal_SetInt( int value );
	void Internal_SetUint64( uint64 value );
	void Internal_SetString( const char *value );
	void Internal_SetWString( const wchar_t *value );
	void Internal_SetPtr( void *value );

	void Internal_SetFromString( types_t type, const char *value );

	bool Internal_HasEscapeSequences() const;
	void Internal_SetHasEscapeSequences( bool state );

	union  {
		struct {
			union
			{
				int m_iValue;
				float m_flValue;
				void *m_pValue;
				unsigned char m_Color[4];
				uintp m_uValue;
				const char *m_sValue;
				const wchar_t *m_wsValue;
				KeyValues * m_pSub;
			};

			void * pUnk1;

			uint32 m_iKeyNameCaseSensitive : 24;
			uint32 m_iDataType : 3;
			uint32 m_bHasEscapeSequences : 1;
			uint32 m_bAllocatedExternalMemory : 1;
			uint32 m_bKeySymbolCaseSensitiveMatchesCaseInsensitive : 1;
			uint32 m_bStoredSubKey : 1;

			KeyValues * m_pPeer;
		} a;
		struct {
			KeyValues * m_pKeys0;
			KeyValues * m_pKeys1;
			KeyValues * m_pKeys2;
			KeyValues * m_pKeys3;
			KeyValues * m_pKeys4;
			KeyValues * m_pKeys5;
			KeyValues * m_pKeys6;
			KeyValues * m_pKeys7;
		} b;
		unsigned char c[8*8];
	};
};
#pragma pack(pop)

//-----------------------------------------------------------------------------
// Purpose: Simple recursive data access class
//			Used in vgui for message parameters and resource files
//			Destructor deletes all child KeyValues nodes
//			Data is stored in key (string names) - (string/int/float)value pairs called nodes.
//
//	About KeyValues Text File Format:

//	It has 3 control characters '{', '}' and '"'. Names and values may be quoted or
//	not. The quote '"' charater must not be used within name or values, only for
//	quoting whole tokens. You may use escape sequences wile parsing and add within a
//	quoted token a \" to add quotes within your name or token. When using Escape
//	Sequence the parser must now that by setting KeyValues::UsesEscapeSequences( true ),
//	which it's off by default. Non-quoted tokens ends with a whitespace, '{', '}' and '"'.
//	So you may use '{' and '}' within quoted tokens, but not for non-quoted tokens.
//  An open bracket '{' after a key name indicates a list of subkeys which is finished
//  with a closing bracket '}'. Subkeys use the same definitions recursively.
//  Whitespaces are space, return, newline and tabulator. Allowed Escape sequences
//	are \n, \t, \\, \n and \". The number character '#' is used for macro purposes 
//	(eg #include), don't use it as first charater in key names.
//-----------------------------------------------------------------------------
#pragma pack(push,1)
class KeyValues : public CKeyValues_Data
{
public:
	KeyValues() {}

	//
	// AutoDelete class to automatically free the keyvalues.
	// Simply construct it with the keyvalues you allocated and it will free them when falls out of scope.
	// When you decide that keyvalues shouldn't be deleted call Assign(NULL) on it.
	// If you constructed AutoDelete(NULL) you can later assign the keyvalues to be deleted with Assign(pKeyValues).
	//
	class AutoDelete
	{
	public:
		explicit inline AutoDelete( KeyValues *pKeyValues ) : m_pKeyValues( pKeyValues ) {}
		explicit inline AutoDelete( const char *pchKVName ) : m_pKeyValues( new KeyValues( pchKVName ) ) {}
		inline ~AutoDelete( void ) { if(m_pKeyValues) delete m_pKeyValues; }
		inline void Assign( KeyValues *pKeyValues ) { m_pKeyValues = pKeyValues; }
		KeyValues *operator->() { return m_pKeyValues; }
		operator KeyValues *() { return m_pKeyValues; }
	private:
		AutoDelete( AutoDelete const &x ); // forbid
		AutoDelete &operator= ( AutoDelete const &x ); // forbid
	protected:
		KeyValues *m_pKeyValues;
	};

	//
	// AutoDeleteInline is useful when you want to hold your keyvalues object inside
	// and delete it right after using.
	// You can also pass temporary KeyValues object as an argument to a function by wrapping it into KeyValues::AutoDeleteInline
	// instance:   call_my_function( KeyValues::AutoDeleteInline( new KeyValues( "test" ) ) )
	//
	class AutoDeleteInline : public AutoDelete
	{
	public:
		explicit inline AutoDeleteInline( KeyValues *pKeyValues ) : AutoDelete( pKeyValues ) {}
		inline operator KeyValues *() const { return m_pKeyValues; }
		inline KeyValues *Get() const { return m_pKeyValues; }
	};

	// Quick setup constructors
	KeyValues( const char *setName, IKeyValuesSystem *kvsystem = NULL, bool unkState = false );
	KeyValues( const char *setName, const char *firstKey, const char *firstValue );
	KeyValues( const char *setName, const char *firstKey, const wchar_t *firstValue );
	KeyValues( const char *setName, const char *firstKey, int firstValue );
	KeyValues( const char *setName, const char *firstKey, const char *firstValue, const char *secondKey, const char *secondValue );
	KeyValues( const char *setName, const char *firstKey, int firstValue, const char *secondKey, int secondValue );

	~KeyValues();

	// Section name
	const char *GetName() const;
	void SetName( const char *setName );

	// gets the name as a unique int
	HKeySymbol GetNameSymbol() const;
	HKeySymbol GetNameSymbolCaseSensitive() const;

	// File access. Set UsesEscapeSequences true, if resource file/buffer uses Escape Sequences (eg \n, \t)
	//void UsesEscapeSequences( bool state ); // default false
	//bool LoadFromFile( IFileSystem *filesystem, const char *resourceName, const char *pathID = NULL, GetSymbolProc_t pfnEvaluateSymbolProc = NULL, void *pUnk1 = NULL, const char *pUnk2 = NULL );
	//bool SaveToFile( IFileSystem *filesystem, const char *resourceName, const char *pathID = NULL, bool bAllowEmptyString = false );
	// Read from a buffer...  Note that the buffer must be null terminated
	//bool LoadFromBuffer( char const *resourceName, const char *pBuffer, IFileSystem *pFileSystem = NULL, const char *pPathID = NULL, GetSymbolProc_t pfnEvaluateSymbolProc = NULL, IKeyValuesErrorSpew *pErrorSpew = NULL, void *pUnk1 = NULL, const char *pUnk2 = NULL );

	// Read from a utlbuffer...
	//bool LoadFromBuffer( char const *resourceName, CUtlBuffer &buf, IFileSystem *pFileSystem = NULL, const char *pPathID = NULL, GetSymbolProc_t pfnEvaluateSymbolProc = NULL, IKeyValuesErrorSpew *pErrorSpew = NULL, void *pUnk1 = NULL, const char *pUnk2 = NULL );

	//CTemporaryKeyValues *LoadTemporaryFromBuffer( bool, char const *resourceName, const char *pBuffer, IFileSystem *pFileSystem = NULL, const char *pPathID = NULL, GetSymbolProc_t pfnEvaluateSymbolProc = NULL, IKeyValuesErrorSpew *pErrorSpew = NULL, void *pUnk1 = NULL, const char *pUnk2 = NULL );
	//CTemporaryKeyValues *LoadTemporaryFromBuffer( bool, char const *resourceName, CUtlBuffer &buf, IFileSystem *pFileSystem = NULL, const char *pPathID = NULL, GetSymbolProc_t pfnEvaluateSymbolProc = NULL, void *pUnk1 = NULL, const char *pUnk2 = NULL );

	//CTemporaryKeyValues *LoadTemporaryFromFile( bool, IFileSystem *filesystem, const char *resourceName, const char *pathID = NULL, GetSymbolProc_t pfnEvaluateSymbolProc = NULL, void *pUnk1 = NULL, const char *pUnk2 = NULL );

	// Find a keyValue, create it if it is not found.
	// Set bCreate to true to create the key if it doesn't already exist (which ensures a valid pointer will be returned)
	KeyValues *FindKey( const char *keyName, bool bCreate );
	const KeyValues *FindKey( const char *keyName ) const;
	KeyValues *FindKey( HKeySymbol keySymbol ) const;
	KeyValues *FindKeyAndParent( const char *keyName, KeyValues **pParent, bool );
	bool FindAndDeleteSubKey( const char *keyName );

	KeyValues *CreateNewKey();		// creates a new key, with an autogenerated name.  name is guaranteed to be an integer, of value 1 higher than the highest other integer key name
	KeyValues *CreatePeerKey( const char *keyName );

	KeyValues *AddKey( const char *keyName );
	void AddSubKey( KeyValues *pSubkey );	// Adds a subkey. Make sure the subkey isn't a child of some other keyvalues
	void AddSubkeyUsingKnownLastChild( KeyValues *pSubkey, KeyValues *pChild );

	KeyValues *CreateKeyUsingKnownLastChild( const char *keyName, KeyValues *pChild );

	void RemoveSubKey( KeyValues *subKey, bool, bool );	// removes a subkey from the list, DOES NOT DELETE IT
	void RemoveOptionalSubKey( KeyValues *subKey );
	void InsertSubKey( int nIndex, KeyValues *pSubKey ); // Inserts the given sub-key before the Nth child location
	bool ContainsSubKey( KeyValues *pSubKey ); // Returns true if this key values contains the specified sub key, false otherwise.
	void SwapSubKey( KeyValues *pExistingSubKey, KeyValues *pNewSubKey );	// Swaps an existing subkey for a new one, DOES NOT DELETE THE OLD ONE but takes ownership of the new one
	void ElideSubKey( KeyValues *pSubKey );	// Removes a subkey but inserts all of its children in its place, in-order (flattens a tree, like firing a manager!)

	// Key iteration.
	//
	// NOTE: GetFirstSubKey/GetNextKey will iterate keys AND values. Use the functions 
	// below if you want to iterate over just the keys or just the values.
	//
	KeyValues *GetFirstSubKey() const;	// returns the first subkey in the list
	KeyValues *FindLastSubKey() const;
	KeyValues *GetNextKey() const;		// returns the next subkey
	void SetNextKey( KeyValues *pDat );

	//
	// These functions can be used to treat it like a true key/values tree instead of 
	// confusing values with keys.
	//
	// So if you wanted to iterate all subkeys, then all values, it would look like this:
	//     for ( KeyValues *pKey = pRoot->GetFirstTrueSubKey(); pKey; pKey = pKey->GetNextTrueSubKey() )
	//     {
	//		   Msg( "Key name: %s\n", pKey->GetName() );
	//     }
	//     for ( KeyValues *pValue = pRoot->GetFirstValue(); pKey; pKey = pKey->GetNextValue() )
	//     {
	//         Msg( "Int value: %d\n", pValue->GetInt() );  // Assuming pValue->GetDataType() == TYPE_INT...
	//     }
	KeyValues *GetFirstTrueSubKey() const;
	KeyValues *GetNextTrueSubKey() const;

	KeyValues *GetFirstValue() const;	// When you get a value back, you can use GetX and pass in NULL to get the value.
	KeyValues *GetNextValue() const;


	// Data access
	int GetInt( const char *keyName = NULL, int defaultValue = 0 ) const;
	uint64 GetUint64( const char *keyName = NULL, uint64 defaultValue = 0 ) const;
	float GetFloat( const char *keyName = NULL, float defaultValue = 0.0f ) const;
	const char *GetString( const char *keyName, const char *defaultValue = "", char *pszOut = NULL, size_t maxlen = 0 );
	const wchar_t *GetWString( const char *keyName = NULL, const wchar_t *defaultValue = L"", wchar_t *pszOut = NULL, size_t maxlen = 0 );
	void *GetPtr( const char *keyName = NULL, void *defaultValue = (void *)0 ) const;
	Color GetColor( const char *keyName = NULL, const Color &defaultColor = Color( 0, 0, 0, 0 ) ) const;
	bool GetBool( const char *keyName = NULL, bool defaultValue = false ) const { return GetInt( keyName, defaultValue ? 1 : 0 ) ? true : false; }
	bool IsEmpty( const char *keyName = NULL ) const;

	// Data access
	int GetInt( HKeySymbol keySymbol, int defaultValue = 0 ) const;
	uint64 GetUint64( HKeySymbol keySymbol, uint64 defaultValue = 0 ) const;
	float GetFloat( HKeySymbol keySymbol, float defaultValue = 0.0f ) const;
	const char *GetString( HKeySymbol keySymbol, const char *defaultValue = "", char *pszOut = NULL, size_t maxlen = 0 );
	const wchar_t *GetWString( HKeySymbol keySymbol, const wchar_t *defaultValue = L"", wchar_t *pszOut = NULL, size_t maxlen = 0 );
	void *GetPtr( HKeySymbol keySymbol, void *defaultValue = (void *)0 ) const;
	Color GetColor( HKeySymbol keySymbol, const Color &defaultColor = Color( 0, 0, 0, 0 ) ) const;
	bool GetBool( HKeySymbol keySymbol, bool defaultValue = false ) const { return GetInt( keySymbol, defaultValue ? 1 : 0 ) ? true : false; }
	bool IsEmpty( HKeySymbol keySymbol ) const;

	// Key writing
	void SetWString( const char *keyName, const wchar_t *value );
	void SetString( const char *keyName, const char *value );
	void SetInt( const char *keyName, int value );
	void SetUint64( const char *keyName, uint64 value );
	void SetFloat( const char *keyName, float value );
	void SetPtr( const char *keyName, void *value );
	void SetColor( const char *keyName, Color value );
	void SetBool( const char *keyName, bool value ) { SetInt( keyName, value ? 1 : 0 ); }

	// Adds key value pair
	void AddString( const char *keyName, const char *value );
	void AddInt( const char *keyName, int value );
	void AddUint64( const char *keyName, uint64 value );
	void AddFloat( const char *keyName, float value );
	void AddPtr( const char *keyName, void *value );

	// Memory allocation (optimized)
	void *operator new(size_t iAllocSize);
	void *operator new(size_t iAllocSize, int nBlockUse, const char *pFileName, int nLine);
	void operator delete(void *pMem);
	void operator delete(void *pMem, int nBlockUse, const char *pFileName, int nLine);

	KeyValues &operator=( KeyValues &src );

	void RecursiveSaveToFile( CUtlBuffer &buf, int indentLevel, bool bSortKeys = false, bool bAllowEmptyString = false );
	void RecursiveSaveToLocalizationFile( IFileSystem *filesystem, void *buf, int indentLevel, bool bAllowEmptyString = false );

	bool WriteAsBinary( CUtlBuffer &buffer );
	bool WriteAsBinaryFiltered( CUtlBuffer &buffer );
	bool ReadAsBinary( CUtlBuffer &buffer );
	bool ReadAsBinaryFiltered( CUtlBuffer &buffer );
	//CTemporaryKeyValues *ReadTemporaryAsBinary( bool, CUtlBuffer &buffer );

	// Allocate & create a new copy of the keys
	KeyValues *MakeCopy( void ) const;

	// Make a new copy of all subkeys, add them all to the passed-in keyvalues
	void CopySubkeys( KeyValues *pParent ) const;

	// Clear out all subkeys, and the current value
	void Clear( void );

	bool IsEqual( KeyValues *pOther );

	int Count( void ) const;

	KeyValues *Element( int nIndex ) const;

	CKeyValues_Data::types_t GetDataType( const char *keyName = NULL );

	// unpack a key values list into a structure
	void UnpackIntoStructure( struct KeyValuesUnpackStructure const *pUnpackTable, void *pDest );

	// Process conditional keys for widescreen support.
	bool ProcessResolutionKeys( const char *pResString );

	// Dump keyvalues recursively into a dump context
	//bool Dump( IKeyValuesDumpContext *pDump, int nIndentLevel = 0 );

	// Merge operations describing how two keyvalues can be combined
	enum MergeKeyValuesOp_t
	{
		MERGE_KV_ALL,
		MERGE_KV_UPDATE,	// update values are copied into storage, adding new keys to storage or updating existing ones
		MERGE_KV_DELETE,	// update values specify keys that get deleted from storage
		MERGE_KV_BORROW,	// update values only update existing keys in storage, keys in update that do not exist in storage are discarded
		MERGE_KV_ADD_ONLY
	};

	void MergeFrom( const KeyValues *kvMerge, MergeKeyValuesOp_t eOp = MERGE_KV_ALL );
//	CTemporaryKeyValues *MergeFromTemporary( const KeyValues *kvMerge, MergeKeyValuesOp_t eOp = MERGE_KV_ALL ) const;

	// Assign keyvalues from a string
	static KeyValues *FromString( char const *szName, char const *szStringVal, char const **ppEndOfParse = NULL );


private:
	KeyValues( KeyValues & ); // prevent copy constructor being used
};
#pragma pack(pop)

typedef KeyValues::AutoDelete KeyValuesAD;

enum KeyValuesUnpackDestinationTypes_t
{
	UNPACK_TYPE_FLOAT,										// dest is a float
	UNPACK_TYPE_VECTOR,										// dest is a Vector
	UNPACK_TYPE_VECTOR_COLOR,								// dest is a vector, src is a color
	UNPACK_TYPE_STRING,										// dest is a char *. unpacker will allocate.
	UNPACK_TYPE_INT,										// dest is an int
	UNPACK_TYPE_FOUR_FLOATS,	 // dest is an array of 4 floats. source is a string like "1 2 3 4"
	UNPACK_TYPE_TWO_FLOATS,		 // dest is an array of 2 floats. source is a string like "1 2"
};

#define SOURCESDK_CS2_UNPACK_FIXED( kname, kdefault, dtype, ofs ) { kname, kdefault, dtype, ofs, 0 }
#define SOURCESDK_CS2_UNPACK_VARIABLE( kname, kdefault, dtype, ofs, sz ) { kname, kdefault, dtype, ofs, sz }
#define SOURCESDK_CS2_UNPACK_END_MARKER { NULL, NULL, UNPACK_TYPE_FLOAT, 0 }

struct KeyValuesUnpackStructure
{
	char const *m_pKeyName;									// null to terminate tbl
	char const *m_pKeyDefault;								// null ok
	KeyValuesUnpackDestinationTypes_t m_eDataType;			// UNPACK_TYPE_INT, ..
	size_t m_nFieldOffset;									// use offsetof to set
	size_t m_nFieldSize;									// for strings or other variable length
};

//-----------------------------------------------------------------------------
// inline methods
//-----------------------------------------------------------------------------
inline int KeyValues::GetInt( HKeySymbol keySymbol, int defaultValue ) const
{
	KeyValues *dat = FindKey( keySymbol );
	return dat ? dat->GetInt( (const char *)NULL, defaultValue ) : defaultValue;
}

inline uint64 KeyValues::GetUint64( HKeySymbol keySymbol, uint64 defaultValue ) const
{
	KeyValues *dat = FindKey( keySymbol );
	return dat ? dat->GetUint64( (const char *)NULL, defaultValue ) : defaultValue;
}

inline float KeyValues::GetFloat( HKeySymbol keySymbol, float defaultValue ) const
{
	KeyValues *dat = FindKey( keySymbol );
	return dat ? dat->GetFloat( (const char *)NULL, defaultValue ) : defaultValue;
}

inline const char *KeyValues::GetString( HKeySymbol keySymbol, const char *defaultValue, char *pszOut, size_t maxlen )
{
	KeyValues *dat = FindKey( keySymbol );
	return dat ? dat->GetString( (const char *)NULL, defaultValue, pszOut, maxlen ) : defaultValue;
}

inline const wchar_t *KeyValues::GetWString( HKeySymbol keySymbol, const wchar_t *defaultValue, wchar_t *pszOut, size_t maxlen )
{
	KeyValues *dat = FindKey( keySymbol );
	return dat ? dat->GetWString( (const char *)NULL, defaultValue, pszOut, maxlen ) : defaultValue;
}

inline void *KeyValues::GetPtr( HKeySymbol keySymbol, void *defaultValue ) const
{
	KeyValues *dat = FindKey( keySymbol );
	return dat ? dat->GetPtr( (const char *)NULL, defaultValue ) : defaultValue;
}

inline Color KeyValues::GetColor( HKeySymbol keySymbol, const Color &defaultColor ) const
{
	KeyValues *dat = FindKey( keySymbol );
	return dat ? dat->GetColor( (const char *)NULL, defaultColor ) : defaultColor;
}

inline bool KeyValues::IsEmpty( HKeySymbol keySymbol ) const
{
	KeyValues *dat = FindKey( keySymbol );
	return dat ? dat->IsEmpty() : true;
}

/*
//
// KeyValuesDumpContext and generic implementations
//

class IKeyValuesDumpContext
{
public:
	virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel ) = 0;
	virtual bool KvWriteValue( KeyValues *pValue, int nIndentLevel ) = 0;
	virtual bool KvEndKey( KeyValues *pKey, int nIndentLevel ) = 0;
};

class IKeyValuesDumpContextAsText : public IKeyValuesDumpContext
{
public:
	virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel );
	virtual bool KvWriteValue( KeyValues *pValue, int nIndentLevel );
	virtual bool KvEndKey( KeyValues *pKey, int nIndentLevel );

public:
	virtual bool KvWriteIndent( int nIndentLevel );
	virtual bool KvWriteText( char const *szText ) = 0;
};

class CKeyValuesDumpContextAsDevMsg : public IKeyValuesDumpContextAsText
{
public:
	// Overrides developer level to dump in DevMsg, zero to dump as Msg
	CKeyValuesDumpContextAsDevMsg( int nDeveloperLevel = 1 ) : m_nDeveloperLevel( nDeveloperLevel ) {}

public:
	virtual bool KvBeginKey( KeyValues *pKey, int nIndentLevel );
	virtual bool KvWriteText( char const *szText );

protected:
	int m_nDeveloperLevel;
};

inline bool KeyValuesDumpAsDevMsg( KeyValues *pKeyValues, int nIndentLevel = 0, int nDeveloperLevel = 1 )
{
	CKeyValuesDumpContextAsDevMsg ctx( nDeveloperLevel );
	return pKeyValues->Dump( &ctx, nIndentLevel );
}*/

} // namespace CS2 {
} // namespace SOURCESDK {

#endif // SOURCESDK_CS2_KEYVALUES_H