/*   C PROGRAM TO CALCULATE SUM ERROR SQUARED FOR
        JWB AND PERFORMANCE RATINGS
 */

#include <stdio.h>
#include <string.h>
#include <math.h>

struct TEAM {
    char *name;             /* team name */
    float rating;
    float JWB;
    struct TEAM *link;        /* link to next team */
} *team_list = NULL;

struct NAME {
    char *name;         /* possible team name variant */
    char *official;     /* official team name */
    struct NAME *link;  /* link to next possible name */
} *name_list = NULL;

char save_line[80];     /* orginal input line for error message */
long int ngames;        /* number of games */
char date[80];          /* a date line from games */
float PerfSumErrSq = 0.0;
float JWBsumErrSq = 0.0;
float Perf2SumErrSq = 0.0;
float JWB2sumErrSq = 0.0;
float TwoOverPi;

void syntax_error() {
    printf("   Sorry, I don't understand: %s",save_line);
    printf("   (Input line for game number %ld)\n",ngames+1);
    exit(1);
}

char *malloc();

char *mallocck(size)  int size; {
    char *result;

    if(size <= 0 || size > 1000) {
        printf("Bad memory allocation size requested: %d\n",size);
        exit(1);
    }
    result = malloc((long) size);
    if(!result) {printf("***Memory Overflow***\n"); exit(1);}
    return result;
}

void read_names() {
    FILE *namesfp;
    char line[256];        /* input line */
    char *cp, *cp2, *official;
    struct NAME *namep;

    namesfp = fopen("../../names.txt","r");
    if(!namesfp) {printf("Can't open names.txt\n"); exit(1);}
    printf("Reading names.txt...\n");
     /* read input file */
    fgets(line, sizeof line, namesfp);
    while(!feof(namesfp)) {
        official = 0;
        for(cp = line;cp2 = strchr(cp,'|');cp = cp2+1) {
            *cp2 = 0;
            namep = (struct NAME *) mallocck(sizeof(struct NAME));
            namep->name = mallocck(strlen(cp)+1);
            strcpy(namep->name,cp);
            if(!official) official = namep->name;
            namep->official = official;
            namep->link = name_list;
            name_list = namep;
        }
        fgets(line, sizeof line, namesfp);
    }
    fclose(namesfp);
}

int strcasecmp(s1,s2) register char *s1, *s2; {  /* case insensative strcmp */
    register char ch1, ch2;

    do {
        ch1 = toupper(*s1++);
        ch2 = toupper(*s2++);
    } while(ch1 == ch2 && ch1);
    return (ch1 - ch2);
}

struct TEAM *find_team(name) char *name; {
    struct TEAM *teamp;
    struct NAME *namep;

     /* look up official name */
    for(namep=name_list; namep && strcasecmp(name,namep->name);
     namep=namep->link);
    if(!namep) {    /* new name--not found in names.txt */
        printf("Team name not found in names.txt: %s\n",name);
        namep = (struct NAME *) mallocck(sizeof(struct NAME));
        namep->name = mallocck(strlen(name)+1);
        strcpy(namep->name,name);
        namep->official = namep->name;
        namep->link = name_list;
        name_list = namep;
    }
    name = namep->official;
     /* look for a team by this name */
    for(teamp=team_list; teamp && strcmp(name,teamp->name);
     teamp=teamp->link);
    if(!teamp) {
        teamp = (struct TEAM *) mallocck(sizeof(struct TEAM));
        teamp->name = name;
        teamp->rating = 500.0;
        teamp->JWB = 500.0;
        teamp->link = team_list;
        team_list = teamp;
    }
    return teamp;
}

void read_JWB() {
    FILE *fp;
    char string[80],*name,*cp;
    float rating;
    int i;

    name = string+4;
    fp = fopen("JWB.txt","r");
    if(fp) {
        printf("Reading JWB.txt...\n");
        do { 
            fgets(string,80,fp);
        } while(strncmp(string,"  1 ",4) && !feof(fp));
        do {
            i = sscanf(string+26,"%6f",&rating);
            if(i == 1) {
                cp = name+20;
                while(*cp == ' ' && cp > name) *cp-- = 0;
                find_team(name)->JWB = rating;
            }
            fgets(string,80,fp);
        } while(i == 1 && strlen(string) >= 32 && !feof(fp));
    }
    fclose(fp);
}

void read_ratings() {
    FILE *fp;
    char string[80],name[18],*cp;
    float rating;
    int i;

    fp = fopen("../../byname.txt","r");
    if(fp) {
        printf("Reading byname.txt...\n");
        fgets(string,80,fp);
        fgets(string,80,fp);
        do {
            fgets(name,18,fp);
            i = fscanf(fp,"%*2d%*3d%*3d%11f\n",&rating);
            if(i == 1) {
                cp = name+16;
                while(*cp == ' ' && cp > name) *cp-- = 0;
                find_team(name)->rating = rating;
            }
        } while(i == 1);
    }
    fclose(fp);
}

void add_game(teamp, score1, opponentp, score2)
 struct TEAM *teamp, *opponentp;
 short int score1, score2;
{
    float PerfEstimate, JWBestimate, Actual;
    float Perf2Estimate, JWB2estimate;

    if(teamp->JWB < 500.0 && opponentp->JWB < 500.0) {
        PerfEstimate = (teamp->rating - opponentp->rating)/100.0;
        JWBestimate = teamp->JWB - opponentp->JWB;
        Perf2Estimate = TwoOverPi*atan((double) PerfEstimate*
         (1.80 + 4.55*PerfEstimate*PerfEstimate));
        JWB2estimate = TwoOverPi*atan((double) JWBestimate*
         (1.80 + 4.55*JWBestimate*JWBestimate));
        if(PerfEstimate >  1.0) PerfEstimate =  1.0;
        if(PerfEstimate < -1.0) PerfEstimate = -1.0;
        if( JWBestimate >  1.0)  JWBestimate =  1.0;
        if( JWBestimate < -1.0)  JWBestimate = -1.0;
        if(score1 > score2) Actual = 1.0;
        else Actual = 0.0;
        PerfSumErrSq += (PerfEstimate-Actual)*(PerfEstimate-Actual);
        JWBsumErrSq  += ( JWBestimate-Actual)*( JWBestimate-Actual);
        Perf2SumErrSq += (Perf2Estimate-Actual)*(Perf2Estimate-Actual);
        JWB2sumErrSq  += ( JWB2estimate-Actual)*( JWB2estimate-Actual);
    }
}

void read_games() {
    short int bowl;       /* set for bowl games */
    char *name;           /* start of name of team on input line */
    short int score[2];   /* scores for current game */
    char line[80];        /* input line */
    char ch, ch2;         /* a character from the input line */
    short int which;      /* 0 or 1 for which team in current game */
    short int number;     /* used to gather a score */
    char *cp, *cp2;       /* places in input line */
    struct TEAM *pair[2];
    FILE *gamesfp,*fp;

    gamesfp = fopen("../../games.txt","r");
    if(!gamesfp) {printf("Can't open games.txt\n"); exit(1);}
    printf("Reading games.txt...\n");
    bowl = 0;
    ngames = 0;
     /* read input file */
    fgets(line, sizeof line, gamesfp);
    while(!feof(gamesfp)) {
        strcpy(save_line,line);
        if(!strncmp(line,"=====",5)) {
            bowl = 1;       /* bowl games count double */
        }
        else {
             /* parse input line */
            cp = line-1;
            for(which=0; which<=1; which++) {
                while((ch = *++cp) && ch <= ' ');   /* bypass leading blanks */
                 /* check for a date line or blank line */
                if(!ch || (ch >= '0' && ch <= '9')) {
                    if(ch) strncpy(date,cp,79);
                    goto skip;
                }
                name = cp;      /* start of the name */
                do {
                    while((ch = *++cp) > ' ');     /* find ending blank */
                    if(! *cp) goto skip;    /* check for header line */
                    cp2 = cp;            /* possible end-of-name location */
                    while((ch = *++cp) && ch <= ' ');  /* find non-blank */
                    if(!ch) goto skip;
                     /* if it's not a digit, the name continues */
                } while(ch < '0' || ch > '9');
                *cp2 = 0;     /* terminate the team name */
                number = 0;   /* gather up the score */
                do {
                    number = 10*number + ch - '0';
                    ch = *++cp;
                } while(ch >= '0' && ch <= '9');
                if(ch == ',') ch = *++cp;
                if(ch > ' ') syntax_error();
                score[which] = number;  /* store the score */
                pair[which] = find_team(name);
            }
            if(score[0] >= score[1])
             add_game(pair[0], score[0], pair[1], score[1]);
            else add_game(pair[1], score[1], pair[0], score[0]);
            ngames++;
        }
        goto read;
skip:   if(which) syntax_error();
read:   fgets(line, sizeof line, gamesfp);
    }
    fclose(gamesfp);
    printf("%ld games\n",ngames);
}

write_error() {
    printf("Sum Err Sq = %f (Perf) %f (JWB)\n  %f (Perf2) %f (JWB2)\n",
     PerfSumErrSq,JWBsumErrSq,Perf2SumErrSq,JWB2sumErrSq);
}

int main() {
    TwoOverPi = 0.5/atan((double) 1.0);
    printf("%f\n",TwoOverPi);
    read_names();
    read_ratings();
    read_JWB();
    read_games();
    write_error();
    return 0;
}
