#include "Error.h"

#ifndef _PROTOCOL
#define _PROTOCOL

#define TEST

#define P0_VERSION 0

#define P0_ERROR 0
#define P0_ORIENTATION_REQUEST 1
#define P0_ORIENTATION_RESPONSE 2
#define P0_ACCESS_INITIALIZE 3		/* init + change */
#define P0_ACCESS_CHANGE 4
#define P0_ACCESS_RESPONSE 5
#define P0_ACCESS_UPGRADE 6		/* async reply for queues */
#define P0_STATUS_QUERY 7		/* ping */
#define P0_STATUS_RESPONSE 8
#define P0_SECURITY 9			/* extra authentication proto */
#define P0_STATE 10
#define P0_STATE_REPLY 11
#define P0_REDUCE 12
#define P0_REDUCE_REPLY 13

#define SERVERVEC ((1 << P0_STATE) | (1 << P0_STATE_REPLY) | \
		   (1 << P0_REDUCE) | (1 << P0_REDUCE_REPLY))

#define ISSERVERPACKET(x) (0 != (SERVERVEC & (1 << x)))

extern char *protoTypes[14];

#define P0_PROTO_NAME(x) (protoTypes[x])

#define E_ACCESSDENIED 1	/* user/machine hasn't access */
#define E_PACKAGEUNKNOWN 2	/* server doesn't know package */
#define E_BADPACKET 3		/* packet couldn't be parsed */
#define E_BADPROTO 4		/* useful? */
#define E_SERVERLOSSAGE 5	/* server problems prevent completion */
#define E_NORESOURCES 6		/* no licenses to grant request */
#define E_CLUELESS 7		/* server doesn't know what's going on */

#define N_BM 3
#define N_MC 3
#define N_retry 3
#define N_storedPools 3

#define N_reduce 3		/* number of packets to exchange */
#define T_reduce 5		/* time between packets */
#define F_reduce 2		/* number of failures to give up on */

#ifdef TEST
#define T_clueless 3
#define T_update 20
#define T_slop 3
#define T_ping 10
#define T_split 120
#define T_retry 1
#else
#define T_clueless 20
#define T_update 60
#define T_slop 20
#define T_ping 500
#define T_split 3600
#define T_retry 10
#endif

#define T_MB (T_update + T_retry * (N_retry + 1))
#define T_BM T_MB

struct _P0Block;

typedef struct _P0Message
{
  Card16 version;
  Card16 type;
  Card16 context;

  int numBlocks;
  struct _P0Block *firstBlock;
  struct _P0Block *lastBlock;
} P0Message;

typedef struct _P0Block
{
  char *type;
  char *current;		/* next empty location */
  int initialSize;
  int dataSize;			/* size of malloced data */
  char *data;
  int malloced;
  struct _P0Block *nextBlock;
  P0Message *message;
} P0Block;

#define P0_BlockType(block) (block->type)
#define P0_ResetBlock(block) block->current = block->data;

#ifdef 0
extern Trap P0_PutHeader(P0Packet *packet);
extern Trap P0_GetHeader(P0Packet *packet);
extern Trap P0_PutLength(P0Packet *packet);
#endif

extern Trap P0_InitMessage(P0Message *message, Card16 type, Card16 context);
extern Trap P0_CreateMessage(P0Message **message, Card16 type, Card16 context);
extern Trap P0_FreeMessage(P0Message *message);

extern Trap P0_InitBlock(char *type, P0Block *block,
			 char *data, int sizeHint);
extern Trap P0_CreateBlock(char *type, P0Block **block,
			   char *data, int sizeHint);
extern Trap P0_FreeBlock(P0Block *block);

extern Trap P0_AddBlockToMessage(P0Message *message, P0Block *block);

extern Trap P0_CvtMessageToBlock(P0Message *message, P0Block *block);
extern Trap P0_CvtBlockToMessage(P0Block *block, P0Message **message);

extern Trap P0_PutBlock(P0Block *block, P0Block *blck);
extern Trap P0_PutString(P0Block *block, char *string);
extern Trap P0_GetString(P0Block *block, char **string);
extern Trap P0_PutCard16(P0Block *block, Card16 card);
extern Trap P0_GetCard16(P0Block *block, Card16 *card);
extern Trap P0_PutCard32(P0Block *block, Card32 card);
extern Trap P0_GetCard32(P0Block *block, Card32 *card);

#endif /* _PROTOCOL */
