//
// Copyright Alexander Ljungberg, 2006
//
// http://www.norwinter.com
//

window.onload = initKonkret;

var d = document;
var MAX_HISTORY = 10;
var rollHistory = new Array(MAX_HISTORY);
var rollHistorySize = 0;
var MAX_MEMORY = 10;
var rollMemory = new Array(MAX_MEMORY);
var rollMemorySize = 0;

var forumDisp = false;
var whatses = new Array();

function initKonkret() {
	setScreen(0);
	displaySystemOption(false);
	displayForumOrResult(false);
}

function setScreen(screenNo) {
	d.getElementById("rollbuttonSelected").style.visibility=(screenNo==0?"visible":"hidden");
	d.getElementById("rollbuttonUnselected").style.visibility=(screenNo==0?"hidden":"visible");
	d.getElementById("rollbox").style.visibility=(screenNo==0?"visible":"hidden");
	// Work around a bug in Firefox involving scrollbars for hidden layers.
	d.getElementById("rollbox").style.overflow=(screenNo==0?"auto":"hidden");
	
	d.getElementById("savedbuttonSelected").style.visibility=(screenNo==1?"visible":"hidden");
	d.getElementById("savedbuttonUnselected").style.visibility=(screenNo==1?"hidden":"visible");
	d.getElementById("savedbox").style.visibility=(screenNo==1?"visible":"hidden");
	d.getElementById("savedbox").style.overflow=(screenNo==1?"auto":"hidden");

	d.getElementById("historybuttonSelected").style.visibility=(screenNo==2?"visible":"hidden");
	d.getElementById("historybuttonUnselected").style.visibility=(screenNo==2?"hidden":"visible");
	d.getElementById("historybox").style.visibility=(screenNo==2?"visible":"hidden");
	d.getElementById("historybox").style.overflow=(screenNo==2?"auto":"hidden");
}

function displaySystemOption(nonAutomatic) {
	sel = parseNumber(d.getElementById("_systemType").value, 0, 0, 3);
	
	d.getElementById("systemParamNone").style.display=(sel==0?"inline":"none");
	d.getElementById("systemParamWod").style.display=(sel==1?"inline":"none");
	d.getElementById("systemParamWeg").style.display=(sel==2?"inline":"none");
	d.getElementById("systemParamNWod").style.display=(sel==3?"inline":"none");

	if (nonAutomatic) {
		// Default to a D10 for WOD.
		if (sel == 1 || sel == 3) {
			d.getElementById("_dieType").value = 10; 
			d.getElementById("_summation").checked = false; 
			d.getElementById("_lowdrop").checked = false; 
		}
	
		// If we're playing WEG, default to a D6, and turn on sums.
		if (sel == 2) {
			d.getElementById("_dieType").value = 6; 
			d.getElementById("_summation").checked = true; 
		}

	}
}

function nWodSel(which) {
	if (which & 1) {
		d.getElementById("_nwod10").checked = true;
	}
	if (which & 2) {
		d.getElementById("_nwod9").checked = true;
	}
}

function oWodSel(which) {
	if (which & 1) {
		d.getElementById("_owod10").checked = true;
	}
	if (which & 2) {
		d.getElementById("_owod9").checked = true;
	}
}

function toggleForum(nonAutomatic) {
	forumDisp = !forumDisp;
	displayForumOrResult(nonAutomatic);
}

function displayForumOrResult(nonAutomatic) {
	d.getElementById("forumSection").style.display=(forumDisp?"inline":"none");
	d.getElementById("_doRoll").disabled=(forumDisp?true:false);
	d.getElementById("resultSection").style.display=(!forumDisp?"inline":"none");
}

function toggleWhats(which) {
	whatses[which] = !whatses[which];
	if (whatses[which])
		showWhats(which);
	else
		hideWhats(which);
}

function showWhats(which) {
	b = d.getElementById("whats"+which);
	b.style.display="block";
}

function hideWhats(which) {
	b = d.getElementById("whats"+which);
	b.style.display="none";
}

function parseNumber(number, defval, lower, higher) {
	if (isNaN(number))
		number = defval;
	number = Math.max(lower, number);
	number = Math.min(higher, number);
	
	return number;
}

function randInt(lower, higher) {
	var r = Math.random()*(higher-lower+1);
	return Math.floor(r+lower);
}

function RollObject(nSides, nPool) {
	this.sides = nSides;
	// Remember this in case the system modifies it
	this.initialPool = nPool;
	this.pool = nPool;
	this.diceValues = new Array(nPool);
	this.diceDropped = new Array(nPool);
	
	this.sum = 0;
	
	this.diceWodType = new Array(nPool);
	this.wodSuccesses = 0;
	this.newWod = false;
	this.wodAgain = new Array();
	this.wodAgainDice = new Array(nPool);
	this.wegWildDie = this.pool-1;
	this.wegDropHigh = false;
	this.wegIgnore = false;
}

function rollDice(result) {
	var i;
	for(i=0; i<result.pool; i++) {
		result.diceValues[i] = randInt(1, result.sides)+result.modifier;
		if (result.capDown && result.diceValues[i]<1)
			result.diceValues[i] = 1;
		if (!result.wegIgnore && result.weg && i+1 == result.pool) {
			// Do the wild die
			if (i == result.wegWildDie && result.diceValues[i] == 1) {
				// Drop the wild and the highest
				result.wegDropHigh = true;
				result.diceDropped[i] = true;
			} else if (result.diceValues[i] == 6) {
				result.pool++;
				firstWild = false;
			}
		}
		
		for(j=0; j<result.wodAgain.length; j++) {
			if (result.diceValues[i] == result.wodAgain[j]) {
				result.pool++;
				result.wodAgainDice[i] = true;
			}
		}
	}
	
	if (result.dropLow) {
		var smallInd = 0;
		for(i=result.pool; i>0; i--) {
			if (result.diceValues[i]<result.diceValues[smallInd])
				smallInd = i;
		}
		result.diceDropped[smallInd] = true;
	}
	
	if (result.wegDropHigh) {
		var bigInd = 0;
		for(i=result.pool; i>0; i--) {
			if (i == result.wegWildDie)
				continue; // Don't wanna drop the Wild Die twice.
			if (result.diceValues[i]>result.diceValues[bigInd])
				bigInd = i;
		}
		result.diceDropped[bigInd] = true;
	}
	
	if (result.doSum) {
		for(i=0; i<result.pool; i++) {
			if (!((result.dropLow || result.wegDropHigh) && result.diceDropped[i]))
				result.sum += result.diceValues[i];
		}
	}
	
	result.sum += result.sumMod;
	
	if (result.wodDiff>0) {
		for(i=0; i<result.pool; i++) {
			if (result.dropLow && result.diceDropped[i])
				continue; // Kinda weird to drop lowest for WOD. But who knows.
			if (!result.newWod && result.diceValues[i] < 2) { // Botch
				result.wodSuccesses--;
				result.diceWodType[i] = 1;
			} else if (result.diceValues[i]>=result.wodDiff) { // Success
				result.wodSuccesses++;
				result.diceWodType[i] = 2;
			} else { // Miss
				result.diceWodType[i] = 0;
			}
		}
	}
	return result;
}

function rollToText(rollResult) {
	var modText="";
	if (rollResult.modifier<0)
		modText = rollResult.modifier;
	else
		modText = "+"+rollResult.modifier;

	var resultEl = d.createElement("div");

	// Floats gotta go first.
	if (rollResult.doSum) {
		var sum = d.createElement("span");
		sum.className = "sumResult";
		var sumModText = "";
		if (rollResult.sumMod<0)
			sumModText = rollResult.sumMod;
		else if (rollResult.sumMod>0)
			sumModText = "+"+rollResult.sumMod;
		sum.appendChild(d.createTextNode("(Sum"+sumModText+": "+rollResult.sum+")"));	
		resultEl.appendChild(sum);
	}
	
	if (rollResult.wodDiff > 0) {
		var wod = d.createElement("span");
		wod.className = "wodResult";
		wod.appendChild(d.createTextNode("(WOD Result: "+rollResult.wodSuccesses+")"));	
		resultEl.appendChild(wod);
	}

	var desc = d.createElement("span");
	desc.className = "rollDesc";
	var descTxt = d.createTextNode(rollResult.initialPool + "x(D"+rollResult.sides+modText+"): ");
	desc.appendChild(descTxt);
	resultEl.appendChild(desc);

	var i;
	for (i=0; i<rollResult.pool; i++) {
		if ((rollResult.system==1 || rollResult.system == 3) && i>=rollResult.initialPool) {
			bar = d.createTextNode("+");
			resultEl.appendChild(bar);
		}
		var die = d.createElement("span");
		var dieTxt;
		var s = rollResult.diceValues[i];
		if(rollResult.weg && i >= rollResult.wegWildDie) {
			die.className = "wegWild";
			// If the Wild Die was dropped, put it in ().
			if (rollResult.diceDropped[i])
				dieTxt = d.createTextNode("("+s+") ");
			else
				dieTxt = d.createTextNode(s+" ");
		} else if (rollResult.diceDropped[i])  { // Dropped value
			die.className = "lowestDropped";
			dieTxt = d.createTextNode("("+s+") ");
		}  else if(rollResult.diceWodType[i] == 1) {
			// Botch
			die.className = "wodBotch";
			dieTxt = d.createTextNode(s+" ");			
		}  else if(rollResult.diceWodType[i] == 2) { // Success
			die.className = "wodSuccess";
			if (rollResult.wodAgainDice[i])
				die.className = "wodSuccessAgain";
			else
				die.className = "wodSuccess";
			dieTxt = d.createTextNode(s+" ");
		} else {
			if (rollResult.wodAgainDice[i])
				die.className = "wodAgain";

			dieTxt = d.createTextNode(s+" ");
		}
		die.appendChild(dieTxt);	
		resultEl.appendChild(die);
		
	}

	return resultEl;
}

function putSaved(roll) {
	// Remove it if its in the list already.
	var i;
	for (i=0; i<rollMemorySize; i++) {
		if (rollMemory[i].label == roll.label) {
			var j;
			for (j=i; j<rollMemorySize-1; j++) {
				rollMemory[j] = rollMemory[j+1];
			}
			rollMemorySize--;
			break;
		}
	}
	
	// Put it at the top.
	rollMemorySize = Math.min(rollMemorySize+1, MAX_MEMORY);
	for (i=Math.min(rollMemorySize, MAX_MEMORY); i>=1; i--) {
		rollMemory[i] = rollMemory[i-1];
	}
	rollMemory[0] = roll;

	updateSavedScreen();
}

function updateSavedScreen() {
	var sel = d.getElementById("_rollRecall");
	while(sel.options.length) {
		sel.remove(0);
	}
	
	var i;
	for(i=0; i<rollMemorySize; i++) {
		// Oh yeah, DOM 0! Thank IE for making crossbrowser stuff so easy!
		sel.options[i] = new Option(rollMemory[i].label, i);
	}	
}

function putHistory(rollResult) {
	if (rollHistorySize<MAX_HISTORY) {
		rollHistory[rollHistorySize++] = rollResult;
	} else {
		var i;
		for (i=0; i<MAX_HISTORY-1; i++) {
			rollHistory[i] = rollHistory[i+1];
		}
		rollHistory[MAX_HISTORY-1] = rollResult;
	}
	updateHistoryScreen();
}

function updateHistoryScreen() {
	var rs = d.getElementById("historySet");
	
	var list = d.createElement("span");
	var i;
	for (i=0; i<rollHistorySize; i++) {
		var p = d.createElement("div");
		var time = d.createElement("span");
		time.className = "historyTime";
		time.appendChild(d.createTextNode("("+rollHistory[i][2]+") "));
		p.appendChild(time);
		if (rollHistory[i][1].length>0) {
			var label = d.createElement("span");
			label.className = "historyLabel";
			label.appendChild(d.createTextNode('"'+rollHistory[i][1]+'"'));
			p.appendChild(label);
		}
		p.appendChild(rollHistory[i][0]);
		list.appendChild(p);
	}
	
	rs.replaceChild(list, rs.firstChild);	
}

function doRestoreAndRoll() {
	var ind = d.getElementById("_rollRecall").value;
	if (ind == "Na")
		return;

	setScreen(0);
	
	var r = rollMemory[ind];
	
	d.getElementById("_label").value = ""; // Prevent accidental overwriting
	d.getElementById("_dieType").value = r.sides;
	d.getElementById("_pool").value = r.pool;
	d.getElementById("_repeat").value = r.repeat;
	d.getElementById("_lowdrop").checked = r.lowdrop;
	d.getElementById("_lowcap").checked = r.lowcap;
	d.getElementById("_summation").checked = r.summation;
	d.getElementById("_wodDiff").value = (r.diff>0?r.diff:6);
	d.getElementById("_systemType").value = r.system;
	d.getElementById("_wegIgnore").checked = r.wegIgnore;
	d.getElementById("_modType").value = (r.modifier != 0?"1":"0");
	d.getElementById("_modifier").value = (r.modifier != 0?r.modifier:r.sumMod);
	
	for(i=0; i<r.wodAgain.length; i++) {
		rep = r.wodAgain[i];
		if (r.system == 3) {
			base = "_nwod";
		} else {
			base = "_owod";
		}
		d.getElementById(base+rep).checked = true;
	}

	displaySystemOption(false);
	
	doRoll();
}

function MemoryEntry() {
}


// Helper method for cloning dice rolls
function cloneObject(what) {
    for (i in what) {
        this[i] = what[i];
    }
}

function getRoll() {
	var sides = parseNumber(d.getElementById("_dieType").value, 10, 1, 100);
	var pool = parseNumber(d.getElementById("_pool").value, 10, 1, 99);
	var modType = parseNumber(d.getElementById("_modType").value, 0, 0, 1);
	var modifier = 0;
	var sumMod = 0;
	if (modType == 1)
		modifier = parseNumber(d.getElementById("_modifier").value, 0, -10000, +10000);
	else
		sumMod = parseNumber(d.getElementById("_modifier").value, 0, -10000, +10000);
	var lowdrop = d.getElementById("_lowdrop").checked;
	var summation = d.getElementById("_summation").checked;
	var lowcap = d.getElementById("_lowcap").checked;
	var system = parseNumber(d.getElementById("_systemType").value, 0, 0, 3);
	var repeat = parseNumber(d.getElementById("_repeat").value, 1, 1, 10);
	var label = d.getElementById("_label").value;

	
	var wod = false; var newWod = false;
	var diff = 0;
	var wodAgain = new Array();
	if (system == 1) {
		wod = true;
		var wi = 0;
		if (d.getElementById("_owod10").checked)
			wodAgain[wi++] = 10;
		if (d.getElementById("_owod9").checked)
			wodAgain[wi++] = 9;
		if (d.getElementById("_owod8").checked)
			wodAgain[wi++] = 8;		
	}
	if (system == 3) {
		wod = true; newWod = true;
		diff = 8; // Always 8 in the new system.
	
		var wi = 0;
		if (d.getElementById("_nwod10").checked)
			wodAgain[wi++] = 10;
		if (d.getElementById("_nwod9").checked)
			wodAgain[wi++] = 9;
		if (d.getElementById("_nwod8").checked)
			wodAgain[wi++] = 8;
	}
	var weg = false;
	if (system == 2)
		weg = true;

	if (wod && !newWod)
		diff = parseNumber(d.getElementById("_wodDiff").value, 6, 1, 10);

	var wegIgnore = false;
	if (weg)
		wegIgnore = d.getElementById("_wegIgnore").checked;

	var rollEntry = new RollObject(sides, pool);
	rollEntry.modifier = modifier;
	rollEntry.sumMod = sumMod;
	rollEntry.dropLow = lowdrop;
	rollEntry.doSum = summation;
	rollEntry.wodDiff = diff;
	rollEntry.newWod = newWod;
	rollEntry.wodAgain = wodAgain;
	rollEntry.weg = weg;
	rollEntry.wegIgnore = wegIgnore;
	rollEntry.capDown = lowcap;
	rollEntry.repeat = repeat;
	rollEntry.label = label;
	rollEntry.system = system;

	return rollEntry;
}

function copyRoll(r) {
	var rollEntry = new RollObject(r.sides, r.pool);
	rollEntry.modifier = r.modifier;
	rollEntry.dropLow = r.dropLow;
	rollEntry.doSum = r.doSum;
	rollEntry.wodDiff = r.wodDiff;
	rollEntry.newWod = r.newWod;
	rollEntry.wodAgain = r.wodAgain;
	rollEntry.weg = r.weg;
	rollEntry.wegIgnore = r.wegIgnore;
	rollEntry.capDown = r.capDown;
	rollEntry.repeat = r.repeat;
	rollEntry.label = r.label;
	rollEntry.system = r.system;
	rollEntry.sumMod = r.sumMod;

	return rollEntry;
}

function webRollUpdate_cb(nc) {
	rs = d.getElementById("rollCount");
	rs.replaceChild(d.createTextNode(nc), rs.firstChild);
}

function doRoll() {
	// Send a roll count increment request
	x_addWebRoll(webRollUpdate_cb);
	
	// Make sure the rolling screen is visible.
	setScreen(0);
	// Make sure the results section is visible.
	forumDisp = false;
	displayForumOrResult(false);
	
	oRoll = getRoll();
	d.getElementById("_label").value = ""; // Prevent accidental overwriting

	var rs = d.getElementById("resultSet");
	var newContent = d.createElement("span");

	var i;
	for (i=0; i<oRoll.repeat; i++) {
		rollEntry = copyRoll(oRoll);		

		var rollResult = rollDice(rollEntry);
		var textResult = rollToText(rollResult);
		newContent.appendChild(textResult);

		var ha = new Array(3);
		ha[0] = textResult.cloneNode(true);
		ha[1] = rollEntry.label;
		Da = new Date();
		ha[2] = Da.toLocaleTimeString();
		putHistory(ha);
	}

	rs.replaceChild(newContent, rs.firstChild);
	
	if (oRoll.label.length>0) {
		// Create a 'memory' entry.
		var sa = new MemoryEntry();
		sa.label = oRoll.label;
		sa.sides = oRoll.sides;
		sa.pool = oRoll.pool;
		sa.modifier = oRoll.modifier;
		sa.repeat = oRoll.repeat;
		sa.lowdrop = oRoll.dropLow;
		sa.summation = oRoll.doSum;
		sa.lowcap = oRoll.capDown;
		sa.diff = oRoll.wodDiff;
		sa.system = oRoll.system;
		sa.wegIgnore = oRoll.wegIgnore;
		sa.sumMod = oRoll.sumMod;
		sa.wodAgain = oRoll.wodAgain;
	
		putSaved(sa);
	}
}

var forumTimer = 0;
var forumBarWidth = 50;
var forumBar2Width = 25;
var forumBarPosition = -forumBar2Width;
var forumTarget = "";
var forumLink = "";

function doPost(which) {
	
	if (which == "rpd") {
		forumLink = d.getElementById("_rpdLink").value;
		if (forumLink == "" || 
			forumLink == "http://s10.invisionfree.com/Role_Players_Direct/index.php?" ||
			forumLink == "http://s10.invisionfree.com/Role_Players_Direct/") {
			d.getElementById("forumResultBar1").style.display = "none";
			clearInterval(forumTimer);
			setForumMsg("Please enter a forum link.");
			d.getElementById("forumResults").style.display = "inline";
			location.href = "#forumresults";
			return;
		}
	} 
	
	if (forumLink == "") {
		alert("No link error.");
		return;
	}
		
	d.getElementById("forumResults").style.display = "inline";
	location.href = "#forumresults";

	
	d.getElementById("forumResultBar1").style.display = "block";
	forumBarPosition = -forumBar2Width;
	if (!forumTimer) {
		forumTimer = setInterval("updateForumBar()", 25);
	}
	var rs = d.getElementById("historySet");

	setForumMsg("Logging in...");
	
	forumTarget = which;
	x_doForumConnect(which, forumGotConnect_cb);
}

function forumGotConnect_cb(r) {
	err = r;
	location.href = "#forumresults";
	if (err != "") {
		d.getElementById("forumResultBar1").style.display = "none";
		clearInterval(forumTimer);
		setForumMsg("Failed to connect! ("+err+")");
	} else {
		setForumMsg("Posting roll...");
		r = getRoll();
	
		var abit = 0;
		for(var i=0; i<r.wodAgain.length; i++) {
			if (r.wodAgain[i] == 10)
				abit = abit | 1;
			if (r.wodAgain[i] == 9)
				abit = abit | 2;
			if (r.wodAgain[i] == 8)
				abit = abit | 4;
		}
	
		x_doForumPost(forumTarget,
		forumLink,
		r.sides,
		r.pool,
		r.modifier,
		r.dropLow,
		r.doSum,
		r.wodDiff,
		r.weg,
		r.wegIgnore,
		r.capDown,
		r.repeat,
		r.label,
		r.sumMod,
		abit,
		r.newWod,
		forumGotPost_cb);
	}
}

function forumGotPost_cb(err) {
	d.getElementById("forumResultBar1").style.display = "none";
	clearInterval(forumTimer);
	location.href = "#forumresults";
	if (err != "") {
		setForumMsg("Failed to post! ("+err+")");
	} else {
		setForumMsg("A new roll has been posted! (No errors detected)");
	}
}


function setForumMsg(msg) {
	rs = d.getElementById("forumResultsMsg");
	rs.replaceChild(d.createTextNode(msg), rs.firstChild);	
}

function updateForumBar() {
	forumBarPosition++;
	if (forumBarPosition>forumBarWidth)
		forumBarPosition = -forumBar2Width;
	d.getElementById("forumResultBar2").style.left = forumBarPosition+"px";
}
