#ifndef _MAIN_C
#define _MAIN_C

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <signal.h>
#include <string.h>
#include "kernel.h"
#include "swis.h"

#include "WoumInclude:lib/screen.h"
#include "WoumInclude:lib/keyboard.h"

#include "car.h"
#include "game.h"
#include "level.h"
#include "message.h"

static void escape(int i)
{
	screen_setbank(1);
	screen_getdata();
	screen_cls();
	printf("Escape\n");
	while (keyboard_scan(0) != KEY_NONE) {};
	keyboard_flush();
	exit(0);
}

char **getfiles(char *dir,int *n)
{
	/* Get list of files in a directory */
	_kernel_swi_regs regs;
	char *buf,**index;
	int i;
	buf = malloc(65536); /* Cheat! */
	regs.r[0] = 9;
	regs.r[1] = (int) dir;
	regs.r[2] = (int) buf;
	regs.r[3] = 1000;
	regs.r[4] = 0;
	regs.r[5] = 65536;
	regs.r[6] = 0;
	_kernel_swi(OS_GBPB,&regs,&regs);
	index = malloc(regs.r[3]*4);
	*n = regs.r[3];
	for (i=0;i<*n;i++)
	{
		index[i] = buf;
		while (*buf)
			buf++;
		buf++;
	}
	return index;
}

typedef struct {
	char **items; /* Menu items */
	int nitems;
	gp_font *f; /* Font to display in */
	gp_font *fs; /* Font for selected item (same size, different colour) */
	int ofs; /* Scroll offset */
	int i; /* Current item */
} menu;

void show_menu(gp_screen *scr,menu *m,int center)
{
	int y,i,l;
	gp_font *f;
	y = -m->ofs;
	for (i=0;(i<m->nitems) && (y<scr->height);i++) {
		if (y > -m->f->height) {
			l = strlen(m->items[i]);
			if (m->i == i)
				f = m->fs;
			else
				f = m->f;
			if (center)
				gp_font_puts(f,m->items[i],l,scr,(scr->width-f->width*l)/2,y);
			else
				gp_font_puts(f,m->items[i],l,scr,0,y);
		}
		y+=m->f->height;
	}
}

void menu_offset(gp_screen *scr,menu *m)
{
	if (m->i < 0)
		m->i = 0;
	else if (m->i >= m->nitems)
		m->i = m->nitems-1;
	m->ofs = -scr->height/2+m->i*m->f->height;
	if (-m->ofs+m->f->height*m->nitems < scr->height)
		m->ofs = m->f->height*m->nitems-scr->height;
	if (m->ofs < 0)
		m->ofs = 0;
}

int do_menu(menu *m,char *title,gp_font *f,int center,gp_spr *back,int bgcol)
{
	_kernel_swi_regs regs;
	gp_screen *s;
	int k;
	regs.r[0] = 4;
	regs.r[1] = 1;
	_kernel_swi(OS_Byte,&regs,&regs); /* Turn off cursor editing */
	keyboard_flush();
	do {
		screen_getdata();
		s = gp_screen_new_fromvdu();
		if (back != 0)
			(back->f->plot)(back,0,0,s);
		else
			gp_screen_rect(s,0,s->width-1,0,s->height-1,2,bgcol);
		gp_font_puts(f,title,strlen(title),s,(s->width-strlen(title)*f->width)/2,s->height/8);
		gp_screen_crop(s,s->width/8,s->height/4,s->width*6/8,s->height*3/4);
		show_menu(s,m,center);
		screen_swap();
		do {
			k = keyboard_read();
			if (k == 143) {
				m->i--;
				menu_offset(s,m);
			} else if (k == 142) {
				m->i++;
				menu_offset(s,m);
			} else if ((k == 13) || (k == 32))
				return 13;
			else if (k != -1)
				return k;
		} while (k == -1);
		free(s);
	} while (1);
}

int choosetrack(char **tracklist,int numtracks,int trackid)
{
	menu m;
	m.items = tracklist;
	m.nitems = numtracks;
	m.f = font_yellow;
	m.fs = font_red;
	m.i = trackid;
	m.ofs = 0;
	screen_setvdu(1); screen_setdisplay(2);
	do_menu(&m,"Select track",font_blue,1,0,0x400000);
	return m.i;
}

int choosecars(char **carlist,int numcars,int carid)
{
	menu m;
	m.items = carlist;
	m.nitems = numcars;
	m.f = font_yellow;
	m.fs = font_red;
	m.i = carid;
	m.ofs = 0;
	screen_setvdu(1); screen_setdisplay(2);
	do_menu(&m,"Select cars",font_blue,1,0,0x400000);
	return m.i;
}

void chooselaps()
{
	menu m;
	char *items[10];
	char text[21];
	int i;
	for (i=0;i<10;i++)
	{
		items[i] = text+i*2;
		sprintf(text+i*2,"%d",i+1);
	}
	m.items = items;
	m.nitems = 10;
	m.f = font_yellow;
	m.fs = font_red;
	m.i = num_laps-1;
	m.ofs = 0;
	screen_setvdu(1); screen_setdisplay(2);
	do_menu(&m,"Select number of laps",font_blue,1,0,0x400000);
	num_laps = m.i+1;
}

int chooseopp(int carsinrace)
{
	menu m;
	char *items[MAX_CAR];
	char text[MAX_CAR*3];
	int i;
	for (i=0;i<MAX_CAR;i++)
	{
		items[i] = text+i*3;
		sprintf(text+i*3,"%d",i);
	}
	m.items = items;
	m.nitems = MAX_CAR;
	m.f = font_yellow;
	m.fs = font_red;
	m.i = carsinrace-1;
	m.ofs = 0;
	screen_setvdu(1); screen_setdisplay(2);
	do_menu(&m,"Select number of opponents",font_blue,1,0,0x400000);
	return m.i+1;
}

char ths[4][3] = {"st","nd","rd","th"};

#define MIN(a,b) ((a)<(b)?(a):(b))
#define MAX(a,b) ((a)>(b)?(a):(b))

int main(int argc,char **argv)
{
	level *l;
	int c,t,frametime,frames;
	_kernel_swi_regs regs;
	gp_screen *s;
	char **tracklist,**carlist;
	int numtracks,numcars;
	int trackid,carid;
	char tempstr[256];
	menu *m;
	int msg,msg_time,stage;
	char mstr[4][256];
	int carsinrace,endtime,i;
	int results[MAX_CAR];
	screen_oldmode(13);
	screen_getdata();
	if (screen.num_banks < 2)
		screen_createbanks(2);
	signal(SIGINT,escape);
	if (init_messages())
		return 1;
	/* do menus */
	tracklist = getfiles("<Micron$Dir>.tracks",&numtracks);
	carlist = getfiles("<Micron$Dir>.cars",&numcars);
	trackid = 0;
	carid = 0;
	num_laps = 5;
	carsinrace = 8;
	screen_setvdu(1);
	screen_setdisplay(2);
	_kernel_swi(OS_RemoveCursors,&regs,&regs);
	m = malloc(sizeof(menu));
	m->items = malloc(4*6);
	m->items[0] = mstr[0];
	m->items[1] = mstr[1];
	m->items[2] = mstr[2];
	m->items[3] = mstr[3];
	m->items[4] = "Race";
	m->items[5] = "Quit";
	m->nitems = 6;
	m->f = font_yellow;
	m->fs = font_red;
	m->i = m->ofs = 0;
	do {
	l = 0;
	screen_setvdu(1); screen_setdisplay(2);
	do {
		sprintf(mstr[0],"Track:     %s",tracklist[trackid]);
		sprintf(mstr[1],"Cars:      %s",carlist[carid]);
		sprintf(mstr[2],"Laps:      %d",num_laps);
		sprintf(mstr[3],"Opponents: %d",carsinrace-1);
		c = do_menu(m,"Micron Machines",font_blue,0,0,0x400000);
		if (c == 13) switch (m->i) {
		case 0:
			trackid = choosetrack(tracklist,numtracks,trackid); break;
		case 1:
			carid = choosecars(carlist,numcars,carid); break;
		case 2:
			chooselaps(); break;
		case 3:
			carsinrace = chooseopp(carsinrace); break;
		case 4:
			screen_setbank(0);
			screen_getdata();
			screen_cls();
			sprintf(tempstr,"<Micron$Dir>.tracks.%s",tracklist[trackid]);
			l = load_level(tempstr);
			if (l != 0) {
				sprintf(tempstr,"<Micron$Dir>.cars.%s",carlist[carid]);
				if (init_cars(l,tempstr) != 0) {
					kill_level(l);
					l = 0;
				}
			}
			if (l == 0) {
				screen_setvdu(1);
				screen_setdisplay(2);
			}
			break;
		case 5:
			screen_setbank(1);
			screen_getdata();
			screen_cls();
			while (keyboard_scan(0) != KEY_NONE) {};
			keyboard_flush();
			return 0;
		} else if (c == 140) switch (m->i) {
		case 0:
			if (trackid > 0) trackid--; break;
		case 1:
			if (carid > 0) carid--; break;
		case 2:
			if (num_laps > 1) num_laps--; break;
		case 3:
			if (carsinrace > 1) carsinrace--; break;
		} else if (c == 141) switch (m->i) {
		case 0:
			if (trackid < numtracks-1) trackid++; break;
		case 1:
			if (carid < numcars-1) carid++; break;
		case 2:
			if (num_laps < 10) num_laps++; break;
		case 3:
			if (carsinrace < 10) carsinrace++; break;
		}
		if ((m->i < 4) && (c == 13))
			m->i++;
	} while (l == 0);
	/* Start game */
	cars[0].player = 1;
	for (c=1;c<carsinrace;c++)
		cars[c].player = -1;
	for (c=carsinrace;c<MAX_CAR;c++)
		cars[c].player = 0;
	/* Run game */
	screen_setvdu(1);
	screen_setdisplay(2);
	screen_getdata();
	t = clock(); /* Time of last frame */
	gametime = -300; /* Time into race */
	msg = MSG_3;
	msg_time = gametime+100;
	stage=0; /* 0=start, 1=race, 2=end, 3=end race */
	frames=0;
	endtime=0;
	do {
		do {
			if (keyboard_ispressed(KEY_ESC))
				escape(0);
			frametime = clock()-t;
		} while (frametime == 0);
			t += frametime;
			gametime += frametime;
		s = gp_screen_new_fromvdu();
		draw_level(l,s,cars[0].x >> 16,cars[0].y >> 16);
		if (stage > 0) {
			for (c=0;c<MAX_CAR;c++)
				if (cars[c].player > 0)
					game_runcar(l,c,player_keys(l,c),frametime);
				else if (cars[c].player < 0)
					game_runcar(l,c,ai_keys(l,c),frametime);
		}
		draw_cars(l,s,cars[0].x >> 16,cars[0].y >> 16);
		if (stage == 0)
		{
			if (msg_time < gametime) {
				msg_time += 100;
				msg++; /* 3->2->1->go */
			}
			if (msg == MSG_GO)
				stage++;
		}
		else if ((stage == 1) && (cars[0].check_time == gametime))
		{
			/* Work out message & time */
			if (cars[0].check)
				msg = MSG_CHECK;
			else if (cars[0].lap == num_laps) {
				msg = MSG_COMPLETE;
				stage++;
			} else if (cars[0].lap == num_laps-1)
				msg = MSG_LASTLAP;
			else
				msg = MSG_LAP;
			msg_time = gametime+200;
		}
		else if (stage == 2)
		{
			msg = MSG_COMPLETE;
			msg_time = gametime+200;
		}
		if (msg_time > gametime)
			plotmessage(msg,s);
		/* Check race end rules */
/*		i=0;
		for (c=0;c<MAX_CAR;c++)
			if (cars[c].lap == num_laps)
				i++;
		if ((i == carsinrace) && ((endtime == 0) || (endtime > gametime+500)))
			endtime = gametime+500;
		else if ((i >= 3) && ((endtime == 0) || (endtime > gametime+500)))
			endtime = gametime+500;
		else*/ if ((cars[0].lap == num_laps) && (endtime == 0))
			endtime = gametime+1000;
		/* Display player status */
		if (gametime < 0)
			c = 0;
		else if ((msg == MSG_LAP) || (msg == MSG_COMPLETE))
			c = cars[0].lap_time;
		else
			c = gametime;
		sprintf(tempstr,"%02d:%02d.%02d",c/6000,(c/100) % 60,c % 100);
		if (((endtime != 0) && (gametime & 32)) || (msg == MSG_LAP) || (msg == MSG_COMPLETE))
			gp_font_puts(font_red,tempstr,strlen(tempstr),s,0,0);
		else
			gp_font_puts(font_white,tempstr,strlen(tempstr),s,0,0);
		if (cars[0].lap == num_laps)
		{
			i = ranking(0);
			sprintf(tempstr,"Result: %d%s",i,ths[MIN(i-1,3)]);
			gp_font_puts(font_white,tempstr,strlen(tempstr),s,0,font_white->height);
		}
		else
		{
			sprintf(tempstr,"Lap %d/%d",cars[0].lap+1,num_laps);
			gp_font_puts(font_white,tempstr,strlen(tempstr),s,0,font_white->height);
			sprintf(tempstr,"Check %d/%d",cars[0].check,l->highest_check);
			gp_font_puts(font_white,tempstr,strlen(tempstr),s,0,font_white->height*2);
			if (gametime > 0) {
				frames++;
				sprintf(tempstr,"%dfps",(frames*100)/gametime);
			/*	gp_font_puts(font_white,tempstr,strlen(tempstr),s,0,font_white->height*3); */
			}
		}
		/*screen_vsync();*/
		screen_swap();
		screen_getdata();
		free(s);
	} while ((endtime == 0) || (endtime > gametime));
	/* Show results */
	i=0;
	for (t=1;t<=carsinrace;t++)
		for (c=0;c<carsinrace;c++)
			if (ranking(c) == t)
				results[i++] = c;
	s = gp_screen_new_fromvdu();
	gp_screen_rect(s,0,s->width-1,0,s->height-1,2,0x400000);
	gp_font_puts(font_blue,"Race Results",12,s,(s->width-12*font_blue->width)/2,s->height/8);
	i = s->height/4;
#define R_TBL_WIDTH (car_l+font_white->width*13)
#define R_TBL_CAR ((s->width-R_TBL_WIDTH)/2)
	for (t=0;t<carsinrace;t++)
	{
		c = results[t];
		(cars[c].spr->f->plot)(cars[c].spr,R_TBL_CAR+car_l/2,i+car_w/2,s);
		if (cars[c].lap < num_laps)
			sprintf(tempstr," %d%s %d lap%c",ranking(c),ths[MIN(ranking(c)-1,3)],cars[c].lap,((cars[c].lap==1)?' ':'s'));
		else
			sprintf(tempstr," %d%s %02d:%02d.%02d",ranking(c),ths[MIN(ranking(c)-1,3)],cars[c].lap_time/6000,(cars[c].lap_time/100) % 60,cars[c].lap_time % 100);
		if (c == 0)
			gp_font_puts(font_red,tempstr,strlen(tempstr),s,R_TBL_CAR+car_l,i);
		else
			gp_font_puts(font_white,tempstr,strlen(tempstr),s,R_TBL_CAR+car_l,i);
		i += MAX(car_w,font_white->height);
	}
	screen_swap();
	screen_getdata();
	while (keyboard_scan(0) != KEY_NONE) {};
	while (keyboard_scan(0) == KEY_NONE) {};
	while (keyboard_scan(0) != KEY_NONE) {};
	/* Free race data */
	shutdown_cars();
	kill_level(l);
	l = 0;
	} while (1);
}

#endif
