//==========================  Open Steamworks  ================================
//
// This file is part of the Open Steamworks project. All individuals associated
// with this project do not claim ownership of the contents
//
// The code, comments, and all related files, projects, resources,
// redistributables included with this project are Copyright Valve Corporation.
// Additionally, Valve, the Valve logo, Half-Life, the Half-Life logo, the
// Lambda logo, Steam, the Steam logo, Team Fortress, the Team Fortress logo,
// Opposing Force, Day of Defeat, the Day of Defeat logo, Counter-Strike, the
// Counter-Strike logo, Source, the Source logo, and Counter-Strike Condition
// Zero are trademarks and or registered trademarks of Valve Corporation.
// All other trademarks are property of their respective owners.
//
//=============================================================================

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

#pragma pack( push, 1 )

//-----------------------------------------------------------------------------
// Purpose: encapsulates an appID/modID pair
//-----------------------------------------------------------------------------
class CGameID
{
public:

	CGameID()
	{
		m_gameID.m_nType = k_EGameIDTypeApp;
		m_gameID.m_nAppID = k_uAppIdInvalid;
		m_gameID.m_nModID = 0;
	}

	explicit CGameID(uint64 ulGameID)
	{
		m_ulGameID = ulGameID;
	}

	explicit CGameID(int32 nAppID)
	{
		m_ulGameID = 0;
		m_gameID.m_nAppID = nAppID;
	}

	explicit CGameID(uint32 nAppID)
	{
		m_ulGameID = 0;
		m_gameID.m_nAppID = nAppID;
	}

	CGameID(uint32 nAppID, uint32 nModID)
	{
		m_ulGameID = 0;
		m_gameID.m_nAppID = nAppID;
		m_gameID.m_nModID = nModID;
		m_gameID.m_nType = k_EGameIDTypeGameMod;
	}

	// Hidden functions used only by Steam
	explicit CGameID(const char *pchGameID);
	const char *Render() const;					// render this Game ID to string
	static const char *Render(uint64 ulGameID);		// static method to render a uint64 representation of a Game ID to a string

	// must include checksum_crc.h first to get this functionality
#if defined( CHECKSUM_CRC_H )
	CGameID(uint32 nAppID, const char *pchModPath)
	{
		m_ulGameID = 0;
		m_gameID.m_nAppID = nAppID;
		m_gameID.m_nType = k_EGameIDTypeGameMod;

		char rgchModDir[MAX_PATH];
		Q_FileBase(pchModPath, rgchModDir, sizeof(rgchModDir));
		CRC32_t crc32;
		CRC32_Init(&crc32);
		CRC32_ProcessBuffer(&crc32, rgchModDir, Q_strlen(rgchModDir));
		CRC32_Final(&crc32);

		// set the high-bit on the mod-id
		// reduces crc32 to 31bits, but lets us use the modID as a guaranteed unique
		// replacement for appID's
		m_gameID.m_nModID = crc32 | (0x80000000);
	}

	CGameID(const char *pchExePath, const char *pchAppName)
	{
		m_ulGameID = 0;
		m_gameID.m_nAppID = k_uAppIdInvalid;
		m_gameID.m_nType = k_EGameIDTypeShortcut;

		CRC32_t crc32;
		CRC32_Init(&crc32);
		CRC32_ProcessBuffer(&crc32, pchExePath, Q_strlen(pchExePath));
		CRC32_ProcessBuffer(&crc32, pchAppName, Q_strlen(pchAppName));
		CRC32_Final(&crc32);

		// set the high-bit on the mod-id
		// reduces crc32 to 31bits, but lets us use the modID as a guaranteed unique
		// replacement for appID's
		m_gameID.m_nModID = crc32 | (0x80000000);
	}

#if defined( VSTFILEID_H )

	CGameID(VstFileID vstFileID)
	{
		m_ulGameID = 0;
		m_gameID.m_nAppID = k_uAppIdInvalid;
		m_gameID.m_nType = k_EGameIDTypeP2P;

		CRC32_t crc32;
		CRC32_Init(&crc32);
		const char *pchFileId = vstFileID.Render();
		CRC32_ProcessBuffer(&crc32, pchFileId, Q_strlen(pchFileId));
		CRC32_Final(&crc32);

		// set the high-bit on the mod-id
		// reduces crc32 to 31bits, but lets us use the modID as a guaranteed unique
		// replacement for appID's
		m_gameID.m_nModID = crc32 | (0x80000000);
	}

#endif /* VSTFILEID_H */

#endif /* CHECKSUM_CRC_H */

	uint64 ToUint64() const
	{
		return m_ulGameID;
	}

	uint64 *GetUint64Ptr()
	{
		return &m_ulGameID;
	}

	bool IsMod() const
	{
		return (m_gameID.m_nType == k_EGameIDTypeGameMod);
	}

	bool IsShortcut() const
	{
		return (m_gameID.m_nType == k_EGameIDTypeShortcut);
	}

	bool IsP2PFile() const
	{
		return (m_gameID.m_nType == k_EGameIDTypeP2P);
	}

	bool IsSteamApp() const
	{
		return (m_gameID.m_nType == k_EGameIDTypeApp);
	}

	uint32 ModID() const
	{
		return m_gameID.m_nModID;
	}

	uint32 AppID() const
	{
		return m_gameID.m_nAppID;
	}

	bool operator == (const CGameID &rhs) const
	{
		return m_ulGameID == rhs.m_ulGameID;
	}

	bool operator != (const CGameID &rhs) const
	{
		return !(*this == rhs);
	}

	bool operator < (const CGameID &rhs) const
	{
		return (m_ulGameID < rhs.m_ulGameID);
	}

	bool IsValid() const
	{
		// each type has it's own invalid fixed point:
		switch(m_gameID.m_nType)
		{
		case k_EGameIDTypeApp:
			return m_gameID.m_nAppID != k_uAppIdInvalid;
			break;
		case k_EGameIDTypeGameMod:
			return m_gameID.m_nAppID != k_uAppIdInvalid && m_gameID.m_nModID & 0x80000000;
			break;
		case k_EGameIDTypeShortcut:
			return (m_gameID.m_nModID & 0x80000000) != 0;
			break;
		case k_EGameIDTypeP2P:
			return m_gameID.m_nAppID == k_uAppIdInvalid && m_gameID.m_nModID & 0x80000000;
			break;
		default:
#if defined(Assert)
			Assert(false);
#endif
			return false;
		}
	}

	void Reset()
	{
		m_ulGameID = 0;
	}

private:

	enum EGameIDType
	{
		k_EGameIDTypeApp = 0,
		k_EGameIDTypeGameMod = 1,
		k_EGameIDTypeShortcut = 2,
		k_EGameIDTypeP2P = 3,
	};

	struct GameID_t
	{
#ifdef VALVE_BIG_ENDIAN
		unsigned int m_nModID : 32;
		unsigned int m_nType : 8;
		unsigned int m_nAppID : 24;
#else
		unsigned int m_nAppID : 24;
		unsigned int m_nType : 8;
		unsigned int m_nModID : 32;
#endif
	};

	union
	{
		uint64 m_ulGameID;
		GameID_t m_gameID;
	};
};

#pragma pack( pop )

#endif // CGAMEID_H
