function FocusMainInput()
{
	document.getElementById("inputCombatantName").focus();
	document.getElementById("inputCombatantName").select();
}

function FocusEffectInput()
{
	document.getElementById("inputEffectName").focus();
	document.getElementById("inputEffectName").select();
}

function GetNameInput(divCombatant)
{
	return divCombatant.getElementsByTagName("input")[0];
}

function GetInitInput(divCombatant)
{
	return divCombatant.getElementsByTagName("input")[1];
}

function GetDexInput(divCombatant)
{
	return divCombatant.getElementsByTagName("input")[2];
}

function GetModInput(divCombatant)
{
	return divCombatant.getElementsByTagName("input")[3];
}

function GetHPInput(divCombatant)
{
	return divCombatant.getElementsByTagName("input")[4];
}

function GetMinusButton(divCombatant)
{
	return divCombatant.getElementsByTagName("input")[5];
}

function GetHPAdjustInput(divCombatant)
{
	return divCombatant.getElementsByTagName("input")[6];
}

function GetEqualsButton(divCombatant)
{
	return divCombatant.getElementsByTagName("input")[7];
}

function GetNotesInput(divCombatant)
{
	return divCombatant.getElementsByTagName("input")[8];
}

function GetEffectNotesInput(divCombatant)
{
	return divCombatant.getElementsByTagName("input")[2];
}

function GetEffectDurationInput(divCombatant)
{
	return divCombatant.getElementsByTagName("input")[3];
}

function GetDeleteButton(divCombatant)
{
	return divCombatant.getElementsByTagName("input")[9];
}

function GetEffectDeleteButton(divCombatant)
{
	return divCombatant.getElementsByTagName("input")[4];
}

function GetTestInput(divCombatant)
{
	var aInputs =  divCombatant.getElementsByTagName("input");
	var str = "";
	for (var i=0; i<aInputs.length; i++)
	{
		str += i;
		str += " - ";
		str += aInputs[i].id;
		str += "\n";
	}
	alert(str);
}

function EnterPressed(oEvent)
{
	if ( typeof oEvent != 'undefined' )
	{
		// If the enter key was pressed, return true
		if ( 13 == oEvent.keyCode )
		{
			return true;
		}
	}

	return false;
}

function AddCombatant()
{
	// Clone the data-entry div without ID
	var divNew = document.getElementById("divBase").cloneNode(true);
	divNew.id = "divCombatant";

	// Remove Add button and show Delete button and notes
	divNew.removeChild( divNew.getElementsByTagName("input")[0] );
//	GetTestInput(divNew);
	GetMinusButton(divNew).style.display = "";
	GetNotesInput(divNew).style.display = "";
	GetDeleteButton(divNew).style.display = "";

	document.getElementById("divMain").appendChild(divNew);

	var aNewInputs = [
		GetNameInput(divNew),
		GetInitInput(divNew),
		GetDexInput(divNew),
		GetModInput(divNew),
		GetHPInput(divNew)
		]

	for (var i=0; i<aNewInputs.length; i++)
	{
		// Remove the keydown handlers
		aNewInputs[i].onkeydown = null;

		// Keep the inputCombatantXxx fields unique for focus/select
		aNewInputs[i].id = "";
	}

	FocusMainInput();
	ResetInitControls();
}

function AddEffect()
{
	// Clone the data-entry div without ID
	var divNew = document.getElementById("divEffectBase").cloneNode(true);
	divNew.id = "divCombatant";

	// Remove Add button and show Delete button and notes
	divNew.removeChild( divNew.getElementsByTagName("input")[0] );
//	GetTestInput(divNew);
	GetEffectDeleteButton(divNew).style.display = "";

	document.getElementById("divMain").appendChild(divNew);

	var aNewInputs = [
		GetNameInput(divNew),
		GetInitInput(divNew),
		GetEffectNotesInput(divNew),
		GetEffectDurationInput(divNew)
		]

	for (var i=0; i<aNewInputs.length; i++)
	{
		// Remove the keydown handlers
		aNewInputs[i].onkeydown = null;

		// Keep the inputCombatantXxx fields unique for focus/select
		aNewInputs[i].id = "";
	}

	FocusEffectInput();
	ResetInitControls();
}

function ResetInitControls()
{
	// Show the "Mark First" button and the init roller
	document.getElementById("btnFirst").style.display = "";
	document.getElementById("divInitRoll").style.display = "";

	// Set the number of combatants to roll for
	var intCombatantCount = document.getElementById("divMain").childNodes.length;
	var intUnrolledCount = 0;

	if ( null != intCombatantCount )
	{
		for (var i=0; i<intCombatantCount; i++)
		{
			var divCurrent = document.getElementById("divMain").childNodes[i];
			if ( GetInitInput(divCurrent).value == '' )
			{
				intUnrolledCount++;
			}
		}
		document.getElementById("inputInitCount").value = intUnrolledCount;
	}
}

function addOnEnter(oEvent)
{
	// If the enter key was pressed, add from base
	if ( EnterPressed(oEvent) )
	{
		AddCombatant();
	}
}

function addEffectOnEnter(oEvent)
{
	// If the enter key was pressed, add from base
	if ( EnterPressed(oEvent) )
	{
		AddEffect();
	}
}

function AdjustHP(objSpanHPExtras)
{
	var objHPCurrent =
		GetHPInput(objSpanHPExtras.parentNode);
	var objHPAdjust = GetHPAdjustInput(objSpanHPExtras.parentNode);

	// Get the integer values from the input edit boxes
	var intHPCurrent = parseInt(objHPCurrent.value);
	var intHPAdjust = parseInt(objHPAdjust.value);

	// If any non-number values, return
	if (intHPCurrent != intHPCurrent) return;
	if (intHPAdjust != intHPAdjust) return;

	objHPCurrent.value = ( intHPCurrent - intHPAdjust );
}

function MinusClicked(objSpanHPExtras)
{
	var objHPAdjust = GetHPAdjustInput(objSpanHPExtras.parentNode);

	if ( "none" == objHPAdjust.style.display )
	{
		objHPAdjust.style.display = "";
		GetEqualsButton(objSpanHPExtras.parentNode).style.display = "";
	}
	else
	{
		AdjustHP(objSpanHPExtras);
	}

	objHPAdjust.focus();
	objHPAdjust.select();
}

function HideCalculator(objSpanHPExtras)
{
	var objHPAdjust = GetHPAdjustInput(objSpanHPExtras.parentNode);
	objHPAdjust.value = "1";
	objHPAdjust.style.display = "none";

	GetEqualsButton(objSpanHPExtras.parentNode).style.display = "none";
}

function EqualsClicked(objSpanHPExtras)
{
	AdjustHP(objSpanHPExtras);
	HideCalculator(objSpanHPExtras);
}

function calculateOnEnter(oEvent, objSpanHPExtras)
{
	// If the enter key was pressed, treat as click on equals
	if ( EnterPressed(oEvent) )
	{
		EqualsClicked(objSpanHPExtras);
	}
	// If the escape key was pressed, collapse calculator
	else if ( 27 == oEvent.keyCode )
	{
		HideCalculator(objSpanHPExtras);
	}
}

function DeleteCombatant(objDiv)
{
	if ( IsMarked( objDiv ) )
	{
		MarkNext();
	}

	objDiv.parentNode.removeChild(objDiv);
}

function MarkFirst()
{
	document.getElementById("btnNext").style.display="";
	UnmarkAll();

	ResetRound();
	Mark( document.getElementById("divMain").getElementsByTagName("div")[0] );
}

function MarkNext()
{
	var ainputCombatants = document.getElementById("divMain").getElementsByTagName("div");
	var intCombatantCount = ainputCombatants.length;
	var intCurrentMark = 0;

	if ( null != intCombatantCount )
	{
		// Find marked combatant
		for (var i=0; i<intCombatantCount; i++)
		{
			if ( IsMarked( ainputCombatants[i] ) )
			{
				Unmark( ainputCombatants[i] );

				if ( i < intCombatantCount - 1 )
				{
					intCurrentMark = i + 1;
				}
				else
				{
					IncrementRound();
					intCurrentMark = 0;
				}
			}
		}
	}

	Mark( ainputCombatants[intCurrentMark] );
}

function Mark(objDiv)
{
	objDiv.style.borderLeftColor = "#008000";
	objDiv.style.borderTopColor = "#008000";

	DecrementDuration(objDiv);
}

function Unmark(objDiv)
{
	objDiv.style.border = "3px solid #FFFFFF";
}

function UnmarkAll()
{
	// Hide all marks
	var ainputCombatants = document.getElementById("divMain").getElementsByTagName("div");
	var intCombatantCount = ainputCombatants.length;

	if ( null != intCombatantCount )
	{
		for (var i=0; i<intCombatantCount; i++)
		{
			Unmark( ainputCombatants[i] );
		}
	}
}

function IsMarked(objDiv)
{
	return objDiv.style.borderLeftColor != objDiv.style.borderRightColor;
}

function ResetRound()
{
	var objRound = document.getElementById("inputRound");
	objRound.value = 1;
}

function IncrementRound()
{
	var objRound = document.getElementById("inputRound");
	++objRound.value;
}

function DecrementDuration(objDiv)
{
	// If this is an effect with a duration
	var inputs = objDiv.getElementsByTagName("input");
	for ( var i = 0; i < inputs.length; ++i )
	{
		if ( inputs[i].name == "inputEffectDuration" )
		{
			if ( inputs[i].value > 0 )
			{
				// Decrement duration
				--inputs[i].value;
				if ( inputs[i].value == 0 )
				{
					inputs[0].style.color = "red";
					inputs[0].style.fontWeight = "bold";
				}
			}
		}
	}
}

function SortCombatants()
{
/*
	// Bubble sort combatants
	for (var i=0; i<(divMain.children.length-1); i++)
	{
		for (var j=i+1; j<divMain.children.length; j++)
		{
			if (compareRows(divMain.children[i], divMain.children[j]) < 0)
			{
				swapRows( divMain.children(i), divMain.children(j) );
			}
		}
	}
*/
	// Quick sort combatants
	var ainputCombatants = document.getElementById("divMain").getElementsByTagName("div");
	quicksort (ainputCombatants, 0, ainputCombatants.length - 1);
}

function quicksort (a, lo, hi)
{
//  lo is the lower index, hi is the upper index
//  of the region of array a that is to be sorted
	var i=lo, j=hi;
	var x=a[ parseInt( (lo+hi)/2 ) ];

	//  partition
	do
	{
		// while (a[i]<x) i++;
		while ( compareRows(a[i], x) > 0 ) i++;
		// while (a[j]>x) j--;
		while ( compareRows(a[j], x) < 0 ) j--;
		if (i<=j)
		{
			swapRows(a[i], a[j]);
			i++; j--;
		}
	} while (i<=j);

	//  recursion
	if (lo<j) quicksort(a, lo, j);
	if (i<hi) quicksort(a, i, hi);
}

function compareRows(a,b)
{
	// Compare combatants by Init then Dex
	var intResult =
		GetInitInput(a).value - GetInitInput(b).value;

	if ( 0 == intResult )
	{
		intResult =
			GetDexInput(a).value - GetDexInput(b).value;
	}

	return intResult;
}

function swapRows(a,b)
{
	if ( a == b ) return;

	var bNext = b.nextSibling;
	document.getElementById("divMain").removeChild(b);

	var aNext = a.nextSibling;
	document.getElementById("divMain").removeChild(a);

	if ( aNext )
	{
		document.getElementById("divMain").insertBefore(b, aNext);
	}
	else
	{
		document.getElementById("divMain").appendChild(b);
	}

	if ( bNext )
	{
		document.getElementById("divMain").insertBefore(a, bNext);
	}
	else
	{
		document.getElementById("divMain").appendChild(a);
	}
}

function ClearInitiative()
{
	var ainputCombatants = document.getElementById("divMain").getElementsByTagName("div");
	for (i = 0; i < ainputCombatants.length; i++)
	{
		GetInitInput( ainputCombatants[i] ).value = "";
	}
	UnmarkAll();
	document.getElementById("btnNext").style.display="none";
}

function RollInitiative()
{
	// Get the integer values from the input edit boxes
	intRollCount = parseInt(document.getElementById("inputInitCount").value);

	// If non-number count, return
	if (intRollCount != intRollCount) return;

	// Get the first n blank, visible initiative edit boxes
	var aobjInitEdits = new Array();
	var aobjModEdits = new Array();
	var intInitEditCount = 0;
	var ainputCombatants = document.getElementById("divMain").getElementsByTagName("div");
	for (i = 0; i < ainputCombatants.length; i++)
	{
		if ( ( GetInitInput( ainputCombatants[i] ).value == "") )
		{
			aobjInitEdits[intInitEditCount] = GetInitInput( ainputCombatants[i] );
			aobjModEdits[intInitEditCount++] = GetModInput( ainputCombatants[i] );
		}
	}

	for (intEditIndex = 0; intEditIndex < intInitEditCount; intEditIndex++)
	{
		if (intEditIndex >= intRollCount) break;

		var intCurrentRollMod = parseInt(aobjModEdits[intEditIndex].value);
		if (intCurrentRollMod != intCurrentRollMod)
		{
			intCurrentRollMod = 0;
		}

		var objRoll = new CRoll(20, 1, intCurrentRollMod);

		aobjInitEdits[intEditIndex].value = objRoll.m_intTotal;
	}
}

function rollInitOnEnter(oEvent)
{
	// If the enter key was pressed, roll
	if ( EnterPressed(oEvent) )
	{
		RollInitiative();
	}
}

var xml_doc;

function readFile()
{
	// Put combatants from xml in HTML page
	var inputName = document.getElementById("divBase").getElementsByTagName("input")[1];
	var inputDex = document.getElementById("divBase").getElementsByTagName("input")[3];
	var inputMod = document.getElementById("divBase").getElementsByTagName("input")[4];
	var inputHP = document.getElementById("divBase").getElementsByTagName("input")[5];

	xmlCombatants = xml_doc.getElementsByTagName("combatant");

	var intCombatantCount = xmlCombatants.length;

	for ( i=0; i<intCombatantCount; i++ )
	{
		inputName.value = readNodeValue(xmlCombatants[i].getElementsByTagName("name")[0]);
		inputDex.value = readNodeValue(xmlCombatants[i].getElementsByTagName("dex")[0]);
		inputMod.value = readNodeValue(xmlCombatants[i].getElementsByTagName("mod")[0]);
		inputHP.value = readNodeValue(xmlCombatants[i].getElementsByTagName("hp")[0]);

		AddCombatant();
	}
}

function readNodeValue(node)
{
	if ( node.firstChild )
	{
		return node.firstChild.nodeValue;
	}
	return "";
}

function addTextNode(parent, strNodeName, strNodeText)
{
	var newNode=xml_doc.createElement(strNodeName);
	var newText=xml_doc.createTextNode(strNodeText);
	newNode.appendChild(newText);
	parent.appendChild(newNode);
}

function exportXML()
{
	// Account for browser XML implementations - yuck
	var moz = (document.implementation && document.implementation.createDocument) ? true:false;
	var ie = (window.ActiveXObject && document.all) ? true:false;

	if (moz)
	{
		xml_doc = document.implementation.createDocument("", "group", null);
	}
	else if (ie)
	{
		xml_doc = new ActiveXObject("Microsoft.XMLDOM");
		xml_doc.loadXML("<group/>");
	}
	else
	{
		alert("Your browser supports neither Mozilla-style XML document creation nor IE-style ActiveX XML objects. Bummer.");
		return;
	}

	xml_doc.async = false;

	var ainputCombatants = document.getElementById("divMain").getElementsByTagName("div");
	for (i = 0; i < ainputCombatants.length; i++)
	{
		var combatantNode=xml_doc.createElement("combatant")

		addTextNode(combatantNode, "name", GetNameInput( ainputCombatants[i] ).value);
		addTextNode(combatantNode, "dex", GetDexInput( ainputCombatants[i] ).value);
		addTextNode(combatantNode, "mod", GetModInput( ainputCombatants[i] ).value);
		addTextNode(combatantNode, "hp", GetHPInput( ainputCombatants[i] ).value);

		xml_doc.documentElement.appendChild(combatantNode);
	}

	var strXML = "";
	if (moz)
	{
		var serializer = new XMLSerializer();
		strXML = serializer.serializeToString(xml_doc);
	}
	else if (ie)
	{
		strXML = xml_doc.xml;
	}
	strXML = strXML.replace(/></g, ">\n<");
	var aLines = strXML.split("\n");

	var xmlOut = document.getElementById("inputXMLOut")
	xmlOut.parentNode.style.display = "";
	xmlOut.rows = aLines.length;
	xmlOut.value = strXML;
}

function importXML(strFileName)
{
	// Account for browser XML implementations - yuck
	var moz = (document.implementation && document.implementation.createDocument) ? true:false;
	var ie = (window.ActiveXObject && document.all) ? true:false;

	if (moz)
	{
		xml_doc = document.implementation.createDocument("", "", null);
		xml_doc.onload = readFile;
		if ( 0 != strFileName.search(/http:/) )
		{
			strFileName = "file:///" + strFileName;
		}
	}
	else if (ie)
	{
		xml_doc = new ActiveXObject("Microsoft.XMLDOM");
	}
	else
	{
		alert("Your browser supports neither Mozilla-style XML document creation nor IE-style ActiveX XML objects. Bummer.");
	}

	xml_doc.async = false;
	xml_doc.load(strFileName);

	if (ie)
	{
		readFile();
	}
}

function AddFromXML(strFileName)
{
	var inputName = document.getElementById("divBase").getElementsByTagName("input")[1];
	var inputDex = document.getElementById("divBase").getElementsByTagName("input")[3];
	var inputMod = document.getElementById("divBase").getElementsByTagName("input")[4];
	var inputHP = document.getElementById("divBase").getElementsByTagName("input")[5];

	var strOldName = inputName.value;
	var strOldDex = inputDex.value;
	var strOldMod = inputMod.value;
	var strOldHP = inputHP.value;

	importXML(strFileName);

	inputName.value = strOldName;
	inputDex.value = strOldDex;
	inputMod.value = strOldMod;
	inputHP.value = strOldHP;
	FocusMainInput();
}

function addFromXMLOnEnter(oEvent, strFileName)
{
	// If the enter key was pressed, add from XML
	if ( EnterPressed(oEvent) )
	{
		AddFromXML(strFileName);
	}
}
