var Infinum = 1000000;

var Event_SimulationSpecified = false;
var Event_SimulationNumber;
var Event_SimulationXs;
var Event_SimulationYs;
var Event_SimulationTs; // times at (x,y)
var Event_SimulationOs; // time origins
var Event_SimulationSplits; // split times at controls
var Event_SimulationRunnables;
var Event_SimulationChaseEnabled = false;
var Event_SimulationSplitsSpecified = false;

var SimStarted = false;
var SimPaused = false;
var SimTimerId;
var SimTimeScale; // = SimTimeScales[SimTimeScaleDefault];
var SimFrameRate; // = SimFrameRates[SimFrameRateDefault];
var SimFrameNumber;
var SimFrame = 0;
var SimPoss;
var SimMaxT;
var SimMinO;
var SimChase = false;
var SimScrollMode; // = SimScrollModeDefault;

var SimControlNumber;
var SimCurControl;
var SimPassedControls;
var SimShowSplits = false;

function SecondsToString(t)
{
	var hh = Math.floor(t / 3600);
	var mm = Math.floor(t % 3600 / 60);
	var ss = Math.floor(t % 60);
	return hh + ":" + (mm < 10? "0" : "") + mm + ":" + (ss < 10? "0" : "") + ss;
}

function SecondsToStringWoHours(t)
{
	var hh = Math.floor(t / 3600);
	var mm = Math.floor(t % 3600 / 60);
	var ss = Math.floor(t % 60);
	return (hh == 0? "" : (hh + ":")) + (mm < 10? "0" : "") + mm + ":" + (ss < 10? "0" : "") + ss;
}

function SimOnLoadingOptions()
{
	SimTimeScale = SimTimeScales[SimTimeScaleDefault];
	SimFrameRate = SimFrameRates[SimFrameRateDefault];
	SimScrollMode = SimScrollModeDefault;
}

function SimFindControlNumber()
{
	SimControlNumber = 0;
	if (Event_SimulationSplitsSpecified)
	{
		for (i = 1; i < Event_SimulationNumber; i++)
		{
			if (!Event_SimulationRunnables[i]) continue;
			SimControlNumber = Event_SimulationSplits[i].length - 2;
			break;
		}
	}
}

function SimShowTime()
{
	var t = SimFrame / (SimFrameRate * SimTimeScale);
	if (SimChase && SimStarted) t += SimMinO;
	document.getElementById("simdisplay").innerHTML = SecondsToString(t);
}

function SimScroll()
{
	var vp = document.getElementById("viewport");
	var ms = document.getElementById("mapspace");
	if ((vp.scrollWidth < 2 * SimScrollSensitiveMargin) ||
		(vp.scrollHeight < 2 * SimScrollSensitiveMargin)) return;
	
	var view_left = vp.scrollLeft;
	var view_top = vp.scrollTop;
	var view_right = vp.scrollLeft + vp.clientWidth;
	var view_bottom = vp.scrollTop + vp.clientHeight;
	
	var arena_left = +Infinum, arena_top = +Infinum, arena_right = -Infinum, arena_bottom = -Infinum;
	for (i = 1; i < Event_SimulationNumber; i++)
	{
		if (!Event_SimulationRunnables[i] || !document.getElementById("layerbox" + i).checked) continue;
		var r = document.getElementById("runner" + i);
		var x = parseInt(r.style.left);
		var y = parseInt(r.style.top);
		if (arena_left > x) arena_left = x;
		if (arena_top > y) arena_top = y;
		if (arena_right < x) arena_right = x;
		if (arena_bottom < y) arena_bottom = y;
	}

	var scroll_dx = 0, scroll_dy = 0;
	// scroll technique: scroll to superpose the center of arena with the center of view
	if (((view_left > 0) && (arena_left < view_left + SimScrollSensitiveMargin)) ||
		((view_right < ms.clientWidth) && (arena_right > view_right - SimScrollSensitiveMargin)))
		scroll_dx = ((arena_left + arena_right) - (view_left + view_right)) / 2;
	if (((view_top > 0) && (arena_top < view_top + SimScrollSensitiveMargin)) ||
		((view_bottom < ms.clientHeight) && (arena_bottom > view_bottom - SimScrollSensitiveMargin)))
		scroll_dy = ((arena_top + arena_bottom) - (view_top + view_bottom)) / 2;
	
	if ((Math.abs(scroll_dx) >= SimScrollMinMove) || (Math.abs(scroll_dy) >= SimScrollMinMove))
	{
		if (SimScrollMode == SimScrollModeFast)
		{
			if (scroll_dx != 0) vp.scrollLeft += scroll_dx; 
			if (scroll_dy != 0) vp.scrollTop += scroll_dy; 
		}
		else if (SimScrollMode == SimScrollModeSmooth)
		{
			var signofdx = scroll_dx > 0? +1 : -1; scroll_dx *= signofdx;
			var signofdy = scroll_dy > 0? +1 : -1; scroll_dy *= signofdy;
			var stepnumx = Math.floor((scroll_dx + SimScrollSmoothStep - 1) / SimScrollSmoothStep);
			var stepnumy = Math.floor((scroll_dy + SimScrollSmoothStep - 1) / SimScrollSmoothStep);
			var stepnummax = Math.max(stepnumx, stepnumy);
			for (i = 0; (i < stepnummax); i++)
			{
				var tinydx = (i >= stepnumx)? 0 : ((i == stepnumx - 1)? scroll_dx % SimScrollSmoothStep : SimScrollSmoothStep);
				var tinydy = (i >= stepnumy)? 0 : ((i == stepnumy - 1)? scroll_dy % SimScrollSmoothStep : SimScrollSmoothStep);
				if (tinydx != 0) vp.scrollLeft += signofdx * tinydx; 
				if (tinydy != 0) vp.scrollTop += signofdy * tinydy; 
			}
		}
	}
}

function runnersplitinfo_create(title, splittime, laptime)
{
	this.title = title;
	this.splittime = splittime;
	this.laptime = laptime;
	return this;
}

function runnersplitinfo_compare(item1, item2)
{
	return item1.splittime - item2.splittime;
}

function SimUpdateSplitsTable()
{
	var RunnerSplitInfos = new Array();
	var Ctrl = SimStarted? SimCurControl : SimControlNumber;
	for (i = 1; i < Event_SimulationNumber; i++)
	{
		if (!Event_SimulationRunnables[i] || !document.getElementById("layerbox" + i).checked) continue;
		if (!SimStarted || (SimPassedControls[i] >= Ctrl))
		{
			var tctrl = Event_SimulationSplits[i][Ctrl + 1];
			var tctrlprev = SimCurControl > 0? Event_SimulationSplits[i][Ctrl] : Event_SimulationSplits[i][Ctrl + 1];
			if (SimChase) { tctrl += Event_SimulationOs[i]; tctrlprev += Event_SimulationOs[i] }
			RunnerSplitInfos[RunnerSplitInfos.length] = new runnersplitinfo_create(Event_LayerTitles[i], tctrl, tctrl - tctrlprev);
		}
	}
	RunnerSplitInfos.sort(runnersplitinfo_compare);
	var splitscontent = "<B>";
	if (Ctrl == 0)
		splitscontent += SimResStartLabel;
	else if (Ctrl >= SimControlNumber)
		splitscontent += SimResFinalLabel;
	else
		splitscontent += SimResIntermediateLabel + Ctrl;
	splitscontent += "<\/B><BR><BR><TABLE>";
	splitscontent += "<TR><TD><\/TD><TD><\/TD><TD CLASS=split>" + ((!SimStarted || (Ctrl == 0))? "" : ((Ctrl - 1) + " - " + Ctrl)) + "<\/TD><TD CLASS=split>" + (SimChase? SimResChaseTotalLabel : SimResTotalLabel) + "<\/TD><\/TR>";
	for (i = 0; i < RunnerSplitInfos.length; i++)
	{
		var info = RunnerSplitInfos[i];
		var title = i == 0? "<B>" + info.title + "<\/B>" : info.title;
		var time1 = (!SimStarted || (Ctrl == 0))? "" : SecondsToStringWoHours(info.laptime);
		var time2 = (!SimStarted || (i == 0))? SecondsToString(info.splittime) : "+" + SecondsToStringWoHours(info.splittime - RunnerSplitInfos[0].splittime);
		splitscontent += "<TR><TD STYLE=\"text-align: right\">" + (i + 1) + "<\/TD><TD>" + title + "<\/TD><TD STYLE=\"text-align: right; padding-left: 20px\">" + time1 + "<\/TD><TD STYLE=\"text-align: right; padding-left: 20px\">" + time2 + "<\/TD><\/TR>";
	}
	splitscontent += "<\/TABLE>";
	document.getElementById("splitstable").innerHTML = splitscontent;
}

function SimPrepare()
{
	SimPassedControls = new Array(Event_SimulationNumber);
	SimCurControl = 0;
	SimPoss = new Array(Event_SimulationNumber);
	SimMaxT = -1;
	SimMinO = +Infinum;
	for (i = 1; i < Event_SimulationNumber; i++)
	{
		if (!Event_SimulationRunnables[i]) continue;
		var ti = Event_SimulationTs[i][Event_SimulationTs[i].length - 1];
		if (SimChase)
		{
			var oi = Event_SimulationOs[i];
			if (oi < SimMinO) SimMinO = oi;
			ti += oi;
		}
		if (ti > SimMaxT) SimMaxT = ti;
		SimPoss[i] = 1;
		SimPassedControls[i] = 0;
	}
	if (SimChase) SimMaxT -= SimMinO;
	SimFrameNumber = SimMaxT * SimTimeScale * SimFrameRate;
}

function SimStartTimer()
{
	OnSimTimer();
}

function SimKillTimer()
{
	clearTimeout(SimTimerId);
	SimTimerId = null;
}

function OnSimTimer()
{
	if (SimFrame <= SimFrameNumber)
	{
		SimTimerId = setTimeout("OnSimTimer();", 1000 / SimFrameRate);
		var t = SimFrame / (SimFrameRate * SimTimeScale);
		SimShowTime();
		var x, y, i, j;
		var rradius = Math.floor(SimRunnerSize / 2);
		for (i = 1; i < Event_SimulationNumber; i++)
		{
			if (!Event_SimulationRunnables[i] || !document.getElementById("layerbox" + i).checked) continue;
			var tl = SimChase? t + SimMinO - Event_SimulationOs[i] : t; 
			if (SimShowSplits)
			{
				j = SimPassedControls[i] + 2;
				while ((j < Event_SimulationSplits[i].length) & (Event_SimulationSplits[i][j] <= tl)) j++;
				SimPassedControls[i] = j - 2;
			}
			j = SimPoss[i];
			while ((j < Event_SimulationTs[i].length) & (Event_SimulationTs[i][j] < tl)) j++;
			if (j < Event_SimulationTs[i].length)
			{
				if (j > 1)
				{
					var k = (Event_SimulationTs[i][j] == Event_SimulationTs[i][j - 1])? 1 : (tl - Event_SimulationTs[i][j - 1]) / (Event_SimulationTs[i][j] - Event_SimulationTs[i][j - 1]);
					x = k * Event_SimulationXs[i][j] + (1 - k) * Event_SimulationXs[i][j - 1];
					y = k * Event_SimulationYs[i][j] + (1 - k) * Event_SimulationYs[i][j - 1];
				}
				else
				{
					// start point
					x = Event_SimulationXs[i][j];
					y = Event_SimulationYs[i][j];
				}
			}
			else
			{
				// finish point
				x = Event_SimulationXs[i][j - 1];
				y = Event_SimulationYs[i][j - 1];
			}
			SimPoss[i] = j;
			x += Event_LayerOfsXs[i] - MinX - rradius;
			y += Event_LayerOfsYs[i] - MinY - rradius;
			var r = document.getElementById("runner" + i);
			r.style.left = x + "px";
			r.style.top = y + "px";
		}
		if (SimScrollMode != SimScrollModeNone) SimScroll();
		if (SimShowSplits)
		{
			newcur = +Infinum;
			for (i = 1; i < Event_SimulationNumber; i++)
			{
				if (!Event_SimulationRunnables[i] || !document.getElementById("layerbox" + i).checked) continue;
				if (newcur > SimPassedControls[i]) newcur = SimPassedControls[i];
			}
			if (newcur > SimCurControl)
			{
				SimCurControl = newcur;
				SimUpdateSplitsTable();
			}
		}
		SimFrame++;
	}
	else OnSimStop();
}

function OnSimStart()
{
	if (SimStarted)
	{
		if (SimPaused)
		{
			SimStartTimer();
			document.getElementById("simplaybutton").value = SimPauseButtonCaption;
		}
		else
		{
			SimKillTimer();
			document.getElementById("simplaybutton").value = SimStartButtonCaption;
		}
		SimPaused = !SimPaused;
	}
	else
	{
		SimStarted = true;
		SimPaused = false;
		document.getElementById("simplaybutton").value = SimPauseButtonCaption;
		document.getElementById("optshowbutton").disabled = true;
		if (Event_SimulationChaseEnabled) document.getElementById("simchasecheck").disabled = true;
		
		// check if some runners checked
		var someChecked = false;
		for (i = 1; i < Event_LayerNumber; i++)
		{
			if (!Event_SimulationRunnables[i]) continue;
			if (document.getElementById("layerbox" + i).checked)
			{
				someChecked = true;
				break;
			}
		}
		// if nobody is checked, check all of them
		if (!someChecked)
		{
			for (i = 1; i < Event_LayerNumber; i++)
			{
				if (!Event_SimulationRunnables[i]) continue;
				document.getElementById("layerbox" + i).checked = true;
			}
		}

		for (i = 1; i < Event_LayerNumber; i++)
		{
			if (!Event_SimulationRunnables[i]) continue;
			if (document.getElementById("layerbox" + i).checked)
			{
				document.getElementById("layer" + i).style.visibility = "hidden";
				document.getElementById("runner" + i).style.visibility = "visible";
			}
		}
		SimPrepare();
		if (SimShowSplits) SimUpdateSplitsTable();
		document.getElementById("viewportprefix").scrollIntoView();
		SimStartTimer();
	}
}

function OnSimStop()
{
	if (SimStarted)
	{
		SimKillTimer();
		SimStarted = false;
		SimPaused = false;
		SimFrame = 0;
		SimShowTime();
		document.getElementById("simplaybutton").value = SimStartButtonCaption;  
		document.getElementById("optshowbutton").disabled = false;
		if (Event_SimulationChaseEnabled) document.getElementById("simchasecheck").disabled = false;
		for (i = 1; i < Event_LayerNumber; i++)
		{
			if (!Event_SimulationRunnables[i]) continue;
			if (document.getElementById("layerbox" + i).checked)
			{
				document.getElementById("layer" + i).style.visibility = "visible";
				document.getElementById("runner" + i).style.visibility = "hidden";
			}
		}
		if (SimShowSplits) SimUpdateSplitsTable();
	}
}

function OnSimRewind()
{
	SimFrame -= 60 * SimTimeScale * SimFrameRate;
	if (SimFrame < 0) SimFrame = 0;
	if (SimStarted)
	{
		for (i = 1; i < Event_SimulationNumber; i++)
		{
			if (!Event_SimulationRunnables[i]) continue;
			SimPoss[i] = 1;
		}
	}
	if (!SimStarted || SimPaused) SimShowTime();
}

function OnSimFastForward()
{
	SimFrame += 60 * SimTimeScale * SimFrameRate;
	if (SimFrame > SimFrameNumber) SimFrame = SimFrameNumber;
	if (!SimStarted || SimPaused) SimShowTime();
}

function OnSimChaseChange()
{
	SimChase = document.getElementById("simchasecheck").checked;
	if (SimShowSplits)
		SimUpdateSplitsTable();
}

function SimChangePace(NewTimeScale, NewFrameRate)
{
	var t = SimFrame / (SimFrameRate * SimTimeScale);
	SimFrameRate = NewFrameRate;
	SimTimeScale = NewTimeScale;
	SimFrame = t * SimTimeScale * SimFrameRate; 
	SimFrameNumber = SimMaxT * SimTimeScale * SimFrameRate;
}

function OnSimTimeScaleChange()
{
	SimChangePace(document.getElementById("simtimescalelist").value, SimFrameRate);
}

function OnSimFrameRateChange()
{
	SimChangePace(SimTimeScale, document.getElementById("simframeratelist").value);
}

function OnSimScrollModeChange()
{
	SimScrollMode = document.getElementById("simscrollmodelist").value;
}

function OnSimShowSplitsChange()
{
	SimShowSplits = document.getElementById("simshowsplitscheck").checked;
	document.getElementById("splitstable").style.visibility = SimShowSplits? "visible" : "hidden";
	if (SimShowSplits)
		SimUpdateSplitsTable();
}
