var COLUMN_TOP = 0;
var COLUMN_BOTTOM = 1;
var COLUMN_VOTE = 2;

var COLUMN_INTERMEDIATE = 3;
var COLUMN_RESULT_ROW = 4;
var COLUMN_VOTE_ROW = 5;

var VOTE_GORE = 0;
var VOTE_BUSH = 1;

var LEFT_AUDIT = 0;
var RIGHT_AUDIT = 1;
var NO_AUDIT = -1;

var NUMBER_BALLOTS = 3;


var pTable = new Array();
var dTable = new Array();
var rTable = new Array();


var pTableHtml = new Array(
	"<tr><td> <div id='pRow", //0
	"' class='tableRow' onmouseover='mouseOverPRow(", //0
	")' onmouseout='mouseOutPRow(", //0
	")' onclick='clickPTable(", //0
	")'><div id='pRowFader", //0
	"' style='position:absolute; left:89px; z-index:3; background:blue; filter:alpha(opacity=100); opacity:1; top:", // 30
	"px; width:172px'>Sealed</div><table cellpadding=0 cellspacing=0><tr><td>",  //Normal
	"</td><td>", // Flipped 
	"</td><td style='border:0px solid red;'>", // Unknown 
	"</td></tr></table></div></td></tr>",
	"<table cellpadding=0 cellspacing=0>",
	"</table>"
);


var dTableHtml = new Array(
	"<table cellpadding=0 cellspacing=0>",
	"<tr><td><div id='dRow", //0
	"' class='tableRow' onmouseover='mouseOverDRow(", //0
	")' onmouseout='mouseOutDRow(", //0
	")' onclick='clickDTable(", //0
	")'><div id='dRowFader", //0
	"' style='position:absolute; z-index:3; background:gray; filter:alpha(opacity=100); opacity:1; top:", // 30
	"px; left:2px; width:259px'>Sealed</div><table cellpadding=0 cellspacing=0><tr><td>", //2
	"</td><td>",// Flipped 
	"</td><td style='border:0px solid red;'>",  //3 
	"</td></tr></table></div></td></tr>",
	"</table>"
);

var rTableHtml = new Array(
	"<table cellpadding=0 cellspacing=0>",
	"<tr><td><div id='rRow",// 0
	"' class='tableRow' onmouseover='mouseOverRRow(", //0
	")' onmouseout='mouseOutRRow(", //0
	")' onclick='clickRTable(", //0
	")'><table cellpadding=0 cellspacing=0><tr><td style='border:0px solid red;'>",// Unknown
	"<div id='rRowFader", //0
	"' style='position:absolute; z-index:3; background:green; filter:alpha(opacity=100); opacity:1; top:", // 30
	"px; left:2px; width:85px'>Sealed</div></td></tr></table></div></td></tr>",
	"</table>"
);




/////////////////////////////////////////////////
// elements for the table with printed ballots
/////////////////////////////////////////////////
function ElementP(top, bottom, vote) {
	this.topSheet = top; 
	this.bottomSheet = bottom;
	this.voteSide = vote ? vote : NO_VOTE;
	this.audited = false;
	this.exposedSheet = NO_SHEET;
}


ElementP.prototype.toString = function (which) {
	if (which == COLUMN_TOP)
		return (this.topSheet == NORMAL) ? "Normal" : "Flipped";
	else if (which == COLUMN_BOTTOM)
		return (this.bottomSheet == NORMAL) ? "Normal" : "Flipped";
	else
	{
		if (this.voteSide == VOTE_LEFT)
			return "Normal";
		else if (this.voteSide == VOTE_RIGHT)
			return "Flipped";
		else // if (this.voteSide == NO_VOTE)
			return "Unknown";
	}
};


/////////////////////////////////////////////////
// elements for the table with decryption ballots
/////////////////////////////////////////////////
function ElementD(voteR, top, bottom, resultR, intermediate) {
	this.voteRow = voteR;
	this.topSheet = top; 
	this.intermediateVote = intermediate ? intermediate : UNKNOWN; 
	this.bottomSheet = bottom;
	this.resultRow = resultR;
	this.audited = false;
	this.postElectionAudit = NO_AUDIT;
}


ElementD.prototype.toString = function (which) {
	if (which == COLUMN_VOTE_ROW)
		return this.voteRow;
	else if (which == COLUMN_TOP)
		return (this.topSheet == NORMAL) ? "Normal" : "Flipped";
	else if (which == COLUMN_INTERMEDIATE)
	{
		if (this.intermediateVote == VOTE_LEFT)
			return "Normal";
		else if (this.intermediateVote == VOTE_RIGHT)
			return "Flipped";
		else // if (this.intermediateVote == NO_VOTE)
			return "Unknown";
	}
	else if (which == COLUMN_BOTTOM)
		return (this.bottomSheet == NORMAL) ? "Normal" : "Flipped";
	else
		return this.resultRow;
};


/////////////////////////////////////////////////
// elements for the result table
/////////////////////////////////////////////////
function ElementR(candidate) {
	this.candidateVote = candidate ? candidate : NO_VOTE; 
	this.audited = false;
}

ElementR.prototype.toString = function () {
	if (this.candidateVote == VOTE_GORE)
		return "Gore";
	else if (this.candidateVote == VOTE_BUSH)
		return "Bush";
	else
		return "Unknown";
};

/////////////////////////////////////////////////
// initialize everything needed
/////////////////////////////////////////////////
function createRandomLinks(size)
{
	linkArray = new Array();

	// create the links
	for (i = 0; i < size; i++)
	{
		linkArray[i] = i;
	}

	// now swap them all
	for (i = 0; i < pTable.length; i++)
	{
		swapElt = (get_random() % size);
		temp = linkArray[i];


		linkArray[i] = linkArray[swapElt];
		linkArray[swapElt] = temp;
	}


	return linkArray;
}



function initializeTables() {
	
	size = NUMBER_BALLOTS * 2;

	// setup the pTable
	for (i = 0; i < size; i++)
	{
		pTable[i] = new ElementP((get_random() % 2), (get_random() % 2));
	}

	linkArray1 = createRandomLinks(size);
	linkArray2 = createRandomLinks(size);

	for (i = 0; i < size;)
	{
		dTable[i] = new ElementD(linkArray1[i], (get_random() % 2), (get_random() % 2), linkArray2[i]);

		pRow = dTable[i].voteRow;

		pVal = (pTable[pRow].topSheet + pTable[pRow].bottomSheet) % 2;
		dVal = (dTable[i].topSheet + dTable[i].bottomSheet) % 2;

		if (pVal == dVal)
			i++;
	}

	// setup the rTable
	for (i = 0; i < size; i++)
	{
		rTable[i] = new ElementR();
	}


	drawTable();
}

function drawTable()
{
	calculateVotes();

	drawPRows();
	drawDRows();
	drawRRows();

	// show everything
	if (current_step == STEP_1)
	{
		showRows();
	}
	else if (current_step == STEP_3)
	{
		showAuditedRows();
	}
	// show audited rows
	else if (current_step == STEP_4 || current_step == STEP_5)
	{
		showAuditedRows();
		showExposedSheets();
	}

	// show voted rows and post election columns
	if (current_step == STEP_5)
	{
		showPostElectionColumns();
		showVotes();
	}
}


function drawRRows()
{
	if (explorer)
		offset = 42;
	else
		offset = 43;

	el = document.getElementById("rTable");

	str = rTableHtml[0];

	for (i = 0; i < rTable.length; i++)
	{
		realOffset = offset + i*17;

		str += rTableHtml[1] + i;
		str += rTableHtml[2] + i;
		str += rTableHtml[3] + i;
		str += rTableHtml[4] + i;

		str += rTableHtml[5] + rTable[i].toString();
		str += rTableHtml[6] + i;
		str += rTableHtml[7] + realOffset;
		str += rTableHtml[8];
	}

	str += rTableHtml[9];

	el.innerHTML = str;
}

function showRows()
{
	for (num = 0; num < rTable.length; num++)
	{
		el = document.getElementById("rRowFader" + dTable[num].resultRow);
		setOpacity(el, 0.0);
		el = document.getElementById("pRowFader" + dTable[num].voteRow);
		setOpacity(el, 0.0);
		el = document.getElementById("dRowFader" + num);
		setOpacity(el, 0.0);		
	}
}


function showAuditedRows()
{
	for (num = 0; num < rTable.length; num++)
	{
		rRow = dTable[num].resultRow;
		vRow = dTable[num].voteRow;

		if (rTable[rRow].audited)
		{
			el = document.getElementById("rRowFader" + rRow);
			setOpacity(el, 0.0);
		}
		if (pTable[vRow].audited)
		{
			el = document.getElementById("pRowFader" + vRow);
			setOpacity(el, 0.0);
		}
		if (dTable[num].audited)
		{
			el = document.getElementById("dRowFader" + num);
			setOpacity(el, 0.0);		
		}
	}
}

function showVotes()
{
	for (num = 0; num < rTable.length; num++)
	{
		if (rTable[num].candidateVote != NO_VOTE)
		{
			el = document.getElementById("rRowFader" + num);
			setOpacity(el, 0.0);
		}
	}
}


function showAuditedRows()
{
	for (num = 0; num < rTable.length; num++)
	{
		rRow = dTable[num].resultRow;
		vRow = dTable[num].voteRow;

		if (rTable[rRow].audited)
		{
			el = document.getElementById("rRowFader" + rRow);
			setOpacity(el, 0.0);
		}
		if (pTable[vRow].audited)
		{
			el = document.getElementById("pRowFader" + vRow);
			setOpacity(el, 0.0);
		}
		if (dTable[num].audited)
		{
			el = document.getElementById("dRowFader" + num);
			setOpacity(el, 0.0);		
		}
	}
}


function showExposedSheets()
{
	for (num = 0; num < pTable.length; num++)
	{
		if (pTable[num].exposedSheet != NO_SHEET)
		{
			if (pTable[num].exposedSheet == BOTTOM_SHEET)
			{
				el = document.getElementById("pRowFader" + num);
				el.style.width = "85px";
			}
			else
			{
				el = document.getElementById("pRowFader" + num);
				el.style.left = "176px";
				el.style.width = "85px";
			}
		}
	}
}

function showPostElectionColumns()
{
	for (num = 0; num < dTable.length; num++)
	{
		if (dTable[num].postElectionAudit == LEFT_AUDIT)
		{
			el = document.getElementById("dRowFader" + num);
			el.style.left = "176px";
			el.style.width = "85px";
		}
		else if (dTable[num].postElectionAudit == RIGHT_AUDIT)
		{
			el = document.getElementById("dRowFader" + num);
			el.style.width = "85px";
		}
	}
}




function drawDRows()
{
	if (explorer)
		offset = 42;
	else
		offset = 43;

	el = document.getElementById("dTable");

	str = dTableHtml[0];

	for (i = 0; i < dTable.length; i++)
	{
		realOffset = offset + i*17;

		str += dTableHtml[1] + i;
		str += dTableHtml[2] + i;
		str += dTableHtml[3] + i;
		str += dTableHtml[4] + i;
		str += dTableHtml[5] + i;
		str += dTableHtml[6] + realOffset;


		//str += dTableHtml[7] + dTable[i].toString(COLUMN_VOTE_ROW);
		str += dTableHtml[7] + dTable[i].toString(COLUMN_TOP);
		str += dTableHtml[8] + dTable[i].toString(COLUMN_INTERMEDIATE);
		str += dTableHtml[9] + dTable[i].toString(COLUMN_BOTTOM);
		//str += dTableHtml[9] + dTable[i].toString(COLUMN_RESULT_ROW);
		str += dTableHtml[10];
	}

	str += dTableHtml[11];


	el.innerHTML = str;
}



function drawPRows()
{
	if (explorer)
		offset = 42;
	else
		offset = 43;

	el = document.getElementById("pTable");

	str = pTableHtml[10];

	for (i = 0; i < pTable.length; i++)
	{
		realOffset = offset + i*17;

		str += pTableHtml[0] + i;
		str += pTableHtml[1] + i;
		str += pTableHtml[2] + i;
		str += pTableHtml[3] + i;
		str += pTableHtml[4] + i;
		str += pTableHtml[5] + realOffset;
		str += pTableHtml[6] + i;
		str += pTableHtml[7] + pTable[i].toString(COLUMN_TOP);
		str += pTableHtml[7] + pTable[i].toString(COLUMN_BOTTOM);
		str += pTableHtml[8] + pTable[i].toString(COLUMN_VOTE);
		str += pTableHtml[9];
	}

	str += pTableHtml[11];

	el.innerHTML = str;
}



function calculateVotes()
{
	for (num = 0; num < dTable.length; num++)
	{
		rRow = dTable[num].resultRow;
		vRow = dTable[num].voteRow;

		if (pTable[vRow].voteSide != NO_VOTE)
		{
			dTable[num].intermediateVote = (pTable[vRow].voteSide + dTable[num].topSheet) % 2;

			rTable[rRow].candidateVote = (dTable[num].intermediateVote + dTable[num].bottomSheet) % 2;
		}
	}
}

