#pragma once
//
//============================================================
//
// Contents:  Network header file
//
// Owner   :  AndyG
// Created :  Aug 2 1999
//
// All Rights reserved worldwide (c) Microsoft
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               
//============================================================
//
#include "Network.hpp"
#include "DirectX.hpp"

//
// Packet overhead of DirectPlay
//
#define PACKET_OVERHEAD 42


#define OUTBOUND_WINDOW


//
//
// Used to store network packets
//
//
typedef struct _PacketBuffer
{
	_PacketBuffer*	pNext;
	DWORD			Size;			// Size of buffer
	DWORD			PacketSize;
	DWORD			FromID;
	DWORD			ToID;
	double			TimeStamp;
	bool			Encrypted;
	BYTE			Data[0];		// Data follows

} PacketBuffer;

//
// List of names, used for modems, serial ports, players, games etc...
//
typedef struct _ListOfNames
{
	_ListOfNames*	pNext;				// Pointer to next in chain
	DWORD			Data;				// Data that is list dependent
	DWORD			PacketsReceived;	// NUmber of packets received from a player
	double			LastTime;			// Time last packet received
	char			Name[1];			// Name

} ListOfNames;


//
// List of games (and players in those games)
//
typedef struct _ListOfGames
{
	_ListOfGames*	pNext;				// Pointer to next in chain
	DPSESSIONDESC2	SessionDescriptor;	// Session description
	ListOfNames*	pPlayers;			// Pointer to list of player names
	bool			bIPX;				// whether the game is hosted with IPX or not (TCP/IP)
	char			Name[1];			// Name

} ListOfGames;

//
// List of messages waiting for the application to get
//
typedef struct _Messages
{
	_Messages*	pNext;
	NetPacket	Data;

} Messages;


//
// All memory in networking must be allocated on this heap
//
extern HGOSHEAP Heap_Network;


//
// Interfaces
//
#define MAX_DP_OBJECTS	8
extern IDirectPlayLobby3*		dplobby3;	// Lobby interface
extern IDirectPlay4*			dplay4;	// Direct Play interface


//
// Current joined or opened session description
//
extern DPSESSIONDESC2 CurrentSession;

//
// Last time that games and players were enumerated
//
extern double LastEnumTime;
extern bool WaitingForEnum;

//
// Protocols
//
extern bool hasTCP;
extern bool hasIPX;							// True when protcol is valid
extern bool hasModem;
extern bool hasSerial;
extern bool hasZoneMatch;

//
// True when connection exists
//
extern int Connected;

//
// Result from last enumeration on a thread
//
extern HRESULT EnumResult;

//
// True when a game created or joined
//
extern bool InNetworkGame;

//
// True when created the game
//
extern bool IAmTheServer;

//
// Current players ID
//
extern DWORD MyDirectPlayID;

//
// String containing my address (when TCPIP)
//
extern char* MyIPAddress;

//
// Valid serial ports
//
extern ListOfNames* SerialPortNames;

//
// Valid modem names (maximum of 8)
//
extern ListOfNames* ModemNames;

//
// Points to a list of the current game names found on the network
//
extern ListOfGames*	GameNames;

extern char** ListOfPassworded;

//
// Points to a list of the current game names found on the network being enumerated
//
extern ListOfGames* EnumNames;

//
// List of messages on the recieve queue
//
extern Messages* pMessages;

//
// List of players in the current game
//
extern ListOfNames* CurrentPlayers;

//
// Buffer used while receiving messages
//
extern BYTE* MessageBuffer;
extern DWORD MessageBufferSize;

//
// Points to a list of messages that the Application will pull message from
//
extern Messages*	pMessages;
//
// Points to the last message read by the Application (will be freed)
//
extern Messages*	pLastMessage;




//
// Linked list of sent/recieved packets
//
typedef struct _PacketLogging
{
	_PacketLogging* pNext;
	double			TimeStamp;							// When packet was added to list
	DWORD			FrameNumber;						// Frame number added
	char			Type[11];							// Type of packet
	char			Player[11];							// From or To player name
	DWORD			FromID;								// ID of FROM player
	DWORD			ToID;								// ID of TO player
	DWORD			Size;								// Size of packet
	BYTE			Data[8];							// 1st 8 bytes

} PacketLogging;
//
// Pointer to latest packet
//
extern PacketLogging*	pPacketLog;
//
// Exact time network stats were grabbed
//
extern double NetworkDebugTime;
//
// Pointer to log at start of frame
//
extern PacketLogging*	pDebugPacketLog;





#pragma pack(push,1)
//
// Structure sent with all network packets
//
#ifdef OUTBOUND_WINDOW
typedef struct _PacketHeader
{
	BYTE	Type;										// User defined type (224-> system messages)
	WORD	ThisPacketNumber;
	WORD	LastPacketReceived;

} PacketHeader;
#else
typedef struct _PacketHeader
{
	BYTE	Type;										// User defined type (224-> system messages)

} PacketHeader;
#endif



#pragma pack(pop)


//
// Routine's
//
void _stdcall CheckProtocols();
void _stdcall ReceivePackets();
void _stdcall GetCurrentPlayers();
void _stdcall AddGOSMessage( Messages* pMessage );
BOOL PASCAL EnumSessionsCallback( LPCDPSESSIONDESC2 lpSessionDesc, LPDWORD lpdwTimeOut, DWORD dwFlags, void* lpContext );
BOOL PASCAL EnumJoinSessionCallback( LPCDPSESSIONDESC2 lpSessionDesc, LPDWORD lpdwTimeOut, DWORD dwFlags, void* lpContext );
BOOL PASCAL EnumPlayersCallback( DPID dpId, DWORD dwPlayerType, LPCDPNAME lpName, DWORD dwFlags, LPVOID lpContext );
BOOL FAR PASCAL ModemCallback( REFGUID guidDataType, DWORD dwDataSize, LPCVOID lpData, void* lpContext );
BOOL FAR PASCAL TCPIPCallback( REFGUID guidDataType, DWORD dwDataSize, LPCVOID lpData, void* lpContext );
void _stdcall WaitTillQueueEmpty();
void _stdcall AddPlayerToGame( ListOfNames** pListOfPlayers, char* Name, DPID dpId );
void _stdcall RemovePlayerFromGame( ListOfNames** pListOfPlayers, char* Name, DPID dpId );
char* _stdcall GetName10( DWORD Id );
void _stdcall UpdateNetworkDebugInfo();
char* _stdcall DecodeIPAddress( DPLCONNECTION* pConnection );
WORD _stdcall DecodePORTAddress( DPLCONNECTION* pConnection );


//
// Receive packet thread variables
//
extern unsigned int __stdcall NetworkThread(void*);
extern unsigned int NetworkThreadID;
extern HANDLE HandleNetworkThread;
extern CRITICAL_SECTION NetworkCriticalSection;
extern HANDLE NetworkEvent;
extern HANDLE KillNetworkEvent;
extern unsigned int __stdcall NetworkThread(void*);

//
// Enumeration thread variables
//
extern unsigned int EnumThreadID;
extern HANDLE HandleEnumThread;
extern CRITICAL_SECTION EnumCriticalSection;
extern HANDLE EnumEvent;
extern HANDLE KillEnumEvent;
extern unsigned int __stdcall EnumThread(void*);

//
// Used to hold list of packets to pass data between threads
//
extern PacketBuffer* pEmptyList;		// List of spare blocks
extern PacketBuffer* pPackets;			// List of received packets
extern PacketBuffer* pLastPacket;		// End of list of received packets



//
// Functions used initialize game list drivers
//

int _stdcall InitLanGames();
int _stdcall InitGUNGames();
void _stdcall GUNDestroyNetworking();
void _stdcall CheckForInternet();


// InternalJoinGame() needs this for joining GUN Games.
void _stdcall PushGameList( void );
bool _stdcall GUNPrepareDPlay( const char * GameName );

HRESULT _stdcall QuickEnum( bool async ); // quickly begin dplay enumeration of sessions.



#ifdef OUTBOUND_WINDOW
typedef struct tagPACKETQUEUE
{ 
	NetPacket *				pPacket;
	struct tagPACKETQUEUE *	pNext;

} PACKETQUEUE;


//========================================================================
// OutboundWindow
//
// The OutboundWindow class is an object that manages how many non
// guaranteed packets are allowed to be outstanding and not accounted for.
// This prevents us from filling the modem send queue qith messages.
//
// What we do is we stamp each outgoing message with a count, and the
// remote machine informs us of the last packet it received with every
// packet it sends to us. This way, we can know how many outstanding non
// guaranteed packets are outstanding at any time. If there are more than
// some predetermined number (the "window"), then any attempt to send a
// packet fails.
//
// A client will have a single OutboundWindow object, associated with the
// server. A server will have one for each client.
//
// If we haven't sent the last packet we've received after a certain
// amount of time, we manually send this in a packet that contains ONLY
// this.
//========================================================================
class OutboundWindow
{
public:
	static const int m_WindowSize;
	static const double m_ResendTime;

	// we only have one constructor: you MUST supply the DPID when you create one!!!
	OutboundWindow(DPID);

	static bool __stdcall Synchronize(void);	// call every frame
	static bool __stdcall CleanAll(void);
	static OutboundWindow* _stdcall Find(DPID dpid);
	bool __stdcall Add(void);
	bool __stdcall Remove(void);
	void * operator new(size_t size)
	{
		return gos_Malloc(size, Heap_Network);
	}
	void operator delete( void* ptr )
	{
		gos_Free(ptr);
	}
	void operator delete[] ( void* ptr )
	{
		gos_Free(ptr);
	}


public:
	double					m_TimeLastPacketSent;
	WORD					m_NextPacketNumberToSend;
	WORD					m_LastPacketWeReceived;
	WORD					m_LastPacketTheyReceived;
	PACKETQUEUE *			m_PacketQueue;
	DPID					m_dpid;			// the dpid of the associated remote machine
	OutboundWindow *		m_pNext;

	static OutboundWindow *	m_pHead;

	//PacketLogging* pThis=(PacketLogging*)gos_Malloc( sizeof(PacketLogging), Heap_Network );

};

#endif OUTBOUND_WINDOW
