/* Copyright (c) 1993 Stephen F. White */

#ifndef COOL_H
#define COOL_H

#include "os.h"
#undef IN
#undef IGNORE
#undef ECHO
#undef CTIME
#include "string.h"

#define raise(x) cool_raise(x)  /* so as not to conflict with signal.h */

/*
 * useful macros
 */
#define Arraysize(x)   (int) (sizeof(x) / sizeof(x[0]))
#ifndef MIN
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#endif
#ifndef MAX
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#endif

#define INT_SIZE    10  /* size of buffer big enough to hold an int */
#define LONG_SIZE   20  /* size of buffer big enough to hold a long */

#define STRING_INIT_SIZE    16  /* initialize length of String values */
#define STRING_DOUBLING         /* double Strings when needed */
#define STRING_GROW_BY      32  /* or use this to increment linearly */

#define CODE_INIT_SIZE  32
#define SYM_INIT_SIZE   16
#define STACK_SIZE  128

#define HASH_INIT_SIZE  37
#define HASH_INIT_LOAD  2

#define MAX_TOKEN_LEN   40  /* maximum length of internal token names */
#define MAX_PATH_LEN    1024    /* maximum length of path names */

#define SYS_OBJ     0
#define ROOT_OBJ    1   /* if defined, the server will force 1 root */
#define MAX_AGE     20  /* default max. recursion, essentially */
#define MAX_TICKS   10000   /* default maximum instructions per task */
#define PLAYER_PORT 7777    /* default player port */

typedef short   Serverid;
typedef int Playerid;

#define NOTHING (-1)        /* represents an invalid player */

#define BLOCK_SIZE 512      /* size of input block */
#define UDP_BLOCK_SIZE 2048     /* size of input block for YO packets */
#define PROGDIR     "/tmp"  /* temp directory for COOL programs */
#define RUNDIR      "online"    /* directory for on-line files */

#define MALLOC(what, number) (what *) cool_malloc((number) * sizeof(what))
#define FREE(what) cool_free( (void *) what)

/*
 * timing stuff
 */

#define MSG_TIMEOUT 30  /* message timeout, in seconds */
#define MSG_RETRY   1500    /* message retry interval, in msec */
#define EXP_BACKOFF     /* define this for exponential backoff */
#define LOCK_TIMEOUT    30  /* lock timeout, in seconds */

/*
 * input quotas
 */
#define MAX_CMDS    100 /* maximum commands in a burst */
#define MSEC_PER_CMD    1000    /* time between commands after a burst */

#define OUTBOUND_TIMEOUT 5	/* timeout for gethostbyname() */
#define MAX_OUTPUT 16384    /* maximum amount of queued output */

#define CONNECT_MSG "*** Connected ***\r\n"
#define DISCONNECT_MSG "*** Disconnected ***\r\n"
#define TRANSFER_MSG1 "*** Transferring to new connection ***\r\n"
#define TRANSFER_MSG2 "*** Reconnecting to old connection ***\r\n"


typedef enum Type_spec {
  STR, NUM, OBJ, LIST, MAP, ERR, PC
} Type_spec;

typedef struct Var Var;

typedef struct Objid {
  short server;                 /* server id (0 == this server) */
  int id;                       /* object id */
} Objid;

typedef struct List {
  int len;                      /* length of list */
  int mem;                      /* memory actually allocated */
  int ref;                      /* reference count */
  Var *el;                      /* elements of list */
} List;

typedef struct MapPair MapPair;

typedef enum Error {
  E_NONE, E_TYPE, E_RANGE, E_INVIND, E_DIV, E_MAXREC,
  E_METHODNF, E_VARNF, E_VERBNF, E_FOR, E_PERM, E_SERVERNF, E_SERVERDN,
  E_OBJNF, E_MESSAGE, E_TIMEOUT, E_STACKUND, E_STACKOVR, E_INTERNAL,
  E_FILE, E_ARGTYPE, E_NARGS, E_TICKS, E_TERM, E_MAPNF
} Error;

#define NERRS 25

/*
 * cannot ignore or catch these errors
 */
#define NOIGNORE(err) (err == E_STACKUND || err == E_STACKOVR \
            || err == E_INTERNAL || err == E_TICKS)

typedef struct HashT {
  int size;                     /* width of hash table */
  int num;                      /* number of elements in table */
  int ref;                      /* reference count */
  void **table;                 /* have to use void *, for multiple datatypes */
} HashT;

typedef HashT Map;

struct Var {
  Type_spec type;
  union {
    int num;                    /* number */
    Objid obj;                  /* object id */
    String *str;                /* string header */
    List *list;                 /* list header */
    Map *map;                   /* map header */
    Error err;                  /* error */
  } v;
};

struct MapPair {
  Var from;                     /* key of map element */
  Var to;                       /* data of map element */
  MapPair *next;
};

typedef struct Symbol {
  int ref;                      /* local object references to symbol */
  String *s;                    /* symbol */
} Symbol;

#define ISTRUE(x)  ((x.type == NUM && x.v.num) \
        ||  (x.type == STR && x.v.str->str[0]) \
        ||  (x.type == OBJ && x.v.obj.id >= 0) \
        ||  (x.type == LIST && x.v.list->len))

typedef int Inst;
typedef struct Method Method;
typedef struct Verbdef Verbdef;
typedef struct Vardef Vardef;

typedef struct Lock Lock;

struct Lock {
  String *name;
  int added_by;                 /* msgid which added this lock */
  Lock *next;
};

typedef struct Object {
  Objid id;                     /* object's id */
  int ref;                      /* reference count */
  List *parents;                /* parent list */
  Lock *locks;
  HashT *methods;               /* method list, hashed */
  Verbdef *verbs;
  HashT *vars;                  /* variables, hashed */
  int var_hashsize;
  int nsymb;                    /* number of symbols */
  int st_size;                  /* memory actually allocated for symbols */
  Symbol *symbols;              /* symbol table */
  int last_search;              /* generational flag, last search on object */
  /* kudos to greg hudson for the idea */
} Object;

enum eh { EH_DEFAULT, EH_IGNORE, EH_CATCH };

struct Method {
  int name;                     /* index into symbol table */
  int ninst;                    /* number of instructions in machine */
  Inst *code;                   /* the compiled code */
  enum eh ehandler[NERRS];      /* error handler */
  Vardef *vars;                 /* local variables */
  int ref;                      /* reference count */
  Method *next;                 /* next method in linked list */
  int blocked:1;                /* non-overrideable ("nomask") flag  */
};

struct Verbdef {
  int verb;                     /* name of verb */
  int prep;                     /* preposition, or -1 for none */
  int method;                   /* method to call */
  Verbdef *next;                /* next verbdef in linked list */
};

struct Vardef {
  int name;                     /* index into symbol table */
  Var value;                    /* value */
  Vardef *next;                 /* next vardef in linked list */
};

enum state { RUNNING,           /* program is running */
  STOPPED,                      /* program stopped by return or end of code */
  HALTED,                       /* program halted by method called */
  RAISED,                       /* program stopped by raise() */
  BLOCKED
};                              /* program blocked on event */

typedef void (*PFV) (void);

typedef enum Sys_sym {
  BLANK, INIT, PARSE, BOOT_SERVER, CONNECT_SERVER, DISCONNECT_SERVER,
    SYM_CONNECT, SYM_DISCONNECT, RAISE, RETURN
} Sys_sym;

enum arg_type { none, NUM_ARG, ID_ARG, STR_ARG, VARNO_ARG };

struct bf_entry {
    int         num;
    const char  *name;
    int         minargs;
    int         maxargs;
};

typedef struct Op_entry {
  int opcode;
  const char name[MAX_TOKEN_LEN];
  PFV func;
  int nargs;
  enum arg_type arg_type[3];
  struct bf_entry	*builtin;
} Op_entry;

#endif /* !COOL_H */