#ifndef BILL_H
#define BILL_H

#include <X11/Xlib.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/xpm.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>

#define INTERVAL 250		/*timer interval*/
#define MAX_COMPUTERS 25	/*maximum number of computers on screen*/
#define WALK_CELS 4		/*number of bill walking animation frames*/
#define DEATH_CELS 5		/*number of bill dying animation frames*/
#define AT_CELS 13		/*number of bill switching OS frames*/
#define NUM_OS	5		/*number of operating systems supported*/
				/*  not including wingdows  */
#define BILL_X_OFFSET 20	/*offset of bill from right of computer*/
#define BILL_Y_OFFSET 3		/*offset of bill from top of computer*/
#define OS_OFFSET 4		/*offset of computer screen from pixmap 0,0 */
#define GRAVITY 3		/*speed at which os drop*/
#define BORDER 8		/*width/BORDER pixels left free on each side*/
				/*height/BORDER pixels left free on top/bottom*/

#define ENDLEVEL 42		/*Action codes for update score */
#define BILLPOINTS 5		/*How much a bill is worth to you!*/

#define N 0			/*directions for monster to walk in */
#define NE 1
#define E 2
#define SE 3
#define S 4
#define SW 5
#define W 6
#define NW 7 

#define WINGDOWS 0		/*important constant */

#define NUM_STATES 3		/*states for each computer*/
#define BASE_STATE 0
#define WINGDOWS_STATE 1
#define OFF_STATE 2

#define SLOW 0			/* speeds of moving bills */
#define FAST 1

#define PLAYING 1
#define OPENING 2
#define BETWEEN 3
#define END 4
#define WAITING 5

#define LOGO_WIDTH 299
#define LOGO_HEIGHT 66

typedef struct {		/**structure for Bills**/
	int index;		/*index to animation & context frame*/
	Pixmap *cels;		/*pointer to array of animation frames*/
	GC *contexts;		/*pointer to graphic context which stores
				  mask for drawing the bill*/
	int x, y;		/*location*/
	int target_x;		/*target x postion*/
	int target_y;		/*target y postion*/
	int target_c;		/*target computer*/
	Pixmap cargo;		/*pointer to picture of OS carried*/
	int x_offset;		/*accounts for width differences*/
	int y_offset;		/*'bounce' factor for OS carried*/
	int type;		/*reserved for future use*/
	int id;			/*good for debugging*/
} monster;

typedef struct {		/**structure for Computers**/
	Pixmap picture;		/*pointer to current computer picture*/
	int os;			/*index to native os picture*/
	int x, y;		/*location*/
	int status;		/*determines what the computer is doing*/
	int busy;		/*is the computer being used?*/
} hardware;

typedef monster *data_ptr;
struct node_struct{
	data_ptr data;
	struct node_struct *prev, *next;
};

typedef struct node_struct node;
typedef node *list;

typedef struct{			/**structure for global network of all computers**/
	Pixmap pictures[NUM_OS+1][NUM_STATES];		/*array of cpu pictures*/
	int width, height;			/*size of cpu picture*/
	int units;				/*number of cpus in network*/
	int nt, base, off;			/*number in each state*/
	hardware computers[MAX_COMPUTERS];	/*array of cpu info*/
} network;

typedef struct{				/**global structure of all bills**/
	list in, at, out, dying;	/*lists of monsters in different states*/
	int width, height, awidth, aheight;
	int on_screen, off_screen;
	Pixmap lcels[WALK_CELS], rcels[WALK_CELS], acels[AT_CELS], dcels[DEATH_CELS];
	Pixmap lmask[WALK_CELS], rmask[WALK_CELS], amask[AT_CELS], dmask[DEATH_CELS];
	GC lcontexts[WALK_CELS], rcontexts[WALK_CELS], acontexts[AT_CELS], dcontexts[DEATH_CELS];
} horde;	

typedef struct{
	int width, height;	/* size of OS picture*/
	Pixmap os[NUM_OS+1];	/* array of OS pictures*/
	Pixmap cursor[NUM_OS+1];	/* array of OS cursors (drag and drop) */
	list strays;		/* list of dropped OSes */
	node *grabbed;		/* the OS held, if there is one */
} library;

typedef struct {
	char name[21];
	int level;
	int score;
} scorelist;

#define RAND(lb, ub) (rand()%(ub-lb+1)+lb)
#define MAX(x,y) (x>y ? x : y)
#define MIN(x,y) (x>y ? y : x)

#define INTERSECT(x1, y1, w1, h1, x2, y2, w2, h2) \
	(((x2-x1<=w1 && x2-x1>=0) || (x1-x2<=w2 && x1-x2>=0)) \
		&& ((y2-y1<=h1 && y2-y1>=0) || (y1-y2<=h2 && y1-y2>=0)))

#define bills_on(level) MIN(8+3*level, 100)
#define computers_on(level) MIN(8+level, 14)
#define max_bills_at_once(level) MIN(2+level/2, 12)
#define between_bills(level) MAX(14-level/2, 8)
#define step_size(level) MIN(14+level, 20)

#ifdef DEBUG
#define DPRINTF(str) printf(str)
#else
#define DPRINTF(str) 
#endif

void insert (data_ptr d, list *root);
void delete (node *n, list *root);
void move (node *n, list *src, list *dest);
void init (list *l);
void destroy (list *l);
int empty (list l);
int count (list l);

void warp_to_level (int lev);
void recalc_high_scores (char *str);

void hit_monster(Widget w, horde *bill, XButtonEvent *event);
void drop_os(Widget w, library *systems, XButtonEvent *event);
void leave_window(Widget w, XtPointer client_data, XEvent *event);
void enter_window(Widget w, XtPointer client_data, XEvent *event);
void redraw_window(Widget w, XtPointer client_data, XEvent *event);
void print_debug_info(Widget w, XtPointer client_data, XKeyEvent *event);

void new_game (Widget w, XtPointer client_data, XtPointer call_data);
void quit_game (Widget w, XtPointer call_data, XtPointer client_data);
void level_callback (Widget w, XtPointer call_data, XtPointer client_data);
void popup (Widget w, Widget *box, XtPointer client_data);
void popdown (Widget w, XtPointer call_data, XtPointer client_data);
void update_all(XtPointer client_data, XtIntervalId *timer_id);

void warp_apply (Widget w, Widget text, XtPointer client_data);
void enter_name (Widget w, Widget text, XtPointer client_data);

#endif
