text: //========= Copyright Valve Corporation, All rights reserved. ============//
  //
  // Purpose: 
  //
  //=============================================================================//
  #ifndef C_TF_GAMESTATS_H
  #define C_TF_GAMESTATS_H
  #ifdef _WIN32
  #pragma once
  #endif
  
  #include "gamestats.h"
  #include "tf_gamestats_shared.h"
  #include "GameEventListener.h"
  #include "c_tf_player.h"
  #include "econ_store.h"
  #include "store/store_panel.h"
  
  class CTFPlayer;
  
  struct TF_Gamestats_ClientSession_t
  {
  public:
  
  	TF_Gamestats_ClientSession_t();
  
  private:
  	TF_Gamestats_ClientSession_t( const TF_Gamestats_ClientSession_t &stats ) {}
  
  public:
  	void Reset();
  
  	struct SessionSummary_t
  	{
  		int iClassesPlayed;
  		int iMapsPlayed;
  		int iRoundsPlayed;
  		int iFavoriteClass;
  		int iFavoriteWeapon;
  		char szFavoriteMap[64];
  		int	iKills;
  		int iDeaths;
  		int iSuicides;
  		int iAssists;
  		int	iBuildingsBuilt;
  		int iBuildingsUpgraded;
  		int	iBuildingsDestroyed;
  		int	iHeadshots;
  		int	iDominations;
  		int	iRevenges;
  		int	iInvulns;
  		int	iTeleports;
  		int	iDamageDone;
  		int	iHealingDone;
  		int	iCrits;
  		int	iBackstabs;
  		int iAchievementsEarned;
  	};
  
  	SessionSummary_t			m_Summary;
  
  	RTime32						m_SessionStart;
  	RTime32						m_FirstConnect;
  	int							m_iMapsPlayed;
  	int							m_iRoundsPlayed;
  	CBitVecT< CFixedBitVecBase<32> >	m_ClassesPlayed;
  };
  
  struct TF_Gamestats_WeaponInfo_t
  {
  	TF_Gamestats_WeaponInfo_t();
  
  	int weaponID;
  	int critsFired;
  	int shotsFired;
  	int shotsHit;
  	int shotsMissed;
  	int avgDamage;
  	int totalDamage;
  	int critHits;
  	float lastUpdateTime;
  };
  
  struct TF_Gamestats_AchievementEvent_t
  {
  	TF_Gamestats_AchievementEvent_t( int in_achievementNum, const char* in_achievementID );
  
  	int		eventTime;
  	int		achievementNum;
  	const char* achievementID;
  };
  
  // Item event baseclass.
  class TF_Gamestats_ItemEvent
  {
  public:
  	TF_Gamestats_ItemEvent( int in_eventNum, CEconItemView* in_item );
  
  	int		eventNum;
  	int		eventTime;
  	const char* eventID;
  
  	item_definition_index_t itemDefIndex;
  	itemid_t itemID;
  	const char* itemName;
  	char itemNameBuf[512];
  	bool bUseNameBuf;
  
  	const char* GetItemName()
  	{
  		if ( bUseNameBuf )
  			return itemNameBuf;
  		else
  			return itemName;
  	}
  };
  
  // Mann Co Catalog Usage Tracking
  class TF_Gamestats_CatalogEvent : public TF_Gamestats_ItemEvent
  {
  public:
  	TF_Gamestats_CatalogEvent( int in_eventNum, CEconItemView* in_item, const char* in_filter );
  
  	const char* catalogFilter;
  };
  
  // Crafting System Usage Tracking
  class TF_Gamestats_CraftingEvent : public TF_Gamestats_ItemEvent
  {
  public:
  	TF_Gamestats_CraftingEvent( int in_eventNum, CEconItemView* in_item, int in_numAttempts, int in_recipe );
  
  	int		numAttempts;
  	int		recipeFound;
  };
  
  // Store Usage Tracking
  class TF_Gamestats_StoreEvent : public TF_Gamestats_ItemEvent
  {
  public:
  	TF_Gamestats_StoreEvent( int in_eventNum, CEconItemView* in_item, 
  		const char* in_panelName, int in_classId, const cart_item_t* in_cartItem,
  		int in_checkoutAttempts, const char* in_storeError, int in_totalPrice, int in_currencyCode );
  
  	int classId;
  	int cartQuantity;
  	int cartItemCost;
  	int currencyCode;
  	int checkoutAttempt;
  	const char* storeError;
  	const char* panelName;
  };
  
  // General client-subjective item transaction tracking.
  class TF_Gamestats_ItemTransactionEvent : public TF_Gamestats_ItemEvent
  {
  public:
  	TF_Gamestats_ItemTransactionEvent( int in_eventNum, CEconItemView* in_item, const char* in_reason, int in_quality );
  
  	const char* reason;
  	int itemQuality;
  };
  
  // Trade Usage Tracking
  class TF_Gamestats_TradeEvent : public TF_Gamestats_ItemEvent
  {
  public:
  	TF_Gamestats_TradeEvent( int eventID, CEconItemView* item, bool localPlayerIsPartyA,
  		uint64 steamIDPartyA, uint64 steamIDPartyB, int iTradeRequests, int iTradeAttempts );
  	TF_Gamestats_TradeEvent( int eventID, uint64 steamIDRequested, int iTradeRequests, int iTradeAttempts );
  	TF_Gamestats_TradeEvent( int eventID, int iTradeRequests, const char* reason, int iTradeAttempts );
  
  	bool localPlayerPartyMatters;
  	bool localPlayerIsPartyA;
  	uint64 steamIDPartyA;
  	uint64 steamIDPartyB;
  
  	uint64 steamIDRequested;
  	int tradeRequests;
  	int tradeAttempts;
  
  	const char* reason;
  };
  
  // Matchmaking stats
  struct TF_Gamestats_QuickPlay_t
  {
  	// Status code for the search as a whole
  	enum eResult
  	{
  		k_Result_InternalError = -1,
  		k_Result_UserCancel = 10,
  		k_Result_NoServersFound = 20,
  		k_Result_NoServersMetCrtieria = 30,
  		//k_Result_NeverHeardBackFromGC = 40,
  		//k_Result_ReceivedZeroGCScores = 50,
  		k_Result_FinalPingFailed = 60,
  		k_Result_TriedToConnect = 100,
  	};
  
  	// Status codes for the servers
  	enum eServerStatus
  	{
  		k_Server_Invalid = -1, // we have a bug if this gets reported
  		k_Server_Ineligible = 10,
  		k_Server_Eligible = 20,
  		k_Server_RequestedScore = 30,
  		k_Server_Scored = 40,
  		k_Server_Pinged = 50,
  		k_Server_PingTimedOut = 60,
  		k_Server_PingIneligible = 70,
  		k_Server_Connected = 100,
  	};
  
  	TF_Gamestats_QuickPlay_t()
  	{
  		m_fUserHoursPlayed = -1.0f;
  		m_sUserGameMode;
  		m_fSearchTime = -1.0;
  		m_eResultCode = k_Result_UserCancel;
  		m_iExperimentGroup = 0;
  	}
  
  	float m_fUserHoursPlayed;
  	CUtlString m_sUserGameMode;
  	float m_fSearchTime;
  	eResult m_eResultCode;
  	int m_iExperimentGroup; // TF2ScoringNumbers_t::ExperimentGroup_t
  
  	struct Server_t
  	{
  		uint32 m_ip;
  		uint16 m_port;
  		bool m_bRegistered;
  		bool m_bValve;
  		bool m_bSecure;
  		bool m_bMapIsNewUserFriendly;
  		bool m_bMapIsQuickPlayOK;
  		int m_nPlayers;
  		int m_nMaxPlayers;
  		CUtlString m_sMapName;
  		CUtlString m_sTags;
  		int m_iPing;
  		float m_fScoreClient;
  		float m_fScoreServer;
  		float m_fScoreGC;
  		eServerStatus m_eStatus;
  	};
  	CUtlVector<Server_t> m_vecServers;
  };
  
  //=============================================================================
  //
  // TF Game Stats Class
  //
  
  class C_CTFGameStats : public CBaseGameStats, public CGameEventListener, public CAutoGameSystem
  {
  public:
  
  	// Constructor/Destructor.
  	C_CTFGameStats( void );
  	~C_CTFGameStats( void );
  
  	virtual void Clear( void );
  
  	virtual bool UseOldFormat() { return false; }
  	virtual bool AddDataForSend( KeyValues *pKV, StatSendType_t sendType );
  
  	virtual bool Init();
  	virtual void Shutdown();
  
  	void ResetRoundStats();
  
  	void ClientDisconnect( int iReason );
  
  	// Events.
  	virtual void Event_LevelInit( void );
  	virtual void Event_LevelShutdown( float flElapsed );
  	virtual void Event_RoundActive();
  	virtual void Event_RoundEnd( int winningTeam, float roundTime, int fullRound );
  	virtual void Event_PlayerChangeClass( int userid, int classid );
  	virtual void Event_AchievementProgress( int achievementID, const char* achievementName );
  	virtual void Event_PlayerHurt( IGameEvent* event /*player_hurt*/ );
  	virtual void Event_PlayerFiredWeapon( C_TFPlayer *pPlayer, bool bCritical );
  	virtual void Event_Catalog( int eventID, const char* filter=NULL, CEconItemView* item=NULL );
  	virtual void Event_Crafting( int eventID, CEconItemView* item=NULL, int numAttempts=0, int recipeFound=0 );
  	virtual void Event_Store( int eventID, CEconItemView* item=NULL, const char* panelName=NULL, 
  		int classId=0, const cart_item_t* in_cartItem=NULL, int in_checkoutAttempts=0, const char* storeError=NULL, int in_totalPrice=0, int in_currencyCode=0 );
  	virtual void Event_ItemTransaction( int eventID, CEconItemView* item, const char* pszReason=NULL, int iQuality=0 );
  	virtual void Event_Trading( int eventID, CEconItemView* item=NULL, bool localPlayerIsPartyA=false,
  		uint64 steamIDPartyA=0, uint64 steamIDPartyB=0, int iTradeRequests=0, int iTradeAttempts=0 );
  	virtual void Event_Trading( int eventID, uint64 steamIDRequested=0, int iTradeRequests=0, int iTradeAttempts=0 );
  	virtual void Event_Trading( int eventID, int iTradeRequests=0, const char* reason=NULL, int iTradeAttempts=0 );
  	virtual void Event_Trading( TF_Gamestats_TradeEvent& event );
  
  	virtual void FireGameEvent( IGameEvent * event );
  
  	void SW_GameStats_WriteClientSessionSummary();
  	void SW_GameStats_WriteClientWeapons();
  	void SW_GameStats_WriteClientRound( int winningTeam, int fullRound, int endReason );
  	void SW_GameStats_WriteClientMap();
  
  	void SetExperimentValue( uint64 experimentValue ) { m_ulExperimentValue = experimentValue; }
  
  	static void ImmediateWriteInterfaceEvent( const char *pszEventType, const char *pszEventDesc );
  
  	/*
  	void SW_GameStats_WriteClientAchievements();
  	void SW_GameStats_WriteClientCatalogEvents();
  	void SW_GameStats_WriteClientCraftingEvents();
  	void SW_GameStats_WriteClientStoreEvents();
  	void SW_GameStats_WriteClientItemTransactionEvents();
  	void SW_GameStats_WriteClientTradeEvents();
  	*/
  
  	void QuickplayResults( const TF_Gamestats_QuickPlay_t &info );
  
  private:
  	char	m_szCountryCode[64];
  	char	m_szAudioLanguage[64];
  	char	m_szTextLanguage[64];
  
  	TF_Gamestats_ClientSession_t	m_currentSession;
  	TF_Gamestats_RoundStats_t		m_currentRound;
  	TF_Gamestats_LevelStats_t		m_currentMap;
  	CUtlVector<TF_Gamestats_AchievementEvent_t>	m_vecAchievementEvents;
  	CUtlMap<int, TF_Gamestats_WeaponInfo_t>	m_mapWeaponInfo;
  
  	CUtlVector<TF_Gamestats_CatalogEvent> m_vecCatalogEvents;
  	CUtlVector<TF_Gamestats_CraftingEvent> m_vecCraftingEvents;
  	CUtlVector<TF_Gamestats_StoreEvent> m_vecStoreEvents;
  	CUtlVector<TF_Gamestats_ItemTransactionEvent> m_vecItemTransactionEvents;
  	CUtlVector<TF_Gamestats_TradeEvent> m_vecTradeEvents;
  
  	uint64 m_ulExperimentValue;
  
  	bool m_bRoundActive;
  	bool m_bIsDisconnecting;
  };
  
  extern C_CTFGameStats C_CTF_GameStats;
  
  #endif // C_TF_GAMESTATS_H
  