#include <stdio.h>
#include <pwd.h>

#include "game.h"
#include "score.h"


static char *scorefile = SCOREFILE;
static char *lockfile = LOCKFILE;

typedef struct {
    char *pseudo;
    char *name;
    int items;
    int lives;
    int time;
    int uid;
    int active;
} Score;


static Score *scores;
static int max_scores = 10;
static int nb_scores = 0;


static int lock_scores ()
{
#define TRIES 2
    int i = 0;
    for (i=0; i<TRIES; i++) {
	int res;
	if (i>0)
	    sleep (1);
	res = mkdir (lockfile, 0400);
	if (res == 0)
	    break;
    }
    if (i == TRIES) {
	fprintf (stderr, "Couldn't lock score file.\n");
	return 0;
    }
    return 1;
}


static int unlock_scores ()
{
    int res;
    res = rmdir (lockfile);
    if (res == 0)
	return 1;
    fprintf (stderr, "Couldn't unlock score file.\n");
    return 0;
}


static void clear_scores ()
{
    int i;

    if (scores == NULL) {
	scores = (Score *) malloc (max_scores * sizeof (Score));
    }
    for (i=0; i<nb_scores; i++) {
	free (scores[i].pseudo);
	free (scores[i].name);
    }
    nb_scores = 0;
}

static void maybe_grow_scores ()
{
    if (nb_scores == max_scores) {
	max_scores *= 2;
	scores = (Score *) realloc (scores,
				    max_scores * sizeof (Score));
    }
}

static void load_scores ()
{
    FILE *file;
    char pseudo[100];
    char name[100];
    int items;
    int lives;
    int time;
    int uid;
    int active;

    file = fopen (scorefile, "r");
    clear_scores ();
    if (file != NULL) {
	while (1) {
	    if (fscanf (file, "%s %s %d %d %d %d %d",
			pseudo, name, &items,
			&lives, &time, &uid, &active) != 7)
		break;
	    maybe_grow_scores ();
	    scores[nb_scores].pseudo = (char *) malloc (strlen (pseudo) + 1);
	    strcpy (scores[nb_scores].pseudo, pseudo);
	    scores[nb_scores].name = (char *) malloc (strlen (name) + 1);
	    strcpy (scores[nb_scores].name, name);
	    scores[nb_scores].items = items;
	    scores[nb_scores].lives = lives;
	    scores[nb_scores].time = time;
	    scores[nb_scores].uid = uid;
	    scores[nb_scores].active = active;
	    nb_scores++;
	}
	fclose (file);
    }
}

static void write_sc (FILE *file,
		      char *pseudo, char *name,
		      int items, int lives, int time, int uid, int active)
{
    struct passwd *pwd;
    char buf[100];

    if (name == NULL) {
	pwd = getpwuid (getuid ());
	if (pwd != NULL)
	    name = pwd->pw_name;
	else {
	    name = "nobody";
	    pseudo = name;
	}
    }
    if (pseudo == NULL) {
	char *p;
	extern char *getenv ();

	pseudo = getenv ("NICKNAME");
	if (pseudo == NULL)
	    pseudo = getenv ("NAME");
	if (pseudo == NULL)
	    pseudo = name;
	strncpy (buf, pseudo, 90);
	buf[90] = '\0';
	pseudo = buf;
	for (p = buf; *p; p++) {
	    if (*p == ' ' || *p == '\t' || *p == '\n') {
		*p = '_';
		break;
	    }
	}
    }
    fprintf (file, "%s %s %d %d %d %d %d\n",
	     pseudo, name, items, lives, time, uid, active);
}


void save_score (int items, int lives, int time, int flag)
{
#define MAXNB 1000
    FILE *file;
    extern int debugging;

/*    if (debugging)
	return;*/
    if (items <= 1 && flag != SCORE_REMOVE)
	return;
    if (!lock_scores ())
	return;
    load_scores ();
    file = fopen (scorefile, "w");
    if (file != NULL) {
	int i;
	int myuid = getuid ();
	int written = (flag == SCORE_REMOVE);

	for (i=0; i<((nb_scores<MAXNB)?nb_scores:MAXNB); i++) {
	    if (!written) {
		if (items > scores[i].items
		    || (items == scores[i].items
			&& (lives > scores[i].lives
			    || (lives == scores[i].lives
				&& time < scores[i].time)))) {
		    write_sc (file, NULL, NULL, items,
			      lives, time, myuid, flag == SCORE_ACTIVE);
		    written = 1;
		}
	    }
	    if (scores[i].uid != myuid || !scores[i].active)
		write_sc (file,
			  scores[i].pseudo, scores[i].name,
			  scores[i].items, scores[i].lives,
			  scores[i].time, scores[i].uid,
			  scores[i].active);
	}
	if (!written)
	    write_sc (file, NULL, NULL, items, lives, time, myuid,
		      flag == SCORE_ACTIVE);
	fclose (file);
    }
    unlock_scores ();
}

void print_scores (int all)
{
    char buf[100];
    char buf2[30];
    int i;

    load_scores ();
    printf ("                           items    time\n");
    for (i=0; i<(all?nb_scores:(nb_scores<10?nb_scores:10)); i++) {
	int t = scores[i].time;
	int items = scores[i].items;

	sprintf (buf, "(%s)", scores[i].name);
	if (items > WIN_ITEMS)
	    sprintf (buf2, "WINNER");
	else if (scores[i].active)
	    sprintf (buf2, "(%d live%s)", scores[i].lives,
		     (scores[i].lives > 1) ? "s" : "");
	else
	    *buf2 = '\0';
	printf ("%-10s %15s  %3d   %02d:%02d:%02d  %s\n",
		buf,
		scores[i].pseudo,
		(items > WIN_ITEMS) ? WIN_ITEMS : items,
		t/3600, (t/60)%60, t%60,
		buf2);
    }
}
