// Direct Play object class implementation

#ifndef _DP_SPIMP_H
#define _DP_SPIMP_H

#include "..\dplay\dplayi.h"

// Begin: declaration of main implementation class for IDirectPlay


#define MAX_MSG      (512 + sizeof(DPHDR))
#define MAX_PLAYERS  16
#define MAXIMUM_PLAYER_ID   256

typedef struct
{
    DPID    pid;
    char    chNickName[DPSHORTNAMELEN];
    char    chFullName[DPLONGNAMELEN ];
    HANDLE  hEvent;
    BOOL    bPlayer;
    BOOL    bValid;
    BOOL    bLocal;
    DPID    aGroup[MAX_PLAYERS];
} PLAYER_RECORD;


class CImpIDP_SP : public IDirectPlaySP {
public:
    // IUnknown methods
    // IDirectPlay methods
    virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID iid, LPVOID *ppvObj );
    virtual ULONG STDMETHODCALLTYPE AddRef( void);
    virtual ULONG STDMETHODCALLTYPE Release( void );

    virtual HRESULT STDMETHODCALLTYPE AddPlayerToGroup(
                                            DPID dwDPIDGroup,
                                            DPID dwDPIDPlayer);
    virtual HRESULT STDMETHODCALLTYPE Close(DWORD);
    virtual HRESULT STDMETHODCALLTYPE CreatePlayer(
                                        LPDPID pPlayerID,
                                        LPSTR pNickName,
                                        LPSTR pFullName,
                                        LPHANDLE lpReceiveEvent,
                                        BOOL     bPlayer);

    virtual HRESULT STDMETHODCALLTYPE   DeletePlayerFromGroup(
                                        DPID DPid,
                                        DPID dwDPIDPlayer);
    virtual HRESULT STDMETHODCALLTYPE DestroyPlayer( DPID pPlayerID, BOOL );
    virtual HRESULT STDMETHODCALLTYPE EnumGroupPlayers(
                                      DPID dwGroupPid,
                                      LPDPENUMPLAYERSCALLBACK EnumCallback,
                                      LPVOID pContext,
                                      DWORD dwFlags);

    virtual HRESULT STDMETHODCALLTYPE EnumPlayers(
                                      DWORD dwSessionID,
                                      LPDPENUMPLAYERSCALLBACK EnumCallback,
                                      LPVOID pContext,
                                      DWORD dwFlags);

    virtual HRESULT STDMETHODCALLTYPE EnumSessions(
                                       LPDPSESSIONDESC,
                                       DWORD dwTimeout,
                                       LPDPENUMSESSIONSCALLBACK EnumCallback,
                                       LPVOID,
                                       DWORD);

    virtual HRESULT STDMETHODCALLTYPE GetCaps(LPDPCAPS lpDPCaps);
    virtual HRESULT STDMETHODCALLTYPE GetMessageCount(DPID pidPlayer, LPDWORD lpdwCount);
    virtual HRESULT STDMETHODCALLTYPE GetPlayerCaps(
                                        DPID dwDPId,
                                        LPDPCAPS lpDPCaps);
    virtual HRESULT STDMETHODCALLTYPE GetPlayerName(DPID dpID,
                          LPSTR lpFriendlyName,          // buffer to hold name
                          LPDWORD pdwFriendlyNameLength, // length of name buffer
                          LPSTR lpFormalName,
                          LPDWORD pdwFormalNameLength
                          );


    virtual HRESULT STDMETHODCALLTYPE Initialize(LPGUID);
    virtual HRESULT STDMETHODCALLTYPE Open(
                        LPDPSESSIONDESC lpSDesc, HANDLE hEvent);

    virtual HRESULT STDMETHODCALLTYPE Receive(
                                LPDPID from,
                                LPDPID to,
                                DWORD  dwReceiveFlags,
                                LPVOID,
                                LPDWORD);


    virtual HRESULT STDMETHODCALLTYPE SaveSession(LPVOID lpv, LPDWORD lpdw);

    virtual HRESULT STDMETHODCALLTYPE SetPrevPlayer(LPSTR lpName, LPVOID lpv, DWORD dw);

    virtual HRESULT STDMETHODCALLTYPE SetPrevSession(LPSTR lpName, LPVOID lpv, DWORD dw);

    virtual HRESULT STDMETHODCALLTYPE EnableNewPlayers(BOOL bEnable);

    virtual HRESULT STDMETHODCALLTYPE Send(
                                DPID from,
                                DPID to,
                                DWORD dwFlags,
                                LPVOID lpvMsg,
                                DWORD dwLength);
    virtual HRESULT STDMETHODCALLTYPE SetPlayerName(
                                DPID from,
                                LPSTR lpFriendlyName,          
                                LPSTR lpFormalName,
                                BOOL  bPlayer);



   static CImpIDP_SP* NewCImpIDP_SP();

    VOID HandleConnect();
    VOID HandleMessage(LPVOID lpv, DWORD dwSize);
    VOID PulseBlock() {PulseEvent(m_hBlockingEvent);}
    VOID SetBlock() {SetEvent(m_hBlockingEvent);}
    VOID SendDesc(LPDPSESSIONDESC);
    VOID SendPing();
    VOID PostHangup();
    VOID ISend(LONG, LONG, DWORD, LPVOID, DWORD);
    VOID LocalMsg(LONG, LPVOID, DWORD);
    VOID RemoteMsg(LONG, LPVOID, DWORD);
    LONG FindInvalidIndex();
    VOID ConnectPlayers();
    VOID DeleteRemotePlayers();
    VOID ResetSessionDesc() {memset(&m_dpDesc, 0x00, sizeof(DPSESSIONDESC));}
    volatile BOOL             m_bConnected;
    BOOL             m_bPlayer0;            // If I created the call, I am player
                                            // zero.
    volatile DWORD            m_dwPendingWrites;

   void *operator new( size_t size );
   void operator delete( void *ptr );


protected:
    void Lock();
    void Unlock();

private:
    LONG GetPlayerIndex(DPID);
    BOOL SetSession(DWORD dw);
    CImpIDP_SP(void);
   ~CImpIDP_SP(void);

    DWORD            m_dwPingSent;
    HANDLE           m_hBlockingEvent;
    DWORD            m_dwNextPlayer;
    BOOL             m_bEnablePlayerAdd;

    PLAYER_RECORD    m_aPlayer[MAX_PLAYERS];
    char             m_lpDisplay[128];
    char             m_lpDialable[128];
    DWORD            m_dwID;
    LONG             m_iPlayerIndex;
    DPSESSIONDESC    m_dpDesc;

    int              m_refCount;
    CRITICAL_SECTION m_critSection;
    DPCAPS           m_dpcaps;

    HANDLE           m_hNewPlayerEvent;

    HANDLE           m_hTapiThread;
    DWORD            m_dwTapiThreadID;
    char           **m_ppSessionArray;
    DWORD            m_dwSessionPrev;
    DWORD            m_dwSessionAlloc;
};


BOOL SetIDP_SP( CImpIDP_SP *pSP);


// End  : declaration of main implementation class for IDirectPlay


/****************************************************************************
 *
 * DIRECTPLAY MESSAGES
 *
 * Errors are represented by negative values and cannot be combined.
 *
 ****************************************************************************/






// #define DPSYS_ENUM                    0x6172  // '4b797261' == 'Kyra' Born 10/21/94
// #define DPSYS_KYRA                    0x6172794b
// #define DPSYS_HALL                    0x6c6c6148
#define SPSYS_SYS                     0x07
#define SPSYS_USER                    0x0b
#define SPSYS_HIGH                    0x0d
#define SPSYS_CONNECT                 0x0f
// #define SYS_MSG     0x8000

typedef struct
{
    union
    {
        DWORD dwConnect1;  
        struct
        {
            UINT    to          :  8;
            UINT    from        :  8;
            UINT    usCount     : 10;
            UINT    usCookie    :  6;
        };
    };
}   DPHDR;

#if 0
typedef struct
{
    union
    {
        DWORD dwConnect1;
        struct
        {
            USHORT  usCookie;
            BYTE    to;
            BYTE    from;
        };
    };
    union
    {
        DWORD dwConnect2;
        struct
        {
            USHORT  usCount;
            BYTE    bHdrCRC;
            BYTE    bMsgCRC;
        };
    };
} DPHDR;
#endif


typedef struct
{
    DPHDR dpHdr;
    char chMsgCompose[1000];
} MSG_BUILDER;

#define SP_ENUM_COOKIE     0x794b

typedef struct
{
    DPHDR   dpHdr;
    USHORT  usVerMajor;
    USHORT  usVerMinor;
    DWORD   dwConnect1;
    DWORD   dwConnect2;
} SPMSG_CONNECT;

typedef struct
{
    DPHDR           dpHdr;
    DPMSG_GENERIC   sMsg;
} SPMSG_GENERIC;

typedef struct
{
    DPHDR   dpHdr;
    DWORD   dwType;
    BYTE    Group;
    BYTE    bytePlayers[16];
} SPMSG_SETGROUPPLAYERS16;    


#define SIZE_GENERIC (sizeof(SPMSG_GENERIC) - sizeof(DPHDR))
typedef struct
{
    DPHDR           dpHdr;
    DWORD          dwType;
    DPSESSIONDESC   dpSessionDesc;
} SPMSG_ENUM;

#define DPSYS_ENUM_REPLY     0x0002

typedef struct
{
    DPHDR           dpHdr;
    DWORD          dwType;
    DWORD          usPort;
} SPMSG_ENUM_REPLY;


typedef struct
{
    DWORD  dwType;
    DPID    dpId;
} DPMSG_GETPLAYER;

typedef struct
{
    DPHDR           dpHdr;
    DPMSG_GETPLAYER sMsg;
} SPMSG_GETPLAYER;
#define SIZE_GETPLAYER  (sizeof(SPMSG_GETPLAYER) - sizeof(DPHDR))


typedef struct
{
    DPHDR           dpHdr;
    DPMSG_ADDPLAYER sMsg;
} SPMSG_ADDPLAYER;


#define SIZE_ADDPLAYER (sizeof(SPMSG_ADDPLAYER) - sizeof(DPHDR))


typedef struct
{
    DPHDR   dpHdr;
    DPMSG_GROUPADD sMsg;
} SPMSG_GROUPADD;

typedef struct
{
    DPHDR   dpHdr;
    DWORD  dwType;
    DWORD   dwTicks;
} SPMSG_PING;

#define SIZE_PING (sizeof(SPMSG_PING) - sizeof(DPHDR))



typedef struct
{
    DPHDR   dpHdr;
    DWORD          dwType;
    GUID    guid;
} SPMSG_INVITE;



typedef struct
{
    DPHDR       dpHdr;
    DWORD       dwType;
    DPCAPS      dpCaps;
} SPMSG_GETPLAYERCAPS;

#define SIZE_GETPLAYERCAPS (sizeof(SPMSG_GETPLAYERCAPS) - sizeof(DPHDR))

typedef struct
{
    DPHDR           dpHdr;
    DWORD           dwType;
    DPSESSIONDESC   dpDesc;
} SPMSG_SENDDESC;

#define SIZE_SENDDESC (sizeof(SPMSG_SENDDESC) - sizeof(DPHDR))

typedef struct
{
    DWORD       dwType;
    BOOL        bEnable;
} DPMSG_ENABLEPLAYER;
typedef struct
{
    DPHDR               dpHdr;
    DPMSG_ENABLEPLAYER  sMsg;
} SPMSG_ENABLEPLAYER;

extern BOOL AddMessage(LPVOID lpvMsg, DWORD dwSize, DPID pidTo, DPID pidFrom, BOOL bHigh);
extern HRESULT GetQMessage(LPVOID lpvMsg, LPDWORD pdwSize, DPID *ppidTo, DPID *ppidFrom,
                DWORD dwFlags, BOOL bPeek);
extern VOID  FlushQueue(DPID pid);
extern DWORD GetPlayerCount(DPID spid);

#define DPSYS_JOHN    0x6e686f4a


// Enumeration Messages

//
// Thread Messages
//
#define PWM_BASE        0x00007000
#define PWM_COMMWRITE   PWM_BASE    +1
#define PWM_SETIDP      PWM_BASE    +2
#define PWM_HANGUP      PWM_BASE    +3
#define PWM_CLOSE       PWM_BASE    +4




#endif