#include <ctype.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "config.h"

#define COMPUTER_FILE	DEFAULT_LISTS "/computer"
#define MAX_LOGIN_NAME	21

char *rnames[] = {"std", "blitz", "wild", "lightning"};

typedef struct _ratings {
  int rating;
  int num;
} ratings;

typedef struct _Entry {
  char name[MAX_LOGIN_NAME];
  ratings r[4];
  int computer;
} ENTRY;

ENTRY **list;
ENTRY **sortme;

int GetPlayerInfo(char *fileName, ENTRY *e)
{
  FILE *fp;
  char line[100];
  char field[20];
  char NameWithCase[30];
  int i, done = 0;

  e->computer = 0;
  for (i = 0; i < 4; i++) {
    e->r[i].num = 0;
    e->r[i].rating = 0;
  }

  fp = fopen(fileName, "r");
  fgets(line, 99, fp);
  if (feof(fp))
    return(0);
  if (!strcmp(line, "v 1\n")) {
    fgets(line, 99, fp);
    sscanf(line, "%s", e->name);
    fgets(line, 99, fp);
    fgets(line, 99, fp);
    fgets(line, 99, fp);
    if (fscanf(fp, "%u %*u %*u %*u %u %*u %*u %*u %*u %u %*u %*u %*u %u %*u %*u %*u %*u %u %*u %*u %*u %u %*u %*u %*u %*u %u %*u %*u %*u %u %*u %*u %*u %*u", &(e->r[0].num), &(e->r[0].rating), &(e->r[1].num), &(e->r[1].rating), &(e->r[2].num), &(e->r[2].rating), &(e->r[3].num), &(e->r[3].rating)) != 8)
      fprintf(stderr, "OOPS: couldn't parse player file %s.\n", fileName);
  } else do {
    sscanf(line, "%s", field);
    if (!strcmp(field, "Name:")) {
      sscanf(line, "%*s %s", NameWithCase);
      if (strcasecmp(e->name, NameWithCase))
        printf("TROUBLE: %s's handle is listed as %s.\n",
	       e->name, NameWithCase);
      else
        strcpy(e->name, NameWithCase);
    } else if (!strcmp(field, "S_NUM:")) {
      sscanf(line, "%*s %d", &(e->r[0].num));
    } else if (!strcmp(field, "B_NUM:")) {
      sscanf(line, "%*s %d", &(e->r[1].num));
    } else if (!strcmp(field, "W_NUM:")) {
      sscanf(line, "%*s %d", &(e->r[2].num));
    } else if (!strcmp(field, "L_NUM:")) {
      sscanf(line, "%*s %d", &(e->r[3].num));
    } else if (!strcmp(field, "S_RATING:")) {
      sscanf(line, "%*s %d", &(e->r[0].rating));
    } else if (!strcmp(field, "B_RATING:")) {
      sscanf(line, "%*s %d", &(e->r[1].rating));
    } else if (!strcmp(field, "W_RATING:")) {
      sscanf(line, "%*s %d", &(e->r[2].rating));
    } else if (!strcmp(field, "L_RATING:")) {
      sscanf(line, "%*s %d", &(e->r[3].rating));
    } else if (!strcmp(field, "Network:")) {
      done = 1;
    }
    fgets(line, 99, fp);
  } while (!done && !feof(fp));
  fclose(fp);
  return (1);
}

int LoadEntries(void)
{
  int listsize;
  FILE *fpPlayerList;
  char letter1;
  char command[90];
  char pathInput[80];
  ENTRY e;
  int len, n = 0;

  listsize = 100;
  list = malloc(sizeof(ENTRY *)*listsize);

  for (letter1 = 'a'; letter1 <= 'z'; letter1++) {
    printf("Loading %c's.\n", letter1);
    sprintf(pathInput, "%s/%c", DEFAULT_PLAYERS, letter1);
    sprintf(command, "ls -1 %s", pathInput);
    fpPlayerList = popen(command, "r");
    if (fpPlayerList == NULL)
      continue;
    while (1) {
      fgets(e.name, MAX_LOGIN_NAME, fpPlayerList);
      if (feof(fpPlayerList))
	break;
      len = strlen(e.name);
      e.name[len - 1] = '\0';
      if (e.name[0] != letter1)
	printf("File %c/%s:  wrong directory.\n", letter1, e.name);
      else {
	sprintf(pathInput, "%s/%c/%s", DEFAULT_PLAYERS, letter1, e.name);
	if (GetPlayerInfo(pathInput, &e)) {
	  if ((list[n] = malloc(sizeof(ENTRY))) == NULL) {
	    fprintf(stderr, "malloc() failed!\n");
	  } else {
	    memcpy(list[n], &e, sizeof(ENTRY));
	    n++;
	    if (n == listsize) {
	      listsize += 100;
	      list = realloc(list, listsize*sizeof(ENTRY *));
	    }
	  }
	}
      }
    }
    pclose(fpPlayerList);
  }
  return (n);
}

int SetComputers(int n)
{
  FILE *fpComp;
  int i = 0;
  char line[100], comp[30];

  sprintf(line, "sort -f %s", COMPUTER_FILE);
  fpComp = popen(line, "r");
  if (fpComp == NULL)
    return 0;
  while (i < n) {
    fgets(comp, 29, fpComp);
    if (feof(fpComp))
      break;
    comp[strlen(comp) - 1] = '\0';

    while (i < n && strcasecmp(list[i]->name, comp) < 0)
      i++;

    if (i < n && strcasecmp(list[i]->name, comp) == 0) {
      list[i++]->computer = 1;
    }
  }
  pclose(fpComp);
  return(1);
}

int rtype;

static int
sortfunc(const void *i, const void *j)
{
	int n =	(*(ENTRY **)j)->r[rtype].rating -
		(*(ENTRY **)i)->r[rtype].rating;

	return n ? n : strcasecmp((*(ENTRY **)i)->name, (*(ENTRY **)j)->name);
}

static void
makerank(void)
{
	FILE	*fp;
	char	 fName[200];
	int	 sortnum, sortmesize, i, n;

	printf("Loading players\n");
	n = LoadEntries();
	printf("Found %d players.\n", n);
	printf("Setting computers.\n");
	SetComputers(n);

	for (rtype = 0; rtype < 4; rtype++) {
		sortnum		= 0;
		sortmesize	= 100;
		sortme		= malloc(sizeof(ENTRY *) * sortmesize);

		for (i = 0; i < n; i++) {
			if (list[i]->r[rtype].rating) {
				sortme[sortnum++] = list[i];

				if (sortnum == sortmesize) {
					sortmesize += 100;
					sortme = realloc(sortme, sortmesize *
					    sizeof(ENTRY *));
				}
			}
		}

		printf("Sorting %d %s.\n", sortnum, rnames[rtype]);
		qsort(sortme, sortnum, sizeof(ENTRY *), sortfunc);

		printf("Saving to file.\n");
		sprintf(fName, "%s/rank.%s", DEFAULT_STATS, rnames[rtype]);

		if ((fp = fopen(fName, "w")) == NULL)
			err(1, "%s: fopen", __func__);

		for (i = 0; i < sortnum; i++) {
			fprintf(fp, "%s %d %d %d\n",
			    sortme[i]->name,
			    sortme[i]->r[rtype].rating,
			    sortme[i]->r[rtype].num,
			    sortme[i]->computer);
		}
		fclose(fp);
		free(sortme);
	}
}

int
main(int argc, char **argv)
{
	if (argc > 1) {
		fprintf(stderr, "usage: %s.\n", argv[0]);
		return EXIT_FAILURE;
	}

	makerank();
	return EXIT_SUCCESS;
}