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

/***************************************************************************************************/
/*
*
*    prop.demo.query.c  (c) Dr. Eric Loeb, 1994  all rights reserved
*
*/
/***************************************************************************************************/


#define TRUE 1
#define FALSE 0

#define BUFSIZE 100

typedef struct {
    char name[128];
    char val[128];
} entry;

void getword(char *word,char *line,char stop);
char x2c(char *what);
void unescape_url(char *url);
void plustospace(char *str);
void readfromfile(char filename[64]);

#define N_VOTERS 5
#define N_CANDS  4
#define N_OFFICES 2
int V[N_CANDS][N_VOTERS];
int Counted[N_CANDS];
int Valid=N_VOTERS;
int Quota=0;
int NWinners = 0;

entry entries[10000];

char BadString[100];

main(int argc, char *argv[]) {
    register int x,m=0;
    int i, nbad, Distribute[N_CANDS], Bad[N_VOTERS];
    char  *cl;

    printf("Content-type: text/html%c%c",10,10);
    cl = getenv("QUERY_STRING");

    if(cl == NULL) {
        printf("Please enter parameters.\n");
        exit(1);
    }

   for(x=0;cl[0] != '\0';x++) {
        m=x;

        getword(entries[x].val,cl,'&');

	plustospace(entries[x].val);
        unescape_url(entries[x].val);
        getword(entries[x].name,entries[x].val,'=');
    }
    
    get_votes();
    readfromfile("Vote.Result.Top.html");
    display_votes();

    printf("<p><LI>Voters can only give a rank (1, 2, 3, ...) once.\n");
    if (nbad = check_votes(Bad)) eliminate_bad(Bad);
    else printf("<b>These ballots are all good\n</b><p>");

    Quota = explain_quota();

    for (i=0; i<N_CANDS; i++) Distribute[i] = Counted[i] = 0;
    i = 1;
    while ((do_round(Bad, Distribute, i) < N_OFFICES) && (i < N_CANDS)) 
      if (remaining_candidates(Distribute, i++) == 1) break;
    printf("</UL><p>\n");

    for (i=0; i<N_CANDS; i++) 
      if (Distribute[i] > 0)
	printf("<h1><img src=\"next.xbm\">Candidate %c Wins!</h1>\n", 
	       'A' + i);

    finish();
  }

remaining_candidates(distr, round)
int *distr, round;
{
  int i, remain = 0, result = 0;
  for (i=0; i<N_CANDS; i++)
    if (distr[i] == 0) {result++; remain=i;}

  if ((result == 1) && (NWinners < N_OFFICES)) {
    distr[remain] = TRUE;
    NWinners++;

    printf("</UL><LI>All but %d candidates have won or been\n", N_OFFICES);
    printf(" eliminated in round %d\n", round);
  }
  return(result);
}

do_round(Bad, Distribute, round)
int *Bad, *Distribute, round;
{
   int votr, win, looser;

   printf("<p><LI> Round %d: Ranks of %d are counted\n<UL>", round, round);

   win = NWinners;
   for (votr=0; votr < N_VOTERS; votr++) 
     if (!Bad[votr]) add_votes(Distribute, votr, round, round);
   if (win == NWinners) show_votes(round);

   if (NWinners < N_OFFICES) 
     {
       if ((looser = eliminate_looser(round)) >= 0)
	 Distribute[looser] = -1;
     }
   printf("</UL><p>\n");
   return(NWinners);
}

show_votes(round)
int round;
{
  printf("<LI>No winners declared in round %d", round);
}

add_votes(distr, votr, round, true_round)
int *distr, votr, round, true_round;
{
  int cand;

  for (cand=0; cand<N_CANDS; cand++)
    {
      if (NWinners >= N_OFFICES) return;

      if (V[cand][votr] == round) 
	{
	  if (round != true_round) 
	    explain_distribution1(votr, cand, round);

	  if (distr[cand] != 0) {
	    explain_distribution2(distr, votr, cand, round);
	    return(add_votes(distr, votr, round + 1, true_round));
	  }

	  if (++Counted[cand] >= Quota) 
	    declare_winner(distr, cand, votr, true_round);
}}}



declare_winner(distr, cand, votr, true_round)
int *distr, cand, votr, true_round;
{
  char who = 'A' + cand;
  printf("<LI> Candidate <b>%c</b> meets quota with voter %d, ",
	 who, votr + 1);
  printf("<B> declared winner!</B>\n");
  NWinners++;
  distr[cand] = TRUE;
  
  if (remaining_candidates(distr, true_round) == 1) return;
  if (NWinners < N_OFFICES) 
    {
      printf("<LI> Subsequent votes of %d for Candidate <b>%c</b>", 
	     true_round, who);
      printf(" are redistributed to the candidates marked next in");
      printf(" preference on the ballot.\n");
    }
}

eliminate_looser(round)
int round;
{
  int cand, minc = Quota, looser, multi=0;
  char who;

  printf("<LI>Lowest vote-getter eliminated:\n");

  for (cand=0; cand<N_CANDS; cand++)
    if (Counted[cand] < minc)
      {
	minc = Counted[cand];
	looser = cand;
      }
  for (cand=0; cand<N_CANDS; cand++) 
    if (Counted[cand] == minc) multi++;

  if (multi > 1)
    {
      printf("<LI> There is a tie for last place in round %d\n", round);
      printf("No candidates are eliminated\n");
      return(-1);
    }

  who = looser + 'A';
  printf("Candidate <b>%c</b> has %d vote%c at the end of round %d\n", 
	 who, minc, (minc != 1) ? 's' : ' ', round);
  printf("<LI> Subsequent votes for Candidate <b>%c</b>", who);
  printf(" are redistributed to the candidates marked next in");
  printf(" preference on the ballot.\n");

  return(looser);
}


explain_distribution2(distr, votr, cand, tr)
int *distr, votr, cand, tr;
{
  char who='A'+cand;
  printf("<LI>Voter %d gives rank %d to Candidate <b>%c</b>,", votr+1, tr, who);
  printf(" but Candidate <b>%c</b> already %s, so we look for", who,
	 (distr[cand] > 0) ? "won" : "lost"); 
  printf(" preference of %d from voter %d :\n", tr + 1, votr+1);
}

explain_distribution1(votr, cand, tr)
int votr, cand, tr;
{
  printf("Candidate <b>%c</b> gets vote of", 'A'+cand);
  printf(" %d from voter %d\n", tr, votr+1); 
}

explain_quota()
{
  printf("<LI> The quota for <B>N</B> elected offices is");
  printf(" 1 + (<B>Valid</B> / <B>N</B>)<p>");
  printf("There %s<B> %d valid ballot%s</B>, and this election", 
	 (Valid == 1) ? "is " : "are", Valid, (Valid == 1) ? "" : "s");
  printf(" is for <B>%d</B> offices.  So, the quota for this ", N_OFFICES);
  printf(" election is <B>%d</B>\n<p>", (Valid/N_OFFICES) + 1);
  return((Valid/N_OFFICES) + 1);
}

eliminate_bad(Bad)
int *Bad;
{
  int i, nbad=0;
  char which[100];

  for (i=0; i<N_VOTERS; i++) nbad=nbad + Bad[i];
  if (nbad <=0) return;
  else if (nbad == 1) 
    sprintf(which,"<B>Voter %d used the same value twice or did not vote</B>:", 
	    next_bad(Bad, 0));
  else {
    bad_str(Bad, nbad);
    sprintf(which, "<B>Voters %s did not fill in their ballots corectly</B>:", 
	    BadString);
  }

  printf("%s th%s not counted.\n<p>", which,
	 (nbad > 1) ? "ese ballots are" : "is ballot is");

  for (i=0; i< N_VOTERS; i++)
    if (Bad[i]) {V[0][i] = V[1][i] = V[2][i] = 0; Valid--;}
}

bad_str(Bad, nbad)
int *Bad, nbad;
{
  int i, nb;

  sprintf(BadString, "%d", nb = next_bad(Bad, 0));
  for (i=1; i<nbad; i++) {
    if (i == nbad - 1)
      sprintf(BadString, "%s and %d", BadString, next_bad(Bad, nb));
    else
      sprintf(BadString, "%s, %d", BadString, nb = next_bad(Bad, nb));
  }
}

next_bad(Bad, k)
int *Bad, k;
{ 
  int i;
  for (i=k; i<N_VOTERS; i++)
    if (Bad[i]) return(i + 1);
  return(0);
}


get_votes()
{
  int cand, votr, index;

  for (cand=0; cand < N_CANDS; cand++)
    for (votr=0; votr < N_VOTERS; votr++) {
      index = (N_VOTERS * cand) + votr;
      V[cand][votr]=atoi(entries[index].val);
    }
}


char cnv(x)
int x;
{ if (x == 0) return('-');
  else return('0' + x);
}

display_votes()
{
  int i, j;

  printf("<pre>");
  printf("\t\tSample Votes\n");
  printf("-----------------------------------------------------------\n");
  printf("Candidate\t\t");
  for (i=0; i<N_VOTERS; i++) printf("%d\t", i + 1);
  printf("\n-----------------------------------------------------------\n");

    for (i=0; i<N_CANDS; i++) {
      printf("\t%c\t\t", 'A' + i);
      for (j=0; j<N_VOTERS; j++)
	printf("%c\t",  cnv(V[i][j]));
      printf("\n");
    }
    printf("----------------------------------------------------------\n");
    printf("</pre>\n<hr>");
}    

check_votes(results)
int *results;
{
  int v, ca, retval=0;
  int checks[N_CANDS];


  for (v =0; v < N_VOTERS; v++)
    {
      for (ca =0; ca < N_CANDS; ca++) checks[ca] = V[ca][v];

      results[v] = one_check(checks);
      if (results[v]) retval++;
    }
  return(retval);
}

one_check(ch)
int *ch;
{
  int i, i2, okv = FALSE;
  for (i=0; i<N_CANDS; i++)
    {
      i2 = i + 1;
      if (i2 >= N_CANDS) i2 = 0;

      if ((ch[i] == ch[i2]) && (ch[i] != 0)) return(TRUE);
      if (ch[i] != 0) okv = TRUE;
    }

  return(!okv);  /* if no votes given, its no good*/
}


finish()
{
  readfromfile("Vote.Result.Bottom.html");
  exit(1);
}

/*did_vote(a, b, c)
int a, b, c;
{
    if (((a==0)&&( entries[0].val[0] !=48))||
	((b==0)&&( entries[2].val[0] !=48))||
	((c==0)&&( entries[4].val[0] !=48)))
      {
	printf("<p>All Voters must give votes for all candidates\n");
	printf("Please return to initial form and try again\n<p>");
	finish();
      }
}*/


void readfromfile(char filename[64])
{

  char buf[BUFSIZE];
  FILE *fp;
  int x; 

  if ((fp=fopen(filename,"r"))==NULL)
  {
    fprintf(stderr, "Error opening file.");
    exit(1);
  }

  fgets(buf,BUFSIZE,fp);
  while (!feof(fp))
    {
      printf("%s",buf);   
      fgets(buf, BUFSIZE, fp);
   
    }
  for (x=0; x<=BUFSIZE;x++)
    buf[x]=32;

  fclose(fp);
}





























