#include <vector>
#include <string>
#include <map>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <stdio.h>

#include "rating.h"

using namespace std;

static const int prizes[6] = {25, 50, 75, 100, 150, 200};
static const int advancers[4] = {400, 200, 100, 48};

bool rerate;

string ratingToAbr(int rating) {
	if (rating >= 2200) return "R";
	if (rating >= 1500) return "Y";
	if (rating >= 1200) return "B";
	if (rating >= 900) return "G";
	return "gr";
}

bool cmpscore(const coder &a, const coder &b) {
	return a.score100 > b.score100;
}

bool cmprating(const coder &a, const coder &b) {
	return a.rating > b.rating;
}

void do_problems(vector<coder> &cs) {
	for (int i = 0; i < cs.size(); i++) {
		cs[i].score100 = (int)round(100*(cs[i].rating +
			cs[i].vol*stdnormal_inv(random()/(double)RAND_MAX)));
//printf("%-25s with rating %4d and vol %3d scores %6.2lf\n",
//cs[i].handle.c_str(), cs[i].rating, cs[i].vol, cs[i].score100/100.0);
	}
}

void do_onsite(vector<coder> &cs){
	do_problems(cs);
	/* sort by score / rank */
	sort(cs.begin(), cs.end(), cmpscore);
	if (rerate) calcRatings(cs);
}

void do_final(vector<coder> &cs,
	map<string, vector<int> > &wins, 
	map<string, vector<int> > &makeit) {
	
	for (int i = 0; i < cs.size(); i++) makeit[cs[i].handle][8]++;
	do_onsite(cs);
	/* add prize money and room advancement to csists */
	wins[cs[0].handle][4] += 19500;
	makeit[cs[0].handle][12]++;
	wins[cs[1].handle][4] += 9500;
	makeit[cs[1].handle][11]++;
	wins[cs[2].handle][4] += 4500;
	makeit[cs[2].handle][10]++;
	wins[cs[3].handle][4] += 2000;
	makeit[cs[3].handle][9]++;
	wins[cs[4].handle][4] += 700;
	wins[cs[5].handle][4] += 700;
	wins[cs[6].handle][4] += 700;
	wins[cs[7].handle][4] += 700;
}

void do_wildcard(vector<coder> &cs,
	map<string, vector<int> > &wins, 
	map<string, vector<int> > &makeit) {
	
	vector<coder> wild(cs.begin()+6, cs.end());
	for (int i = 0; i < wild.size(); i++) makeit[wild[i].handle][7]++;
	do_onsite(wild);
	cs.erase(cs.begin()+6, cs.end());
	cs.push_back(wild[0]);
	cs.push_back(wild[1]);
}

void do_semi(vector<coder> &cs, vector<coder> &wild, vector<coder> &final) {
	do_onsite(cs);
	/* put two in the final */
	final.push_back(cs[0]);
	final.push_back(cs[1]);
	/* put four in the wildcard */
	wild.push_back(cs[2]);
	wild.push_back(cs[3]);
	wild.push_back(cs[4]);
	wild.push_back(cs[5]);
}

void do_semis(vector<coder> &cs,
	map<string, vector<int> > &wins, 
	map<string, vector<int> > &makeit) {
	
	vector<vector<coder> > rooms(3);
	vector<coder> wild, final;
	for (int i = 0; i < cs.size(); i++) {
		wins[cs[i].handle][4] += 500;
		int rm = ((i/3)%2) ? ((2-i)%3+3)%3 : i%3;
		rooms[rm].push_back(cs[i]);
		makeit[cs[i].handle][4+rm]++;
	}
	do_semi(rooms[0], wild, final);
	do_semi(rooms[1], wild, final);
	do_semi(rooms[2], wild, final);
	
	cs.clear();

	cs.insert(cs.end(), final.begin(), final.end());
	cs.insert(cs.end(), wild.begin(), wild.end());
}

void do_online_round(int rd, vector<coder> &cs,
	map<string, vector<int> > &wins, 
	map<string, vector<int> > &makeit) {
	
	do_problems(cs);
	/* mark people as making it to this round */
	for (int i = 0; i < cs.size(); i++) makeit[cs[i].handle][rd]++;
	for (int i = 0; i < cs.size(); i += 25) {
		/* grab the coders in this room */
		vector<coder> room(cs.begin()+i, cs.begin()+i+25);
		/* find the top three and give them prizes */
		sort(room.begin(), room.end(), cmpscore);
		wins[room[0].handle][rd] += prizes[rd+2];
		wins[room[1].handle][rd] += prizes[rd+1];
		wins[room[2].handle][rd] += prizes[rd];
	}
	/* sort by score / rank */
	sort(cs.begin(), cs.end(), cmpscore);
	
	if (rerate) calcRatings(cs);
	/* toss those who don't make it */
	cs.erase(cs.begin()+advancers[rd], cs.end());
	/* sort by rating for room placement next time */
	sort(cs.begin(), cs.end(), cmprating);
}

int read_coders(vector<coder> &cs) {
	char handle[100];
	int rating, vol, cr;
	
	while (scanf("%d,%[^,],%d,%d\n", &cr, handle, &rating, &vol) == 4) {
		coder c;
		c.handle = handle;
		c.cr = cr;
		c.rating = rating;
		c.vol = vol;
		cs.push_back(c);
	}
	return cs.size();
}

int main(int argc, char **argv) {
	unsigned long seed = (unsigned long)time(NULL);
	int times = 100;
	string title = "None";
	rerate = true;
	
	if (argc < 2) {
		fputs("Usage: simulate title [rerate=+] [times=100] [seed=time(NULL)] < coders.csv",
			stderr);
		return 1;
	}
	title = argv[1];
	if (argc > 2) rerate = argv[2][0] == '+';
	if (argc > 3) times = atoi(argv[3]);
	if (argc > 4) seed = atoi(argv[4]);
fprintf(stderr, "Executing %d simulations\n", times);
	// initialize the random number generator
	srandom(seed);
	
	vector<coder> coders, c2;
	int ct = read_coders(coders);
fprintf(stderr, "Read info for %d coders\n", ct);
	
	map<string, vector<int> > wins, makeit;
	
	vector<int> win(5, 0), make(13, 0);
	
	for (int i = 0; i < coders.size(); i++) {
		wins[coders[i].handle] = win;
		makeit[coders[i].handle] = make;
	}
	
	for (int i = 0; i < times; i++) {
fprintf(stderr, "#%d\n", i+1);
		c2 = coders;
		if (ct > 405) do_online_round(0, c2, wins, makeit);
		if (ct > 205) do_online_round(1, c2, wins, makeit);
		if (ct > 105) do_online_round(2, c2, wins, makeit);
		if (ct > 50) do_online_round(3, c2, wins, makeit);
		if (ct > 18) do_semis(c2, wins, makeit);
		if (ct > 8) do_wildcard(c2, wins, makeit);
		do_final(c2, wins, makeit);
		/* give $500 to people if I'm not doing semi-finals */
		if (ct < 40) for (int i = 0; i < ct; i++) wins[coders[i].handle][4] += 500;
	}
	
	double d = times/100.0;
	
	title = "jdmetz's TCO 2005 Predictions after " + title;
	printf("<html><head><title>%s</title>\n", title.c_str());
	puts(	"<style type=\"text/css\">\n"
		"  th {\n"
		"    color: #333333;\n"
		"    font-size: 12px;\n"
		"    font-weight: bold;\n"
		"    text-decoration: none;\n"
		"    text-align: center;\n"
		"    background-color: #CCCCCC;\n"
		"    white-space: nowrap;\n"
		"  }\n"
		"  td.o {\n"
		"    color: #333333;\n"
		"    font-size: 11px;\n"
		"    font-weight: normal;\n"
		"    text-decoration: none;\n"
		"    text-align: left;\n"
		"    background-color: #EEEEEE;\n"
		"    white-space: nowrap;\n"
		"  }\n"
		"  td.oc {\n"
		"    color: #333333;\n"
		"    font-size: 11px;\n"
		"    font-weight: normal;\n"
		"    text-decoration: none;\n"
		"    text-align: center;\n"
		"    background-color: #EEEEEE;\n"
		"  }\n"
		"  td.or {\n"
		"    color: #333333;\n"
		"    font-size: 11px;\n"
		"    font-weight: normal;\n"
		"    text-decoration: none;\n"
		"    text-align: right;\n"
		"    background-color: #EEEEEE;\n"
		"  }\n"
		"  td.orm {\n"
		"    color: #333333;\n"
		"    font-size: 11px;\n"
		"    font-weight: normal;\n"
		"    text-decoration: none;\n"
		"    text-align: right;\n"
		"    background-color: #E7FFE7;\n"
		"  }\n"
		"  td.or2 {\n"
		"    color: #333333;\n"
		"    font-size: 11px;\n"
		"    font-weight: normal;\n"
		"    text-decoration: none;\n"
		"    text-align: right;\n"
		"    background-color: #FFE7E7;\n"
		"  }\n"
		"  td.e {\n"
		"    color: #333333;\n"
		"    font-size: 11px;\n"
		"    font-weight: normal;\n"
		"    text-decoration: none;\n"
		"    text-align: left;\n"
		"    background-color: #DDDDDD;\n"
		"    white-space: nowrap;\n"
		"  }\n"
		"  td.ec {\n"
		"    color: #333333;\n"
		"    font-size: 11px;\n"
		"    font-weight: normal;\n"
		"    text-decoration: none;\n"
		"    text-align: center;\n"
		"    background-color: #DDDDDD;\n"
		"  }\n"
		"  td.er {\n"
		"    color: #333333;\n"
		"    font-size: 11px;\n"
		"    font-weight: normal;\n"
		"    text-decoration: none;\n"
		"    text-align: right;\n"
		"    background-color: #DDDDDD;\n"
		"  }\n"
		"  td.erm {\n"
		"    color: #333333;\n"
		"    font-size: 11px;\n"
		"    font-weight: normal;\n"
		"    text-decoration: none;\n"
		"    text-align: right;\n"
		"    background-color: #D6EED6;\n"
		"  }\n"
		"  td.er2 {\n"
		"    color: #333333;\n"
		"    font-size: 11px;\n"
		"    font-weight: normal;\n"
		"    text-decoration: none;\n"
		"    text-align: right;\n"
		"    background-color: #EED6D6;\n"
		"  }\n"
		"  .cTR, .cTR:link, .cTR:visited {\n"
		"    font-weight: bold;\n"
		"    color: #EE0000;\n"
		"    text-decoration: none;\n"
		"  }\n"
		"  .cTR:hover, .cTR:active {\n"
		"    font-weight: bold;\n"
		"    color: #EE0000;\n"
		"    text-decoration: underline;\n"
		"  }\n"
		"  .cTY, .cTY:link, .cTY:visited {\n"
		"    font-weight: bold;\n"
		"    color: #DDCC00;\n"
		"    text-decoration: none;\n"
		"  }\n"
		"  .cTY:hover, .cTY:active {\n"
		"    font-weight: bold;\n"
		"    color: #DDCC00;\n"
		"    text-decoration: underline;\n"
		"  }\n"
		"  .cTB, .cTB:link, .cTB:visited {\n"
		"    font-weight: bold;\n"
		"    color: #6666FF;\n"
		"    text-decoration: none;\n"
		"  }\n"
		"  .cTB:hover, .cTB:active {\n"
		"    font-weight: bold;\n"
		"    color: #6666FF;\n"
		"    text-decoration: underline;\n"
		"  }\n"
		"  .cTG, .cTG:link, .cTG:visited {\n"
		"    font-weight: bold;\n"
		"    color: #00A900;\n"
		"    text-decoration: none;\n"
		"  }\n"
		"  .cTG:hover, .cTG:active {\n"
		"    font-weight: bold;\n"
		"    color: #00A900;\n"
		"    text-decoration: underline;\n"
		"  }\n"
		"  .cTgr, .cTgr:link, .cTgr:visited {\n"
		"    font-weight: bold;\n"
		"    color: #999999;\n"
		"    text-decoration: none;\n"
		"  }\n"
		"  .cTgr:hover, .cTgr:active {\n"
		"    font-weight: bold;\n"
		"    color: #999999;\n"
		"    text-decoration: underline;\n"
		"  }");
	printf( "</style></head><body align=center><h2>%s</h2>\n"
		"<p>These predictions are the result of simulating the TCO %d times",
		title.c_str(), times);
	if (rerate) fputs("including rating changes after each round", stdout);
	puts(	".</p>");
	puts(	"<table align=center border=0 cellpadding=6 cellspacing=0>");
	
	
	fputs("<tr><th>Seed</th>"
		"<th>Handle</th>"
		"<th>Rating</th>"
		"<th>Volatility</th>", stdout);
	fputs("<th>Expected $</th>", stdout);
	if (ct > 405) fputs("<th>Round1 $</th>", stdout);
	if (ct > 405) fputs("<th>Round2</th>", stdout);
	if (ct > 205) fputs("<th>Round2 $</th>", stdout);
	if (ct > 205) fputs("<th>Round3</th>", stdout);
	if (ct > 105) fputs("<th>Round3 $</th>", stdout);
	if (ct > 105) fputs("<th>Round4</th>", stdout);
	if (ct > 50) fputs("<th>Round4 $</th>", stdout);
	if (ct > 50) fputs("<th>Onsite</th>", stdout);
	fputs("<th>Onsite $</th>", stdout);
	if (ct > 50) fputs("<th>Semi1</th>", stdout);
	if (ct > 50) fputs("<th>Semi2</th>", stdout);
	if (ct > 50) fputs("<th>Semi3</th>", stdout);
	if (ct > 18) fputs("<th>Wildcard</th>", stdout);
	fputs("<th>Final</th>", stdout);
	fputs("<th>4th</th>", stdout);
	fputs("<th>3rd</th>", stdout);
	fputs("<th>2nd</th>", stdout);
	fputs("<th>1st</th></tr>", stdout);
	for (int i = 0; i < coders.size(); i++) {
		string h = coders[i].handle;
		char ch = i&1 ? 'e' : 'o';
		string abr = ratingToAbr(coders[i].rating);
		printf("<tr><td class=%cc>%d</td>", ch, i+1);
		printf("<td class=%c><a href=\"http://www.topcoder.com/tc?module=MemberProfile&cr=%d\" class=cT%s>%s</a></td>",
			ch, coders[i].cr, abr.c_str(), h.c_str());
		printf("<td class=%cr>%6d</td>", ch, coders[i].rating);
		printf("<td class=%cr>%4d</td>", ch, coders[i].vol);
		printf("<td class=%crm>$%8.2lf</td>", ch,
			(wins[h][0]+wins[h][1]+wins[h][2]+wins[h][3]+wins[h][4])/(double)times);
		if (ct > 405) printf("<td class=%crm>$%.2lf</td>", ch, wins[h][0]/(double)times);
		if (ct > 405) printf("<td class=%cr>%.2lf%%</td>", ch, makeit[h][1]/d);
		if (ct > 205) printf("<td class=%crm>$%.2lf</td>", ch, wins[h][1]/(double)times);
		if (ct > 205) printf("<td class=%cr>%.2lf%%</td>", ch, makeit[h][2]/d);
		if (ct > 105) printf("<td class=%crm>$%.2lf</td>", ch, wins[h][2]/(double)times);
		if (ct > 105) printf("<td class=%cr>%.2lf%%</td>", ch, makeit[h][3]/d);
		if (ct > 50) printf("<td class=%crm>$%.2lf</td>", ch, wins[h][3]/(double)times);
		if (ct > 50) printf("<td class=%cr>%.2lf%%</td>", ch, (makeit[h][4]+makeit[h][5]+makeit[h][6])/d);
		printf("<td class=%crm>$%.2lf</td>", ch, wins[h][4]/(double)times);
		if (ct > 50) printf("<td class=%cr2>%.2lf%%</td>", ch, makeit[h][4]/d);
		if (ct > 50) printf("<td class=%cr2>%.2lf%%</td>", ch, makeit[h][5]/d);
		if (ct > 50) printf("<td class=%cr2>%.2lf%%</td>", ch, makeit[h][6]/d);
		if (ct > 18) printf("<td class=%cr>%.2lf%%</td>", ch, makeit[h][7]/d);
		printf("<td class=%cr>%.2lf%%</td>", ch, makeit[h][8]/d);
		printf("<td class=%cr2>%.2lf%%</td>", ch, makeit[h][9]/d);
		printf("<td class=%cr2>%.2lf%%</td>", ch, makeit[h][10]/d);
		printf("<td class=%cr2>%.2lf%%</td>", ch, makeit[h][11]/d);
		printf("<td class=%cr2>%.2lf%%</td>", ch, makeit[h][12]/d);
		puts("</tr>");
	}
	
	return 0;
}

