//-----------------------------------------------------------------------------
//
// Xbox Matchmaking Definitions for Title: 25 To Life [0x45530018]
// Generated by MatchSim
//
//-----------------------------------------------------------------------------
#pragma once


#include <xtl.h>
#include <xonline.h>
#include <assert.h>




//-----------------------------------------------------------------------------
// Constants
//-----------------------------------------------------------------------------

//
// Attribute IDs                          ID num   Data Type
//                                        ------   ----------------------------
const DWORD XATTRIB_CONSOLE_REGION       = 0x000A | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_GAME_VERSION         = 0x000B | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_ADDITIONAL_CONTENT    = 0x000C | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_LEVEL_INDEX          = 0x000E | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_GAME_TYPE            = 0x000F | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_TIME_LIMIT           = 0x0010 | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_SCORE_LIMIT          = 0x0011 | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_TAG_LIMIT            = 0x0012 | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_BEST_OF_SERIES       = 0x0013 | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_PLAYERS_RESPAWN      = 0x0014 | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_FRIENDLY_FIRE        = 0x0015 | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_APPREHENSION         = 0x0016 | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_SELF_DAMAGE          = 0x0018 | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_ALTERNATING_TEAMS    = 0x0019 | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_MAX_PLAYERS          = 0x001A | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_HOST_TITLE           = 0x001B | X_ATTRIBUTE_DATATYPE_STRING;
const DWORD XATTRIB_IS_RANKED            = 0x001C | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_TOTAL_CONNECTED_PLAYERS    = 0x001D | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_LOAD_OUT_LIMIT       = 0x001E | X_ATTRIBUTE_DATATYPE_INTEGER;
const DWORD XATTRIB_VOICE_COUNT          = 0x001F | X_ATTRIBUTE_DATATYPE_INTEGER;


//
// Attribute Maximum Lengths
// (for strings, this doesn't include the terminating NULL)
//
const DWORD XATTRIB_HOST_TITLE_MAX_LEN = 16; // HostTitle attribute


// Specify X_MATCH_NULL_INTEGER for optional integer query arguments
const ULONGLONG X_MATCH_NULL_INTEGER  = 0x7FFFFFFFFFFFFFFFui64;

// Maximum number of sessions returned by CommonMatch query
const DWORD MAX_COMMON_MATCH_RESULTS = 25;

// Maximum number of sessions returned by SpecificMatch query
const DWORD MAX_SPECIFIC_MATCH_RESULTS = 1;

// Number of QoS probes
const DWORD NUM_QOS_PROBES   =     8;

// Maximum bandwidth to consume for QoS probes
const DWORD QOS_BITS_PER_SEC = 64000;





//-----------------------------------------------------------------------------
// Types
//-----------------------------------------------------------------------------

// Helper class for getting/setting blob attributes
#ifndef _XDKTOOL_BLOB
#define _XDKTOOL_BLOB
class CBlob
{
public:
    CBlob() : m_wLength( 0 ), m_pvData( NULL ) {}
    CBlob( WORD wLength, const PVOID pvData ) : m_wLength( wLength), m_pvData( pvData) {}
    CBlob( const CBlob & b ) { *this = b; }
    CBlob & operator=( const CBlob & b ) 
    { m_wLength = b.Length; m_pvData = b.Data; return *this; }
    BOOL operator==( const CBlob & b ) const  
    { return m_wLength == b.Length && memcmp( m_pvData, b.Data, b.Length ) == 0; }
    BOOL IsNull() { return m_pvData == NULL; }
    __declspec( property( put = SetData, get=GetData ) ) const PVOID Data;
    const PVOID GetData() const { return m_pvData; }
    VOID SetData( const PVOID pvData ) { m_pvData = pvData; }
    __declspec( property( put = SetLength, get=GetLength ) ) WORD Length;
    WORD GetLength() const { return m_wLength; }
    VOID SetLength( WORD wLength ) { m_wLength = wLength; }
private:
    WORD m_wLength;
    PVOID m_pvData;
};

// A null blob is defined as having a NULL pointer
#define NULL_BLOB CBlob( 0, NULL )

// Macro for declaring "blob literals" (much like the _T() macro does for strings)
#define B( length, ptr ) CBlob( length, (const PVOID) ptr )
#endif

class CMatchSimSession
{
public:
    CMatchSimSession();
    ~CMatchSimSession();

    HRESULT Create();
    HRESULT Update();
    HRESULT Delete();
    HRESULT Process();

    VOID    Reset();

    DWORD PublicFilled;
    DWORD PublicOpen;
    DWORD PrivateFilled;
    DWORD PrivateOpen;
    XNKEY KeyExchangeKey;
    XNKID SessionID;

    BOOL IsUpdating() const { return m_State == STATE_UPDATING; }
    BOOL IsDeleting() const { return m_State == STATE_DELETING; }
    BOOL IsCreating() const { return m_State == STATE_CREATING; }
    BOOL Exists()     const { return m_State == STATE_ACTIVE || IsUpdating(); }

    // Attribute Accessors

    BOOL IsListening() const { return m_bListening; }
    __declspec( property( put = SetQosResponse, get = GetQosResponse ) ) CBlob QosResponse;
    CBlob GetQosResponse();
    VOID SetQosResponse( CBlob Value );
    VOID Listen( BOOL bEnable = TRUE, DWORD dwBitsPerSec = 0 );
    static const DWORD NO_WAIT = 1;

    __declspec( property( put = SetConsoleRegion, get=GetConsoleRegion ) ) ULONGLONG ConsoleRegion;
    ULONGLONG GetConsoleRegion();
    VOID SetConsoleRegion( ULONGLONG Value );

    __declspec( property( put = SetGameVersion, get=GetGameVersion ) ) ULONGLONG GameVersion;
    ULONGLONG GetGameVersion();
    VOID SetGameVersion( ULONGLONG Value );

    __declspec( property( put = SetAdditionalContent, get=GetAdditionalContent ) ) ULONGLONG AdditionalContent;
    ULONGLONG GetAdditionalContent();
    VOID SetAdditionalContent( ULONGLONG Value );

    __declspec( property( put = SetLevelIndex, get=GetLevelIndex ) ) ULONGLONG LevelIndex;
    ULONGLONG GetLevelIndex();
    VOID SetLevelIndex( ULONGLONG Value );

    __declspec( property( put = SetGameType, get=GetGameType ) ) ULONGLONG GameType;
    ULONGLONG GetGameType();
    VOID SetGameType( ULONGLONG Value );

    __declspec( property( put = SetTimeLimit, get=GetTimeLimit ) ) ULONGLONG TimeLimit;
    ULONGLONG GetTimeLimit();
    VOID SetTimeLimit( ULONGLONG Value );

    __declspec( property( put = SetScoreLimit, get=GetScoreLimit ) ) ULONGLONG ScoreLimit;
    ULONGLONG GetScoreLimit();
    VOID SetScoreLimit( ULONGLONG Value );

    __declspec( property( put = SetTagLimit, get=GetTagLimit ) ) ULONGLONG TagLimit;
    ULONGLONG GetTagLimit();
    VOID SetTagLimit( ULONGLONG Value );

    __declspec( property( put = SetBestOfSeries, get=GetBestOfSeries ) ) ULONGLONG BestOfSeries;
    ULONGLONG GetBestOfSeries();
    VOID SetBestOfSeries( ULONGLONG Value );

    __declspec( property( put = SetPlayersRespawn, get=GetPlayersRespawn ) ) ULONGLONG PlayersRespawn;
    ULONGLONG GetPlayersRespawn();
    VOID SetPlayersRespawn( ULONGLONG Value );

    __declspec( property( put = SetFriendlyFire, get=GetFriendlyFire ) ) ULONGLONG FriendlyFire;
    ULONGLONG GetFriendlyFire();
    VOID SetFriendlyFire( ULONGLONG Value );

    __declspec( property( put = SetApprehension, get=GetApprehension ) ) ULONGLONG Apprehension;
    ULONGLONG GetApprehension();
    VOID SetApprehension( ULONGLONG Value );

    __declspec( property( put = SetSelfDamage, get=GetSelfDamage ) ) ULONGLONG SelfDamage;
    ULONGLONG GetSelfDamage();
    VOID SetSelfDamage( ULONGLONG Value );

    __declspec( property( put = SetAlternatingTeams, get=GetAlternatingTeams ) ) ULONGLONG AlternatingTeams;
    ULONGLONG GetAlternatingTeams();
    VOID SetAlternatingTeams( ULONGLONG Value );

    __declspec( property( put = SetMaxPlayers, get=GetMaxPlayers ) ) ULONGLONG MaxPlayers;
    ULONGLONG GetMaxPlayers();
    VOID SetMaxPlayers( ULONGLONG Value );

    __declspec( property( put = SetHostTitle, get=GetHostTitle ) ) const WCHAR * HostTitle;
    const WCHAR * GetHostTitle();
    VOID SetHostTitle( const WCHAR * Value );

    __declspec( property( put = SetIsRanked, get=GetIsRanked ) ) ULONGLONG IsRanked;
    ULONGLONG GetIsRanked();
    VOID SetIsRanked( ULONGLONG Value );

    __declspec( property( put = SetTotalConnectedPlayers, get=GetTotalConnectedPlayers ) ) ULONGLONG TotalConnectedPlayers;
    ULONGLONG GetTotalConnectedPlayers();
    VOID SetTotalConnectedPlayers( ULONGLONG Value );

    __declspec( property( put = SetLoadOutLimit, get=GetLoadOutLimit ) ) ULONGLONG LoadOutLimit;
    ULONGLONG GetLoadOutLimit();
    VOID SetLoadOutLimit( ULONGLONG Value );

    __declspec( property( put = SetVoiceCount, get=GetVoiceCount ) ) ULONGLONG VoiceCount;
    ULONGLONG GetVoiceCount();
    VOID SetVoiceCount( ULONGLONG Value );

private:

    // The m_Attributes array is accessed using predefined constants:
    enum
    {
        CONSOLE_REGION_INDEX,
        GAME_VERSION_INDEX,
        ADDITIONAL_CONTENT_INDEX,
        LEVEL_INDEX_INDEX,
        GAME_TYPE_INDEX,
        TIME_LIMIT_INDEX,
        SCORE_LIMIT_INDEX,
        TAG_LIMIT_INDEX,
        BEST_OF_SERIES_INDEX,
        PLAYERS_RESPAWN_INDEX,
        FRIENDLY_FIRE_INDEX,
        APPREHENSION_INDEX,
        SELF_DAMAGE_INDEX,
        ALTERNATING_TEAMS_INDEX,
        MAX_PLAYERS_INDEX,
        HOST_TITLE_INDEX,
        IS_RANKED_INDEX,
        TOTAL_CONNECTED_PLAYERS_INDEX,
        LOAD_OUT_LIMIT_INDEX,
        VOICE_COUNT_INDEX,
        NUM_ATTRIBUTES
    };

    XONLINE_ATTRIBUTE m_Attributes[NUM_ATTRIBUTES];

    // Storage for the HostTitle string attribute
    WCHAR m_strHostTitle[XATTRIB_HOST_TITLE_MAX_LEN+1];


    // Qos listening
    struct QosQEntry
    {
        XNKID  SessionID;            // Session to unregister
        DWORD  dwStartTick;          // Time entry was added
        struct QosQEntry *pNext;     // Next item in the queue
    };
    class CMatchSimSessionQosQ
    {
    public:
        CMatchSimSessionQosQ();
        VOID Add( XNKID & SessionID, DWORD dwStartTick );
        VOID Remove( XNKID &SessionID );
        VOID Dequeue();
        const QosQEntry *Head() const { return m_pHead; }
        const QosQEntry *Tail() const { return m_pTail; }
    private:

        QosQEntry *m_pHead;
        QosQEntry *m_pTail;
    };

    CMatchSimSessionQosQ m_SessionQosQ;
    BOOL  m_bListening;              // Listening for Qos probes
    CBlob m_QosResponse;
    VOID  PurgeSessionQ( BOOL fRemoveAll = FALSE );
    VOID  PurgeSessionQHead();



    HRESULT ProcessStateCreateSession();
    HRESULT ProcessStateUpdateSession();
    HRESULT ProcessStateDeleteSession();
    HRESULT ProcessStateActiveSession();

    VOID    Close();
    VOID    SetupAttributes();

    XONLINETASK_HANDLE m_hSessionTask;

    enum STATE
    {
        STATE_IDLE,
        STATE_CREATING,
        STATE_UPDATING,
        STATE_DELETING,
        STATE_ACTIVE
    };

    STATE m_State;
    BOOL  m_bKeyRegistered;
    BOOL  m_bUpdate;

};




//
// CCommonMatchResult represents a single return result from the
// CommonMatch query
//
#pragma pack(push, 1)
class CCommonMatchResult
{
public:
    // The query return attributes must come first, and in the order
    // returned by the query
    ULONGLONG ConsoleRegion;
    ULONGLONG GameVersion;
    ULONGLONG AdditionalContent;
    ULONGLONG LevelIndex;
    ULONGLONG GameType;
    ULONGLONG TimeLimit;
    ULONGLONG ScoreLimit;
    ULONGLONG TagLimit;
    ULONGLONG BestOfSeries;
    ULONGLONG PlayersRespawn;
    ULONGLONG FriendlyFire;
    ULONGLONG Apprehension;
    ULONGLONG SelfDamage;
    ULONGLONG AlternatingTeams;
    ULONGLONG MaxPlayers;
    WCHAR     HostTitle[XATTRIB_HOST_TITLE_MAX_LEN+1];
    ULONGLONG IsRanked;
    ULONGLONG TotalConnectedPlayers;
    ULONGLONG LoadOutLimit;
    ULONGLONG VoiceCount;


    XNKID      SessionID;
    XNKEY      KeyExchangeKey;
    XNADDR     HostAddress;
    DWORD      PublicOpen;
    DWORD      PrivateOpen;
    DWORD      PublicFilled;
    DWORD      PrivateFilled;
    XNQOSINFO* pQosInfo;

};
#pragma pack(pop)



//  Collection of results for the CommonMatch query
class CCommonMatchQueryResults
{
public:
    CCommonMatchQueryResults() { m_dwSize = 0; }
    DWORD Size() { return m_dwSize; }
    CCommonMatchResult &operator[]( DWORD i ) { return v[i]; }
private:
    void Clear() { m_dwSize = 0; }
    void Remove( DWORD i )
    {
        assert( i < m_dwSize );
        if( i < m_dwSize )
        {
            m_dwSize--;
            memcpy( &v[i], &v[i+1], sizeof( v[0] ) * ( m_dwSize - i ) );
        }
    }
    void SetSize( DWORD dwSize ) { m_dwSize = dwSize; }
    friend class CCommonMatchQuery;
    CCommonMatchResult v[MAX_COMMON_MATCH_RESULTS];
    DWORD m_dwSize;
};



//
// Query object for CommonMatch query (id 0x1)
//
class CCommonMatchQuery
{
public:
    CCommonMatchQuery();
    ~CCommonMatchQuery();
    CCommonMatchQueryResults Results;

    HRESULT Process();
    void Cancel();
    void Clear();
    BOOL Done()      const { return m_State == STATE_DONE; }
    BOOL Succeeded() const { return SUCCEEDED( m_hrQuery ); }
    HRESULT Query(
                  ULONGLONG ConsoleRegion,
                  ULONGLONG GameVersion,
                  ULONGLONG AdditionalContent,
                  ULONGLONG LevelIndex, // Optional: X_MATCH_NULL_INTEGER to omit
                  ULONGLONG GameType, // Optional: X_MATCH_NULL_INTEGER to omit
                  ULONGLONG TimeLimit, // Optional: X_MATCH_NULL_INTEGER to omit
                  ULONGLONG ScoreLimit, // Optional: X_MATCH_NULL_INTEGER to omit
                  ULONGLONG TagLimit, // Optional: X_MATCH_NULL_INTEGER to omit
                  ULONGLONG BestOfSeries, // Optional: X_MATCH_NULL_INTEGER to omit
                  ULONGLONG PlayersRespawn, // Optional: X_MATCH_NULL_INTEGER to omit
                  ULONGLONG FriendlyFire, // Optional: X_MATCH_NULL_INTEGER to omit
                  ULONGLONG Apprehension, // Optional: X_MATCH_NULL_INTEGER to omit
                  ULONGLONG SelfDamage, // Optional: X_MATCH_NULL_INTEGER to omit
                  ULONGLONG AlternatingTeams, // Optional: X_MATCH_NULL_INTEGER to omit
                  ULONGLONG MaxPlayers, // Optional: X_MATCH_NULL_INTEGER to omit
                  ULONGLONG IsRanked, // Optional: X_MATCH_NULL_INTEGER to omit
                  ULONGLONG TotalConnectedPlayers, // Optional: X_MATCH_NULL_INTEGER to omit
                  ULONGLONG LoadOutLimit, // Optional: X_MATCH_NULL_INTEGER to omit
                  ULONGLONG VoiceCount // Optional: X_MATCH_NULL_INTEGER to omit
                 );
    BOOL IsRunning() const { return m_State == STATE_RUNNING || m_State == STATE_PROBING_CONNECTIVITY; }
    BOOL IsProbing() const { return m_State == STATE_PROBING_BANDWIDTH; }
    HRESULT Probe();
private:

    // Quality of Service
    const XNADDR *m_rgpXnAddr[ MAX_COMMON_MATCH_RESULTS ];
    const XNKID  *m_rgpXnKid [ MAX_COMMON_MATCH_RESULTS ];
    const XNKEY  *m_rgpXnKey [ MAX_COMMON_MATCH_RESULTS ];
    XNQOS  *m_pXnQos;
    enum STATE
    {
        STATE_IDLE,
        STATE_RUNNING,
        STATE_PROBING_CONNECTIVITY,
        STATE_PROBING_BANDWIDTH,
        STATE_DONE
    };

    STATE m_State;
    HRESULT m_hrQuery;
    XONLINETASK_HANDLE m_hSearchTask;
};




//
// CSpecificMatchResult represents a single return result from the
// SpecificMatch query
//
#pragma pack(push, 1)
class CSpecificMatchResult
{
public:
    // The query return attributes must come first, and in the order
    // returned by the query
    ULONGLONG ConsoleRegion;
    ULONGLONG GameVersion;
    ULONGLONG AdditionalContent;
    ULONGLONG LevelIndex;
    ULONGLONG GameType;
    ULONGLONG TimeLimit;
    ULONGLONG ScoreLimit;
    ULONGLONG TagLimit;
    ULONGLONG BestOfSeries;
    ULONGLONG PlayersRespawn;
    ULONGLONG FriendlyFire;
    ULONGLONG Apprehension;
    ULONGLONG SelfDamage;
    ULONGLONG AlternatingTeams;
    ULONGLONG MaxPlayers;
    WCHAR     HostTitle[XATTRIB_HOST_TITLE_MAX_LEN+1];
    ULONGLONG IsRanked;
    ULONGLONG TotalConnectedPlayers;
    ULONGLONG LoadOutLimit;
    ULONGLONG VoiceCount;


    XNKID      SessionID;
    XNKEY      KeyExchangeKey;
    XNADDR     HostAddress;
    DWORD      PublicOpen;
    DWORD      PrivateOpen;
    DWORD      PublicFilled;
    DWORD      PrivateFilled;

};
#pragma pack(pop)



//  Collection of results for the SpecificMatch query
class CSpecificMatchQueryResults
{
public:
    CSpecificMatchQueryResults() { m_dwSize = 0; }
    DWORD Size() { return m_dwSize; }
    CSpecificMatchResult &operator[]( DWORD i ) { return v[i]; }
private:
    void Clear() { m_dwSize = 0; }
    void Remove( DWORD i )
    {
        assert( i < m_dwSize );
        if( i < m_dwSize )
        {
            m_dwSize--;
            memcpy( &v[i], &v[i+1], sizeof( v[0] ) * ( m_dwSize - i ) );
        }
    }
    void SetSize( DWORD dwSize ) { m_dwSize = dwSize; }
    friend class CSpecificMatchQuery;
    CSpecificMatchResult v[MAX_SPECIFIC_MATCH_RESULTS];
    DWORD m_dwSize;
};



//
// Query object for SpecificMatch query (id 0x3)
//
class CSpecificMatchQuery
{
public:
    CSpecificMatchQuery();
    ~CSpecificMatchQuery();
    CSpecificMatchQueryResults Results;

    HRESULT Process();
    void Cancel();
    void Clear();
    BOOL Done()      const { return m_State == STATE_DONE; }
    BOOL Succeeded() const { return SUCCEEDED( m_hrQuery ); }
    HRESULT Query(
                  ULONGLONG SessionID
                 );
    BOOL IsRunning()  const { return m_State == STATE_RUNNING; }
private:
    enum STATE
    {
        STATE_IDLE,
        STATE_RUNNING,
        STATE_DONE
    };

    STATE m_State;
    HRESULT m_hrQuery;
    XONLINETASK_HANDLE m_hSearchTask;
};
