/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2006 Robert Beckebans <trebor_7@users.sourceforge.net>

This file is part of XreaL source code.

XreaL source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.

XreaL source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with XreaL source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/

// net.h
#ifndef NET_H
#define NET_H

//Ignore __attribute__ on non-gcc platforms
#ifndef __GNUC__
#ifndef __attribute__
#define __attribute__(x)
#endif
#endif

/*
==============================================================

NET MSG

==============================================================
*/

typedef struct
{
	qboolean        allowoverflow;	// if false, do a Com_Error
	qboolean        overflowed;	// set to true if the buffer size failed (with allowoverflow set)
	qboolean        oob;		// set to true if the buffer size failed (with allowoverflow set)
	byte           *data;
	int             maxsize;
	int             cursize;
	int             readcount;
	int             bit;		// for bitwise reads and writes
} msg_t;

void            MSG_Init(msg_t * buf, byte * data, int length);
void            MSG_InitOOB(msg_t * buf, byte * data, int length);
void            MSG_Clear(msg_t * buf);
void            MSG_WriteData(msg_t * buf, const void *data, int length);
void            MSG_Bitstream(msg_t * buf);

// TTimo
// copy a msg_t in case we need to store it as is for a bit
// (as I needed this to keep an msg_t from a static var for later use)
// sets data buffer as MSG_Init does prior to do the copy
void            MSG_Copy(msg_t * buf, byte * data, int length, msg_t * src);

struct usercmd_s;
struct entityState_s;
struct playerState_s;

void            MSG_WriteBits(msg_t * msg, int value, int bits);

void            MSG_WriteChar(msg_t * sb, int c);
void            MSG_WriteByte(msg_t * sb, int c);
void            MSG_WriteShort(msg_t * sb, int c);
void            MSG_WriteLong(msg_t * sb, int c);
void            MSG_WriteFloat(msg_t * sb, float f);
void            MSG_WriteString(msg_t * sb, const char *s);
void            MSG_WriteBigString(msg_t * sb, const char *s);
void            MSG_WriteAngle16(msg_t * sb, float f);

void            MSG_BeginReading(msg_t * sb);
void            MSG_BeginReadingOOB(msg_t * sb);

int             MSG_ReadBits(msg_t * msg, int bits);

int             MSG_ReadChar(msg_t * sb);
int             MSG_ReadByte(msg_t * sb);
int             MSG_ReadShort(msg_t * sb);
int             MSG_ReadLong(msg_t * sb);
float           MSG_ReadFloat(msg_t * sb);
char           *MSG_ReadString(msg_t * sb);
char           *MSG_ReadBigString(msg_t * sb);
char           *MSG_ReadStringLine(msg_t * sb);
float           MSG_ReadAngle16(msg_t * sb);
void            MSG_ReadData(msg_t * sb, void *buffer, int size);

void            MSG_WriteDeltaUsercmd(msg_t * msg, struct usercmd_s *from, struct usercmd_s *to);
void            MSG_ReadDeltaUsercmd(msg_t * msg, struct usercmd_s *from, struct usercmd_s *to);

void            MSG_WriteDeltaUsercmdKey(msg_t * msg, int key, usercmd_t * from, usercmd_t * to);
void            MSG_ReadDeltaUsercmdKey(msg_t * msg, int key, usercmd_t * from, usercmd_t * to);

void            MSG_WriteDeltaEntity(msg_t * msg, struct entityState_s *from, struct entityState_s *to, qboolean force);
void            MSG_ReadDeltaEntity(msg_t * msg, entityState_t * from, entityState_t * to, int number);

void            MSG_WriteDeltaPlayerstate(msg_t * msg, struct playerState_s *from, struct playerState_s *to);
void            MSG_ReadDeltaPlayerstate(msg_t * msg, struct playerState_s *from, struct playerState_s *to);

void            MSG_ReportChangeVectors_f(void);

/*
==============================================================

NET CHANNEL

==============================================================
*/

#define	PACKET_BACKUP	32			// number of old messages that must be kept on client and
									// server for delta comrpession and ping estimation
#define	PACKET_MASK		(PACKET_BACKUP-1)

#define	MAX_PACKET_USERCMDS		32	// max number of usercmd_t in a packet

#define	PORT_ANY			-1

#define	MAX_RELIABLE_COMMANDS	64	// max string commands buffered for restransmit

typedef enum
{
	NA_BOT,
	NA_BAD,							// an address lookup failed
	NA_LOOPBACK,
	NA_BROADCAST,
	NA_IP,
	NA_IPX,
	NA_BROADCAST_IPX
} netadrtype_t;

typedef enum
{
	NS_CLIENT,
	NS_SERVER
} netsrc_t;

typedef struct
{
	netadrtype_t    type;

	byte            ip[4];
	byte            ipx[10];

	unsigned short  port;
} netadr_t;

void            NET_Init(void);
void            NET_Shutdown(void);
void            NET_Restart(void);
void            NET_Config(qboolean enableNetworking);
void			NET_FlushPacketQueue(void);
void            NET_SendPacket(netsrc_t sock, int length, const void *data, netadr_t to);
void QDECL      NET_OutOfBandPrint(netsrc_t net_socket, netadr_t adr, const char *format, ...);
void QDECL      NET_OutOfBandData(netsrc_t sock, netadr_t adr, byte * format, int len);

qboolean        NET_CompareAdr(netadr_t a, netadr_t b);
qboolean        NET_CompareBaseAdr(netadr_t a, netadr_t b);
qboolean        NET_IsLocalAddress(netadr_t adr);
const char     *NET_AdrToString(netadr_t a);
qboolean        NET_StringToAdr(const char *s, netadr_t * a);
qboolean        NET_GetLoopPacket(netsrc_t sock, netadr_t * net_from, msg_t * net_message);
void            NET_Sleep(int msec);


#define	MAX_MSGLEN				16384	// max length of a message, which may
											// be fragmented into multiple packets

#define MAX_DOWNLOAD_WINDOW			8	// max of eight download frames
#define MAX_DOWNLOAD_BLKSIZE		2048	// 2048 byte block chunks

// Netchan handles packet fragmentation and out of order / duplicate suppression
typedef struct
{
	netsrc_t        sock;

	int             dropped;	// between last packet and previous

	netadr_t        remoteAddress;
	int             qport;		// qport value to write when transmitting

	// sequencing variables
	int             incomingSequence;
	int             outgoingSequence;

	// incoming fragment assembly buffer
	int             fragmentSequence;
	int             fragmentLength;
	byte            fragmentBuffer[MAX_MSGLEN];

	// outgoing fragment buffer
	// we need to space out the sending of large fragmented messages
	qboolean        unsentFragments;
	int             unsentFragmentStart;
	int             unsentLength;
	byte            unsentBuffer[MAX_MSGLEN];
} netchan_t;

void            Netchan_Init(int qport);
void            Netchan_Setup(netsrc_t sock, netchan_t * chan, netadr_t adr, int qport);

void            Netchan_Transmit(netchan_t * chan, int length, const byte * data);
void            Netchan_TransmitNextFragment(netchan_t * chan);

qboolean        Netchan_Process(netchan_t * chan, msg_t * msg);

/*
==============================================================

HUFFMAN COMPRESSION

==============================================================
*/

/* This is based on the Adaptive Huffman algorithm described in Sayood's Data
 * Compression book.  The ranks are not actually stored, but implicitly defined
 * by the location of a node within a doubly-linked list */

#define NYT HMAX				/* NYT = Not Yet Transmitted */
#define INTERNAL_NODE (HMAX+1)

typedef struct nodetype
{
	struct nodetype *left, *right, *parent;	/* tree structure */
	struct nodetype *next, *prev;	/* doubly-linked list */
	struct nodetype **head;		/* highest ranked node in block */
	int             weight;
	int             symbol;
} node_t;

#define HMAX 256				/* Maximum symbol */

typedef struct
{
	int             blocNode;
	int             blocPtrs;

	node_t         *tree;
	node_t         *lhead;
	node_t         *ltail;
	node_t         *loc[HMAX + 1];
	node_t        **freelist;

	node_t          nodeList[768];
	node_t         *nodePtrs[768];
} huff_t;

typedef struct
{
	huff_t          compressor;
	huff_t          decompressor;
} huffman_t;

void            Huff_Compress(msg_t * buf, int offset);
void            Huff_Decompress(msg_t * buf, int offset);
void            Huff_Init(huffman_t * huff);
void            Huff_addRef(huff_t * huff, byte ch);
int             Huff_Receive(node_t * node, int *ch, byte * fin);
void            Huff_transmit(huff_t * huff, int ch, byte * fout);
void            Huff_offsetReceive(node_t * node, int *ch, byte * fin, int *offset);
void            Huff_offsetTransmit(huff_t * huff, int ch, byte * fout, int *offset);
void            Huff_putBit(int bit, byte * fout, int *offset);
int             Huff_getBit(byte * fout, int *offset);

extern huffman_t clientHuffTables;

#define	SV_ENCODE_START		4
#define SV_DECODE_START		12
#define	CL_ENCODE_START		12
#define CL_DECODE_START		4

#endif // NET_H
