/* xtmines: game where you try to cross a minefield */
/* hiscore.c: */
/* Written by Timothy Tsai  April 13, 1992 */

#include <sys/file.h>
#ifdef SVR4
#include <fcntl.h>
#endif
#include <pwd.h>
#include <time.h>
#include "xtmines.h"

#define MAXSCORES		10
#define MAX_ANGEL_STARTS	5
#ifndef HISCORE_FILENAME
#define HISCORE_FILENAME	"/home/bach3/ttsai/games/xtmines/xtmines.hiscores"
#endif

typedef struct {
	int		uid, score;
	ranktype	final_level,start_level;
	long		timestamp;
} score_t;

void show_final_score()
{
	printf("Your final score was %d\n",num_score);
	printf("Your final rank was %s\n",num_rank_to_words(level));
}

int add_hiscore()
{
	int	fd;
	score_t
		current, last, mine;
	int	occ = 0;		/* num times current user */
					/*    is on hiscore list  */
	int	angelocc = 0;		/* num times current user is on list */
					/*    and started on level angel */
	int	trickle = FALSE;
	int	myuid;
	int	added = FALSE;		/* current score added yet? */

	myuid = getuid();	/* current user's uid */
	mine.uid = myuid;
	mine.score = num_score;
	mine.final_level = level;
	mine.start_level = start_level;
	mine.timestamp = time(0);

	if ((fd=open(HISCORE_FILENAME,O_RDWR,0666)) < 0) {
	   if ((fd=open(HISCORE_FILENAME,O_CREAT|O_WRONLY,0666)) < 0) {
		fprintf(stderr,"Error: Can't open %s\n",HISCORE_FILENAME);
		exit(5);
	   }
	   write(fd, (char *) &mine, sizeof(score_t));
	   close(fd);
	   return(0);
	}


	while (read(fd,(char *) &current,sizeof(score_t))==sizeof(score_t)) {
		if ((!added) && (num_score > current.score) &&
		    ((angelocc < MAX_ANGEL_STARTS) ||
		     (angelocc == MAX_ANGEL_STARTS) && (start_level != angel))){
		/* add to hiscore list */
			last = mine;
			trickle = TRUE;
			added = TRUE;
			occ++;
			if (mine.start_level == angel) angelocc++;
		}
		if (trickle) {
			lseek(fd, (long) -sizeof(score_t), SEEK_CUR);
			write(fd, (char *) &last, sizeof(score_t));
			last = current;
			if (myuid == current.uid) {
				occ++;
				if (current.start_level == angel) angelocc++;
				if ((occ > MAXSCORES) ||
				    ((angelocc > MAX_ANGEL_STARTS) &&
				     (mine.start_level == angel))) {
					trickle = FALSE;
					if (occ > MAXSCORES) break;
				}
			}
		}
		else {
			if (myuid == current.uid) {
				occ++;
				if (current.start_level == angel) angelocc++;
				if (occ == MAXSCORES)
					break;
			}
		}
	}
	if (trickle)
		write(fd, (char *) &last, sizeof(score_t));
	if ((!added) && (occ < MAXSCORES) && (angelocc < MAX_ANGEL_STARTS))
		write(fd, (char *) &mine, sizeof(score_t));
	close(fd);
}

#define LINE_SEP	2	/* separation between lines in hswind */
#define LEFT_MARGIN	3	/* pixel sep from left edge of hswind */
int show_hiscores(dox)
int dox;	/* boolean:  do Xwindow show or just text */
{
	int	fd;
	int	lastuid = -1;
	int	i = 0;
	score_t	curscore;
	int	pcount = MAXSCORES;
	int	myuid;
	struct passwd *user;
	char	*name;
	int	lines=0,width,height;
	Window	hswind;		/* high score window */
	char	str[MAXSTRLEN];
	int	px=LEFT_MARGIN,	/* pixel positions for next line */
		py=fontmh;
	XEvent                  event;
	XButtonPressedEvent     *eventbp;
	XKeyPressedEvent        *eventkp;
	int                     wait = TRUE;

	if ((fd=open(HISCORE_FILENAME,O_RDONLY,0666)) < 0) {
		fprintf(stderr,"Error: Can't open %s\n",HISCORE_FILENAME);
		exit(5);
	}

	myuid = getuid();
	printf("Rank User          Score Final level  Start level  Time\n");
	lines++;

	while (read(fd,(char *)&curscore,sizeof(score_t)) == sizeof(score_t)) {
		i++;
		if (pcount || curscore.uid == myuid) {
			if (lastuid != curscore.uid) {
				user = getpwuid(curscore.uid);
				lastuid = curscore.uid;
			}
			name = user->pw_name;
			/* no \n is needed because ctime puts one there */
			printf("%4d %-9s %9d %-11s  %-11s  %24s",
				i,name,curscore.score,
				num_rank_to_words(curscore.final_level),
				((curscore.start_level<grunt) ||
				 (curscore.start_level>god)) ?
				" " : num_rank_to_words(curscore.start_level),
				ctime(&curscore.timestamp));
			lines++;
			if (pcount) pcount--;
		}
	}
	close(fd);
	printf("There are %d scores to date\n", i);
	lines++;

	if (dox == NOX)
		return(SUCCESS);

	/* create new window */
	lastuid = -1;
	i = 0;
	pcount = MAXSCORES;
	width = fontmw*40;
	height = (fontmh+LINE_SEP)*(lines+1);
	hswind = XCreateSimpleWindow(disp,frame,(w-width)/2,(h-height)/2,
		width,height,bw,black,white);
	XSelectInput(disp,hswind,KeyPressMask|ButtonPressMask);
	XMapRaised(disp,hswind);
	XSetForeground(disp,gct,color[font_color].pixel);
	XSetBackground(disp,gct,color[background_color].pixel);
	XFlush(disp);

	/* print in new window */
	if ((fd=open(HISCORE_FILENAME,O_RDONLY,0666)) < 0) {
		fprintf(stderr,"Error: Can't open %s\n",HISCORE_FILENAME);
		exit(5);
	}
	sprintf(str,"Rank User          Score  Level");
	XDrawImageString(disp,hswind,gct,px,py,str,strlen(str));
	XFlush(disp);
	py += (fontmh + LINE_SEP);
	while (read(fd,(char *)&curscore,sizeof(score_t)) == sizeof(score_t)){
		i++;
		if (pcount || curscore.uid == myuid) {
			if (lastuid != curscore.uid) {
				user = getpwuid(curscore.uid);
				lastuid = curscore.uid;
			}
			name = user->pw_name;
			sprintf(str,"%4d %-9s %9d %s",i,name,curscore.score,
				num_rank_to_words(curscore.final_level));
			XDrawImageString(disp,hswind,gct,px,py,
				str,strlen(str));
			XFlush(disp);
			py += (fontmh + LINE_SEP);
			if (pcount) pcount--;
		}
	}
	close(fd);
	sprintf(str,"There are %d scores to date", i);
	XDrawImageString(disp,hswind,gct,px,py,str,strlen(str));
	py += (fontmh + LINE_SEP);
	sprintf(str,"Press key or click button to end");
	XDrawImageString(disp,hswind,gct,px,py,str,strlen(str));
	XFlush(disp);

	/* Wait for keypress or button click */
	while (wait == TRUE) {
	   while (!XPending(disp))
		usleep(XPENDING_UDELAY);
	   XNextEvent(disp,&event);
	   if (event.type==ButtonPress) {
		eventbp = (XButtonPressedEvent *) &event;
		if ((eventbp->window == hswind) ||
		    (eventbp->window == field) ||
		    (eventbp->window == wind[quit_wind]))
	                wait = FALSE;
	   }
	   else if (event.type == KeyPress) {
		eventkp = (XKeyPressedEvent *) &event;
		if ((eventkp->window == hswind) ||
		    (eventkp->window == field))
			wait = FALSE;
	   }
	}

	return (SUCCESS);
}

void show_and_add_scores()
{
	show_final_score();
	add_hiscore();
	show_hiscores(DOX);
	exit(SUCCESS);
}
