# include "robots.h"

/*
 * score.c: All the scoring code is in here.
 */

struct scorefile {
	int	s_uid;
	long	s_score;
	char	s_name[MAXSTR];
	bool	s_eaten;
	int	s_level;
	bool    s_hsew;
	bool    s_vsew;
	bool    s_wimpy;
	int	s_days;
};

# define FILE_SIZE	(NUMSCORES*sizeof(struct scorefile))

scoring(eaten)
	bool eaten;
{
	static char buf[MAXSTR];
        toral = hsew && vsew;
	(void) sprintf(buf,"for this %s",TEMP_NAME);
	if( record_score(eaten,toral?T_TMP_FILE:TMP_FILE,TEMP_DAYS,buf)
            || show_highscore) {
		printf("[Press return to continue]");
		fflush(stdout);
		gets(buf);
	}
	record_score(eaten,toral?T_HOF_FILE:HOF_FILE,0,"of All Time");
}

# define	sigbit(x)	(1 << ((x) - 1))

record_score(eaten,fname,max_days,type_str)
	bool eaten;
	char *fname;
	int max_days;
	char *type_str;
{
	int value;
	int fd;
	int omask;

	/* block signals while recording the score
	 * hope this routine doesn't get stuck!
	 */
# ifndef BSD42
# ifdef TURBOC /* rfs */
	void
#elif linux
        void
# else
	int
# endif
	     (*oint)(), (*oterm)(), (*ohup)();

	oint = signal(SIGINT, SIG_IGN);
	oterm = signal(SIGTERM, SIG_IGN);
# ifndef TURBOC /* rfs */
	ohup = signal(SIGHUP, SIG_IGN);
# endif
# else
	omask = sigblock( sigbit(SIGINT) | sigbit(SIGTERM) | sigbit(SIGHUP)
			| sigbit(SIGTSTP));
# endif

	if((fd = lk_open(fname,
# ifdef TURBOC /* rfs */
				O_RDWR | O_CREAT | O_BINARY
# else
				2
# endif
					)) < 0) {
		perror(fname);
	} else {
		value = do_score(eaten,fd,max_days,type_str);
		lk_close(fd, fname);
	}
# ifdef BSD42
	(void) sigsetmask(omask);
# else
	(void) signal(SIGINT, oint);
	(void) signal(SIGTERM, oterm);
# ifndef TURBOC /* rfs */
	(void) signal(SIGHUP, ohup);
# endif
# endif
	return value;
}

do_score(eaten,fd,max_days,type_str)
	bool eaten;
	int fd, max_days;
	char *type_str;
{
	register struct scorefile *position;
	register int x;
/*	register struct scorefile *remove, *sfile, *eof; */ /* rfs */
	register struct scorefile *remove, *eof; /* rfs */
	static struct scorefile *sfile=NULL; /* rfs */
	struct scorefile *oldest, *this;
	int uid, this_day, limit;

	this_day = max_days ? time((time_t *)0)/SECSPERDAY : 0;
	limit = this_day-max_days;
	if (sfile==NULL) /* rfs */
	sfile = (struct scorefile *)(malloc(FILE_SIZE));
	if( sfile == NULL)
	{
		fprintf( stderr, "Out of memory so no scoring");
		return FALSE;
	}
	eof = &sfile[NUMSCORES];
	this = 0;
	for(position = sfile; position < eof; position++) {
		position->s_score = 0;
		position->s_days = 0;
	}
	read(fd, (char *)sfile,FILE_SIZE);
	remove = 0;
	if(score > 0) {
		uid = getuid();
		oldest = 0;
		x = limit;
		for(position = eof-1; position >= sfile; position--) {
			if(position->s_days < x) {
				x = position->s_days;
				oldest = position;
			}
		}
		position = 0;
		for(remove = sfile; remove < eof; remove++) {
			if(position == 0 && score > remove->s_score) position = remove;
# ifndef ALLSCORES
			if(remove->s_uid == uid) break;
# endif ALLSCORES
		}
		if(remove < eof) {
			if(position == 0 && remove->s_days < limit) position = remove;
		} else if(oldest) {
			remove = oldest;
			if(position == 0) {
				position = eof-1;
			} else if(remove < position) {
				position--;
			}
		} else if(position) {
			remove = eof-1;
		}
		if(position) {
			if(remove < position) {
				while(remove < position) {
					*remove = *(remove+1);
					remove++;
				}
			} else {
				while(remove > position) {
					*remove = *(remove-1);
					remove--;
				}
			}
			position->s_score = score;
			(void) strncpy(position->s_name,whoami,MAXSTR);
			position->s_eaten = eaten;
			position->s_level = LEVEL;
			position->s_uid = uid;
			position->s_hsew = hsew;
			position->s_vsew = vsew;
			position->s_wimpy = wimpy;
			position->s_days = this_day;
			this = position;
			if(lseek(fd,0L,0) == -1L ||
				write(fd,(char *)sfile,FILE_SIZE) != FILE_SIZE)
				perror("scorefile");
			close(fd);
		}
	}
	if( show_highscore || this )
	{
		printf(
# ifdef ALLSCORES
			"\nTop %s %s Scores %s:\n",
# else ALLSCORES
			"\nTop %s %s Robotists %s:\n",
# endif ALLSCORES
			NUMNAME,
                        toral?"Toral":"Non-Toral",
			type_str
		);
		printf("Rank     Score    Name\n");
		for(position = sfile; position < eof; position++) {
			if(position->s_score == 0) break;
			if(position == this)
				putchar('>');
			else  putchar(' ');
			printf(
			       "%c%2d %10ld  %8s: %s on %6s",
			       position->s_days < limit ? '*' : ' ',
			       position-sfile+1,
			       position->s_score,
			       position->s_name,
			       position->s_eaten ?
			         "robot food" : "ducked out",
			       position->s_wimpy ? "wimpy" : "studly");
			if(position->s_hsew)
			  printf( " %7s",
				 (position->s_vsew) ? "toral" : "annular");
			else
			  printf( " %7s",
				 (position->s_vsew) ? "annular" : "planar");
			printf(" level %d.", position->s_level);

			if(position == this)
				putchar('<');
			putchar('\n');
		}
	}
	return (this != 0);
}

scorer()
{
	static char tels[6];
	if(free_teleports != old_free) {
		if(free_teleports > free_per_level) {
			(void) sprintf(tels,"%d+%d",
				       free_per_level,
				       free_teleports-free_per_level);
		} else {
			(void) sprintf(tels,"%d",free_teleports);
		}
		old_free = free_teleports;
	}
	move(LINES-1,0);
	clrtoeol();
	printw("<%s> level: %d    score: %ld",tels,LEVEL,score);
        mvprintw(LINES-1,RVPOS,"heaps:%3d robots:%3d value: %d",
				scrap_heaps,nrobots_alive,robot_value);
	clrtoeol();
}

