// Standing.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
/*   C PROGRAM TO PRODUCE CONFERENCE STANDINGS

    (c) Copyright 1996-2000  David Lee Wilson; 620 Pickford St.; Madison, WI  53711
    This program may be freely distributed and used for non-commercial use.
  
 */

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

struct TEAM {
    char *name;             /* team name */
    struct CONF *conf;            /* conference */
    short int won, lost, tied;   /* raw team record */
    short int points, op_points;   /* points scored */
    short int cnfwon, cnflost, cnftied;   /* record within the conference */
    short int cnfpoints, cnfop_points;  /* points within conference */
    float rating;
    struct TEAM *link;        /* link to next team */
    struct TEAM *cnflink;       /* link to next team in the same conference */
} *team_list = NULL;

struct CONF {
    char *name;                /* conference name */
    struct TEAM *teams;        /* link to list of teams in conference */
    struct CONF *link;         /* link to next conference */
};

struct DIV {
    char *name;                 /* division name */
    struct CONF *confs;         /* link to list of conferences in division */
    struct DIV *link;           /* link to next conference */
} *div_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;

struct GAME {
    char* name1;        /* name of winner */
    int score1;         /* score of winner */
    char* name2;        /* name of loser */
    int score2;         /* score of loser */
    struct GAME *link;  /* link to next game */
} *game_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 */
char* ties;             /* set if a tie was found */

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

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

    if(size <= 0 || size > 1000) {
        printf("Bad memory allocation size requested: %d\n",size);
        getchar(); exit(1);
    }
    result = malloc((long) size);
    if(!result) {printf("***Memory Overflow***\n"); getchar(); 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"); getchar(); 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 = (char*) mallocck((int)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 mystrcmp(char *s1, char *s2) {  /* case insensative strcmp */
    register char ch1, ch2;

    do {
        while((ch1 = toupper(*s1++)) && (ch1<'A' || ch1>'Z'));
        while((ch2 = toupper(*s2++)) && (ch2<'A' || ch2>'Z'));
    } while(ch1 == ch2 && ch1);
    return (ch1 - ch2);
}

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

     /* look up official name */
    for(namep=name_list; namep && mystrcmp(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 = (char*) mallocck((int)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->conf = 0;
        teamp->won = 0;
        teamp->lost = 0;
        teamp->tied = 0;
        teamp->points = 0;
        teamp->op_points = 0;
        teamp->cnfwon = 0;
        teamp->cnflost = 0;
        teamp->cnftied = 0;
        teamp->cnfpoints = 0;
        teamp->cnfop_points = 0;
        teamp->rating = 500.0;
        teamp->link = team_list;
        team_list = teamp;
        teamp->cnflink = NULL;
    }
    return teamp;
}

void read_conferences() {
    FILE *fp;
    char line[256];        /* input line */
    int len;
    char *name;
    struct TEAM *teamp;
    struct CONF *confp=NULL, **confpp=NULL;
    struct DIV *divp=NULL, **divpp;

    divpp = &div_list;
    fp = fopen("conf.txt","r");
    if(!fp) {printf("Can't open conf.txt\n"); getchar(); exit(1);}
    printf("Reading conf.txt...\n");
     /* read input file */
    fgets(line, sizeof line, fp);
    len = (int)strlen(line);
    while(!feof(fp) && len) {
        line[len-1] = 0;  /* drop final \n */
        if(line[0] >= 'A' && confpp) {  /* if conference name */
            confp = (struct CONF *) mallocck(sizeof(struct CONF));
            confp->name = (char*) mallocck(len);
            strcpy(confp->name,line);
            *confpp = confp;
            confp->link = 0;
            confpp = &(confp->link);
            confp->teams = NULL;
        }
        else if(line[0] == '-' && len > 11) {  /* division name */
            divp = (struct DIV *) mallocck(sizeof(struct DIV));
            divp->name = (char*) mallocck(len-11);
            strcpy(divp->name,line+11);
            *divpp = divp;
            divp->link = NULL;
            divpp = &(divp->link);
            divp->confs = NULL;
            confpp = &(divp->confs);
            confp = NULL;
        }
        else if(line[0] == '=' && len > 6) {  /* subdivision name */
        }
        else if(confp) {  /* team name */
            name = line;
            while(*name == ' ') name++;
            teamp = find_team(name);
            if(teamp->conf) {
                printf("%s is in 2 conferences\n",name); 
                getchar(); exit(1);
            }
            teamp->conf = confp;
            teamp->cnflink = confp->teams;
            confp->teams = teamp;
        }
        fgets(line, sizeof line, fp);
        len = (int)strlen(line);
    }
    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);
        ties = strchr(string,'T');
        fgets(string,80,fp);
        do {
            fgets(name,18,fp);
            i = fscanf(fp,
             ties ? "%*2d%*3d%*3d%11f\n" : "%*2d%*3d%12f\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(struct TEAM *teamp, short int score1, struct TEAM *opponentp, short int score2) {
    int increment=0;  /* 1 if teams in same conference */

    teamp->points += score1;
    teamp->op_points += score2;
    if(teamp->conf == opponentp->conf) {
        teamp->cnfpoints += score1;
        teamp->cnfop_points += score2;
        increment = 1;
    }
    if(score1 > score2) {
        teamp->won += 1;
        teamp->cnfwon += increment;
    }
    else if(score1 == score2) {
        teamp->tied += 1;
        teamp->cnftied += increment;
    }
    else {
        teamp->lost += 1;
        teamp->cnflost += increment;
    }
}

void output_games(FILE *fp) {
    struct GAME *gamep, *sortp, **sortpp;

    if(!fp) return;
     /* alpha sort */
    gamep = game_list;
    game_list = 0;
    while(gamep) {
        sortpp = &game_list;
        while((sortp = *sortpp) && strcmp(gamep->name1,sortp->name1) > 0)
            sortpp = &(sortp->link);
        *sortpp = gamep;
        gamep = gamep->link;
        (*sortpp)->link = sortp;
    }
    for(gamep = game_list; gamep; gamep=sortp) {
        fprintf(fp,"%-17s%3d   %-17s%3d\n",
         gamep->name1,gamep->score1,gamep->name2,gamep->score2);
        sortp = gamep->link;
        free(gamep);
    }
    game_list = NULL;
}

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;              /* 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;
    struct GAME *gamep;

    gamesfp = fopen("games.txt","r");
    if(!gamesfp) {printf("Can't open games.txt\n"); getchar(); exit(1);}
    printf("Reading games.txt...\n");
    fp = fopen("gam_neat.txt","w");
    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 */
            output_games(fp);
            if(fp) fputs(line,fp);
        }
        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) goto skip;
                if(ch >= '0' && ch <= '9') {
                     /* some names start with things like: 20th */
                    cp2 = cp;
                    while(*cp2 >= '0' && *cp2 <= '9') cp2++;
                    if(*cp2 >= 'A') goto gotname;
                    while(*cp2 > ' ') cp2++;
                    ch = *cp2;
                    *cp2 = 0;
                    if(ch && strncmp(date,cp,79)) {
                        strncpy(date,cp,79);
                        output_games(fp);
                        if(fp) fprintf(fp,"                   %s\n",cp);
                    }
                    *cp2 = ch;
                    while(*cp2 == ' ') cp2++;
                    if(*cp2 < '1') goto skip;
                    cp = cp2;   /* score follows date */
                }
gotname:        name = cp;      /* start of the name */
continue_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>='n' && ch<='t') {
                    /* oops--ordinal like 1st, 2nd, 3rd, 4th.  name continues */
                    *cp2 = ' ';
                    goto continue_name;
                }
                if(ch == ',') ch = *++cp;
                if(ch > ' ') syntax_error();
                score[which] = number;  /* store the score */
                pair[which] = find_team(name);
            }
            add_game(pair[0], score[0], pair[1], score[1]);
            add_game(pair[1], score[1], pair[0], score[0]);
            ngames++;
            if(fp) {
                gamep = (struct GAME*) mallocck(sizeof(struct GAME));
                 /* put winner first */
                if(score[0] > score[1] || (score[0] == score[1] &&
                 strcmp(pair[0]->name,pair[1]->name) > 0)) {
                    gamep->name1 = pair[0]->name;
                    gamep->score1 = score[0];
                    gamep->name2 = pair[1]->name;
                    gamep->score2 = score[1];
                }
                else {
                    gamep->name1 = pair[1]->name;
                    gamep->score1 = score[1];
                    gamep->name2 = pair[0]->name;
                    gamep->score2 = score[0];
                }
                gamep->link = game_list;
                game_list = gamep;
            }
        }
        goto read;
skip:   if(which) syntax_error();
read:   fgets(line, sizeof line, gamesfp);
    }
    output_games(fp);
    fclose(fp);
    fclose(gamesfp);
    printf("%ld games\n",ngames);
}

void write_standings() {
    FILE *fp;
    struct DIV *divp;
    struct CONF *confp;
    struct TEAM *teamp, **sortpp, *sortp;
    int decide1, decide2, compare, count;
    float sum_ratings;
    char filename[32];
    int division_count = 0;

    for(divp=div_list; divp; divp=divp->link) {
        sprintf(filename,"standing%d.txt",++division_count);
        fp = fopen(filename,"w");
        if(!fp) {
            printf("can't open standing%d.txt\n",division_count);
            getchar(); exit(1);
        }
        printf("Writing standing%d.txt\n",division_count);
        fprintf(fp,"%s Football\n", divp->name);
        fprintf(fp,"Conference Standings as of %s\n",date);
        fprintf(fp,"Perfomance Ratings are from David Wilson's system\n");
        for(confp=divp->confs; confp; confp=confp->link) {
            sum_ratings = 0.0;
            count = 0;
            for(teamp=confp->teams; teamp; teamp=teamp->cnflink) {
                sum_ratings += teamp->rating;
                count++;
            }
            fprintf(fp,"\n\n                    %s\n\n",confp->name);
            fprintf(fp,
             "%4.0f Ave. Rating  /--Conference---\\  /---Over-all----\\ Perf\n",
             sum_ratings/count);
            if(ties) {
                fprintf(fp,
              "                  W  L  T  Pts  Opp  W  L  T  Pts  Opp Rate\n");
                fprintf(fp,
              "                  -  -  -  ---  ---  -  -  -  ---  --- ----\n");
            }
            else {
                fprintf(fp,
              "                   W  L   Pts  Opp    W  L   Pts  Opp  Rate\n");
                fprintf(fp,
              "                   -  -   ---  ---    -  -   ---  ---  ----\n");
            }
             /* sort by confernce standing */
            teamp = confp->teams;
            confp->teams = 0;
            while(teamp) {
                 /* in case of equal ratings, use better */
                 /* raw record as tie breaker */
                sortpp = &(confp->teams);
                while(1) {
                    sortp = *sortpp;
                    if(!sortp) break;
                    decide1 = teamp->cnfwon + teamp->cnflost;
                    decide2 = sortp->cnfwon + sortp->cnflost;
                    if(!decide2) compare = teamp->cnfwon - teamp->cnflost;
                    else if(!decide1) compare = sortp->cnflost - sortp->cnfwon;
                    else compare = teamp->cnfwon*decide2 -
                     sortp->cnfwon*decide1;
                    if(compare == 0) compare = teamp->cnfwon+sortp->cnflost-
                     teamp->cnflost-sortp->cnfwon;
                    if(compare == 0) {
                        decide1 = teamp->won + teamp->lost;
                        decide2 = sortp->won + sortp->lost;
                        if(!decide2) compare = teamp->won - teamp->lost;
                        else if(!decide1) compare = sortp->lost - sortp->won;
                        else compare = teamp->won*decide2 - sortp->won*decide1;
                        if(compare == 0) compare = teamp->won+sortp->lost-
                         teamp->lost-sortp->won;
                        if(compare == 0) compare = (int) (teamp->rating - sortp->rating);
                    }
                    if(compare > 0) break;
                    sortpp = &(sortp->cnflink);
                };
                *sortpp = teamp;
                teamp = teamp->cnflink;
                (*sortpp)->cnflink = sortp;
            }
            for(teamp=confp->teams; teamp; teamp=teamp->cnflink) {
                if(ties) fprintf(fp,
                 "%-17s%2d%3d%3d%5d%5d%3d%3d%3d%5d%5d%5.0f\n",
                 teamp->name,teamp->cnfwon,teamp->cnflost,teamp->cnftied,
                 teamp->cnfpoints,teamp->cnfop_points,teamp->won,
                 teamp->lost,teamp->tied,teamp->points,
                 teamp->op_points,teamp->rating);
                else fprintf(fp,
                 "%-17s%3d%3d%6d%5d%5d%3d%6d%5d%6.0f\n",
                 teamp->name,teamp->cnfwon,teamp->cnflost,
                 teamp->cnfpoints,teamp->cnfop_points,teamp->won,
                 teamp->lost,teamp->points,
                 teamp->op_points,teamp->rating);
            }
        }
        fclose(fp);
    }
}

int _tmain(int argc, _TCHAR* argv[]) {
    read_names();
    read_conferences();
    read_ratings();
    read_games();
    write_standings();
	getchar();
    return 0;
}

