///
//	All rights reserved, 92 Productions, Feb. 2008.
//	See http://www.clanannwn.net/legal.php for terms of use.
//

// legLengths are the amounts of time, in seconds, that each ferry
// spends along each trip and at each port.

var debugging = false;
var useIcons = false;
var ferryIndex = 0;
var serverTimeOffset=0;
var TPurl = "/tool-ferry-data.php";

// The ferry class and methods
function Ferry(name){
	this.init(name);
}
Ferry.prototype = {
	init: function(name) {
		this.run = false;	// Turned on during setup
		this.legLengths = new Array; // The time each leg takes
		this.Steps = new Array; // Holds the sextant coordinates marking the
					// route a ferry takes. Is a user-friendly
					// format, which gets parsed away into Paths
					// later.

		this.element = null;		// The HTML DOM element holding the ferry
		this.transitions = new Array;	// Times along route at which a ferry
					 // docks or embarks.
		this.path = new Array;	// an array of Paths, representing the routes
		this.index = ++ferryIndex;	// A unique ID number for each ferry.
		this.oldX = null; // Used to determine direction of picture to display
	},
	// Take the element ID and sets up the required data structures
	initFerryVars: function() {
		// Set up the transitions array, that breaks the trip of this ferry into
		// legs, including time in each port. It needs to be a cumulative time
		// along route.
		this.transitions[0] = 0;
		for(var i = 0; i < this.legLengths.length; i++) {
			this.transitions[1 + i] = this.transitions[i] + this.legLengths[i];
		}

		// Store the number of legs and the total time for the trip
		this.numP = i;
		this.totalTrip = this.transitions[this.legLengths.length];

		// Construct the path objects that are used to interpolate each leg along
		// a polyline.
		this.createPaths();

		this.run = true;
	},
	getPosition: function(port, frac) {
		var path = this.path[port / 2];

		var i = 0;
		while (path.cumFrac[++i] < frac);

		setDebugInfo(2 * this.index - 1, this.name + " : " + Math.round(frac * 1000) / 1000 + " along path " + port / 2 + " which has " + path.nS + " points.");

		var f = (frac - path.cumFrac[i-1]) / (path.cumFrac[i] - path.cumFrac[i-1]);

		var X = path.x1[i-1]	* (1.0-f) + path.x1[i] * f;
		var Y = path.y1[i-1]	* (1.0-f) + path.y1[i] * f;

		return [X, Y];
	},
	// createPaths converts the Steps array into the Path data structure for a
	// given ferry.
	createPaths: function(){
		// Paths (legs) of the journey are marked with coords of -1. Find them,
		// build up the array of Path objects for this ferry, with the number of
		// steps in each path.

		var i, nS=0, nP=0;

		for(i=0; i<this.Steps.length; i++){
		if(this.Steps[i] < 0) {
			this.path[nP] = new Path();
			this.path[nP].nS = nS/2;
			nP++;
			this.Steps.splice(i--,1);
			nS=0;
		} else {
			nS++;
		}
		}

		this.nPaths = nP;

		var offset = 0;
		var sx1, sx2, sy1, sy2;
		var p, pathTotal,temp;

		for(p=0; p<this.nPaths; p++){

		this.path[p].x1[0] = this.Steps[offset];
		this.path[p].y1[0] = this.Steps[1+offset];

		pathTotal = 0.0;
		this.path[p].arc[0] = 0;
		for(i=1; i<this.path[p].nS; i++){

			this.path[p].x1[i] = this.Steps[i*2+offset];
			this.path[p].y1[i] = this.Steps[i*2+1+offset];
			sx1=this.path[p].x1[i-1];
			sy1=this.path[p].y1[i-1];
			sx2=this.path[p].x1[i];
			sy2=this.path[p].y1[i];


			temp = Math.sqrt((sx2-sx1)*(sx2-sx1)+(sy2-sy1)*(sy2-sy1));
			pathTotal += temp;
			this.path[p].arc[i] = temp;
		}

		this.path[p].cumFrac[0] = 0;
		for(i=1; i < this.path[p].nS; i++){

			this.path[p].cumFrac[i] = ( this.path[p].arc[i] / pathTotal )
		+ this.path[p].cumFrac[i-1];
		}
		offset += 2*this.path[p].nS;
		}
	},
	runFerry: function(){

		var CT = (getNow()+this.transitions[this.port] - this.time) %
		this.totalTrip;
		setDebugInfo(7,"current UTC : "+getNow());

		var CP = 0;
		var i = 0;
		while (this.transitions[++i] <= CT) CP = i;

		var syncLag	= getNow() - this.time;
		var fracCP = (CT - this.transitions[CP]) / this.legLengths[CP];
		var left = this.legLengths[CP] - CT + this.transitions[CP];

		setDebugInfo(2*this.index,"time this loop:"+CT+", leg/port: "+CP+", duration: "+this.legLengths[CP]+" Leaving in: "+left+", % of leg/port: "+Math.round(fracCP*1000)/10+" synced: "+this.time+" "+ syncLag/60);

		var enRoute = (i%2 == 1);

		var position;
		if(enRoute) {
			position = this.getPosition(CP,fracCP);
			return {'type':'enroute', 'to': this.portname[(CP)/2+1], 'from': this.portname[(CP)/2], 'time': left, 'x': position[0], 'y': position[1]};
		} else {
			position = this.getPosition((CP+1)%this.legLengths.length,0.0);
			return {'type':'docked', 'at': this.portname[(CP+1)/2], 'next': this.portname[(CP+1)/2+1], 'time': left, 'x': position[0], 'y': position[1]};
		}

	}
};

// Path class. This is a poly-line that holds the poly-line nodes, an
// absolute arclength, and a fraction along the path by arclength for each
// node.	It has no methods associated with it.
function Path(){
	this.nS = 0;
	this.cumFrac = new Array();
	this.arc = new Array();
	this.x1 = new Array();
	this.y1 = new Array();
}

var ferries = [];
ferries.hallowhold = new Ferry("hallowhold");
(function(o){
	o.name = "hallowhold";
	o.legLengths = new Array(257, 301, 257, 301);
	o.Steps = new Array (
						1695, 696,
						1632, 676,
						1443, 579,
						1111, 417,
						-1,
						1111, 417,
						1097, 521,
						1443, 579,
						1632, 676,
						1695, 696,
						-1
						);
	o.portname = new Array ("Tellerium","LoWANGen","Tellerium","LoWANGen");
	o.dname = "<strong>Hallowhold</strong>";
})(ferries.hallowhold);

ferries.riddenmast = new Ferry("riddenmast");
(function(o){
	o.name = "riddenmast";
	o.legLengths = new Array(209, 301, 209, 301);
	o.Steps = new Array (
						695, 813,
						706, 813,
						778, 867,
						812, 972,
						683, 1099,
						494, 1187,
						-1,
						494, 1187,
						683, 1099,
						812, 972,
						778, 867,
						706, 813,
						695, 813,
						-1);
	o.portname = new Array("Rune","Sigil","Rune","Sigil");
	o.dname = "<strong>Riddenmast</strong>";
})(ferries.riddenmast);

ferries.merdraco = new Ferry("merdraco");
(function(o){
	o.name = "merdraco";
	o.legLengths = new Array(
						137, 301, 188, 301, 131, 301, 47, 301,
						47,	301, 131, 301, 188, 301, 128, 301
						);
	o.Steps = new Array(
						705, 786,
						750, 835,
						690, 1051,
						465, 1210,
						 -1,
						465, 1210,
						538, 1172,
						595, 1144,
						642, 1120,
						731, 1079,
						860, 1026,
						967, 982,
						1061, 943,
						1194, 938,
						-1,
						1194, 938,
						1218, 919,
						1261, 898,
						1321, 882,
						1403, 844,
						1533, 825,
						1604, 796,
						1674, 726,
						1695, 704,
						-1,
						1695, 704,
						1671, 686,
						1636, 660,
						1616, 637,
						1600, 590,
						1588, 555,
						-1,
						1588, 555,
						1596, 580,
						1612, 627,
						1631, 657,
						1655, 675,
						1695, 704,
						 -1,
						1695, 704,
						1684, 714,
						1591, 809,
						1459, 845,
						1354, 873,
						1224, 914,
						1194, 938,
						 -1,
						1175, 938,
						1191, 924,
						1112, 932,
						948, 973,
						844, 1017,
						731, 1076,
						696, 1094,
						540, 1173,
						504, 1191,
						465, 1210,
						 -1,
						465, 1210,
						681, 1030,
						737, 825,
						705, 786,
						 -1);
	o.portname = new Array(
				"Rune","Sigil","Pirate's Cove","Tellerium","Templeton",
				"Tellerium","Pirate's Cove","Sigil","Rune","Sigil");
	o.dname = "<strong>Merdraco</strong>";
})(ferries.merdraco);

var currentMap = new Object();
currentMap.width = 2300;
currentMap.height = 1500;
currentMap.sizeX = 818;
currentMap.sizeY = 533;


addLoadEvent(function(){
	// Check with the server, get the ferry synchronization data, sort in TP
	// object. When this function gets a response, it will call the
	// runFerries function to set things moving.
	for (ferryName in ferries) {
		var ferry = ferries[ferryName];
		ferry.initFerryVars();
	}
	getLeaveTimePort();
	syncTimer = setInterval("getLeaveTimePort();",901000);
	ferryTimer = setInterval(runFerries, 1000);
});

function runFerries(){
	for (ferryName in ferries) {
		ferry = ferries[ferryName];
		if (ferry.run == true || true) {
			var state = ferry.runFerry();
			var e = document.getElementById(ferry.name + 'state');
			if (state.type == 'enroute') {
				e.innerHTML = ferry.dname + ": En Route to <em>" + state.to + "</em> from " + state.from + " arriving in " + formatTime(state.time);
			} else {
				e.innerHTML = ferry.dname + ": Docked at <em>" + state.at + "</em>, leaving in " + formatTime(state.time) + " for " + state.next;
			}
			e = document.getElementById(ferry.name);
			e.style.display = 'inline';
			e.style.left = state.x * currentMap.sizeX / currentMap.width - e.offsetWidth / 2 + 'px';
			e.style.top = state.y * currentMap.sizeY / currentMap.height - e.offsetHeight / 2 + 'px';
			if (!ferry.lastX || ferry.lastX < state.x)
				e.src = "/img/ferry/" + ferry.name + "-east.png";
			else
				e.src = "/img/ferry/" + ferry.name + "-west.png";
			ferry.lastX = state.x;
		}
	}
}

// Go get the time and identity of the last time all the ferries left a
// port, and store it in each.

function getLeaveTimePort() {
	var httpRequest = false;
	if (window.XMLHttpRequest) {
		httpRequest = new XMLHttpRequest();
	} else if (window.ActiveXObject) {
		try {
			httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
			} catch (e) {}
		}
	}
	if (!httpRequest) {
		alert("Could not create XMLHTTP instance");
		return false;
	}

	httpRequest.open("GET", TPurl, true);

	httpRequest.onreadystatechange = function() {
		if (httpRequest.readyState == 4) {
			if(httpRequest.status == 200) {
				if (httpRequest.responseText) {
					var lines = httpRequest.responseText.split("\n");
					for (var i = 0; i <	lines.length; i++) {
						line = lines[i].split(":");
						ferries[line[0]].port = line[1];
						ferries[line[0]].time = line[2];
					}
					setDebugInfo(0,pieces[0]+":"+pieces[1]+":"+pieces[2]);
					runFerries();
				} else {
					setDebugInfo(0,"no responseText");
				}
			} else {
				setDebugInfo(1,"httpRequest.status = "+httpRequest.status);
			}
		}
	};
	httpRequest.send(null);
}

function formatTime(seconds) {
	var minutes = Math.floor(seconds / 60);
	seconds = seconds % 60;
	if (minutes > 1)
		minutes = minutes + ' minutes';
	else if (minutes == 1)
		minutes = minutes + ' minute';
	if (seconds > 1 || seconds == 0)
		seconds = seconds + ' seconds';
	else if (seconds == 1)
		seconds = seconds + ' second';

	if (minutes)
		return minutes + ' ' + seconds;
	else
		return seconds;
}

function initFerryOffset(sec){
	serverTimeOffset = sec;
}

function getNow(){
	var curDate = new Date();
	return Math.floor(curDate.getTime()/1000)+serverTimeOffset;
}

function setDebugInfo(i,message){
	if(debugging == true){
		document.getElementById('status'+i).value = message;
		document.getElementById('status'+i).display = 'inline';
	}
}

function displayState(elem,message){
		elem.innerHTML = message;
}
