/* ------------------------------------------------------------------

File:		route.js
Abstract:	handling of routes, route display function
Version:	0.1
Author:		Pascal Dreer

------------------------------------------------------------------ */


var gRt = null;
var routeWindow = null;



function routeTest()
{
	gRt = new RouteList();
	
	gRt.add(1,90);
	gRt.add(2,90);
	alert("Bearing 1 > 2:" + roundNumber(gRt.find(2).getBearing(),2));
	
	gRt.add(3,90);
	
	
	gRt.display();	
	gRt.add(4,90,gRt.find(2));
	gRt.display();
	gRt.add(5,90);
	gRt.display();
	gRt.remove(gRt.find(2));
	
	gRt.display();
	gRt.redraw();
	
	var dist = gRt.getDistance();
	var distText = "Distanz: " +  Math.round(dist / 1000) + " km (" + Math.round(dist * 0.0005399568) + " NM)";
	
	alert("Dist=" + distText + "/Dur=" + formatTimeHHMM(gRt.getDuration()));
	
//	gRt.deleteList();
	
//	gRt.display();
}




function routeStarted()
{
	if (gRt)
		return true;
	else
		return false;
}



function resetRoute()
{
	if (gRt)
		gRt.deleteList();
	gRt = null;
	initRouting();
	if (routeWindow) {
		routeWindow.close();
		routeWindow = null;
	}
}




function openRouteWindow()
{
	if (routeWindow) {
		if (!routeWindow.closed) {
			showRoute();
			routeWindow.focus();
			return;		
		}
	}
	var routeWinWidth = 400;
	var routeWinLeft = getWindowWidth() + 10;
	
	if ((routeWinLeft + routeWinWidth) > screen.width)
		routeWinLeft = screen.width - routeWinWidth;
	
	routeWindow = window.open("","Route","width=" + routeWinWidth + ",height=400,left=" + routeWinLeft + ",top=50");	// this.href
	routeWindow.name = "Routing-Window";
	routeWindow.focus();
	showRoute()	;
	return;


	if (!routeWindow) {
		var routeWinWidth = 400;
		var routeWinLeft = getWindowWidth() + 10;
	
		if ((routeWinLeft + routeWinWidth) > screen.width)
			routeWinLeft = screen.width - routeWinWidth;
	
		routeWindow = window.open("","Route","width=" + routeWinWidth + ",height=400,left=" + routeWinLeft + ",top=50");	// this.href
		routeWindow.name = "Routing-Window";
		routeWindow.focus();
		showRoute()	;
	}
	else {
		showRoute();
		routeWindow.focus();
	}
}



function updateRouteWindow()
{
	
	if (routeStarted() && routeWindow)
		if (!routeWindow.closed)
			showRoute();
}




function showRoute()
{
	
	
	var HTMLstring='<html>\n';
	HTMLstring+='<head>\n';
	HTMLstring+='<title>Route</title>\n';
	HTMLstring+='<style type="text/css">@import "flightmap.css";</style>';
	HTMLstring+='</head>\n';
	HTMLstring+='<body><form="editUserForm">\n';

	if (gRt) {

		var txt = "<table border='0' width='100%' cellpadding='0' cellspacing='1'>";
		txt += "<tr><td><span class=\"routeTextHead\">Waypoint</span></td><td align=right><span class=\"routeTextHead\">Course</span></td><td align=right><span class=\"routeTextHead\">Dist</span></td><td align=right><span class=\"routeTextHead\">Elev (ft)</span></td><td align=right><span class=\"routeTextHead\">GS</span></td><td align=right><span class=\"routeTextHead\">EET</span></td><td align=right><span class=\"routeTextHead\">&Sigma; EET</span></td></tr>";
		var rp = gRt.display();
		var eto = 0;
		var eet = 0;

		while (rp != null) {
			eet = (rp.dist * 0.0005399568) / rp.gs * 60;
			eto = eto + eet;
			txt += "<tr><td><span class=\"routeText\">" + gMappoints[rp.mp_id].name + "</span></td><td align=right><span class=\"routeText\">" + formatBearing(rp.bearing) + "</span></td><td align=right><span class=\"routeText\">" + Math.round(rp.dist * 0.0005399568) + "</span></td><td align=right><span class=\"routeText\">" + gMappoints[rp.mp_id].elev + "</span></td><td align=right><span class=\"routeText\">" + Math.round(rp.gs) + "</span></td><td align=right><span class=\"routeText\">" + formatTimeHHMM(eet) + "</span></td><td align=right><span class=\"routeText\">" + formatTimeHHMM(eto) + "</span></td></tr>";
			rp = gRt.display(rp);
		}
		txt += "</table><br>";
		HTMLstring+=txt;

		var dist = gRt.getDistance();
		var distText = "<span class=\"routeText\">Distance: " + Math.round(dist * 0.0005399568) + " NM (" + Math.round(dist / 1000) + " km)</span>";
		HTMLstring+=distText;
	}
	else {
		
		HTMLstring+='<span class=\"routetitle\">Routing<br/></span>';
		HTMLstring+='<span class=\"route-text\">Es ist keine Route definiert.</span>';
	}
	
	HTMLstring+='<br><p><a href="javascript: self.close();" class="routeText">Fenster schliessen</a></p>';
	HTMLstring+='</form></body>\n';
	HTMLstring+='</html>';
	
//	routeWindow.document.open();

	routeWindow.document.write(HTMLstring);
	routeWindow.document.close();
}



function RoutePoint(mp_id,gs)
{
	this.id = gMappoints[mp_id].id;
	this.mp_id = mp_id;
	this.gs = gs;
	this.dist = 0;
	this.bearing = 0;
	this.line = null;
	this.prev = null;
	this.next = null;
	
	
	this.insertAfter = function(newPoint) 
	{
		if (this == newPoint)
			return;
		newPoint.extract();
		newPoint.prev = this;
		if (this.next) {
			newPoint.next = this.next;
			this.next.prev = newPoint;
		}
		this.next = newPoint;
	}
	
	
	this.extract = function()
	{
		if (this.prev && this.next) {
			if (this.next.mp_id) {
				var points = [];
				points.push(gMarkers[this.prev.mp_id].getPoint());
				points.push(gMarkers[this.next.mp_id].getPoint());
				this.next.dist = points[0].distanceFrom(points[1]);
				points.pop();
				points.pop();
			}
		}
		if (this.line)
			gMap.removeOverlay(this.line);
	
		if (this.prev)
			this.prev.next = this.next;
		
		if (this.next) 
			this.next.prev = this.prev;
			
		
		
		this.prev = this.next = null;
	}
	
	this.getBearing = function() 
	{

		return this.bearing;
	}

}


function RouteList() 
{
	this.prev = this.next = this;
	
	
	this.insertAfter = function(newPoint) 
	{
		
		if (this == newPoint)
			return;
		newPoint.extract();
		newPoint.prev = this;
		if (this.next) {
			newPoint.next = this.next;
			this.next.prev = newPoint;
		}
		this.next = newPoint;
	}
	
	this.remove = function(node)
	{
		node.extract();
	}
	
	
	this.add = function(mp_id,gs,afterNode)
	{
		var newNode = new RoutePoint(mp_id,gs);
		if (!afterNode) {
			if (this.prev)
				afterNode = this.prev;
			else
				afterNode = this;
		}
		afterNode.insertAfter(newNode);
		
		if (newNode.prev.mp_id) {
			var points = [];
			points.push(gMarkers[newNode.prev.mp_id].getPoint());
			points.push(gMarkers[newNode.mp_id].getPoint());
			newNode.dist = points[0].distanceFrom(points[1]);
			newNode.bearing = calcBearing(points[0].lat(),points[0].lng(),points[1].lat(),points[1].lng());
	
			var line = new GPolyline(points,"#f2bf03",4,0.7);
			newNode.line = line;
			gMap.addOverlay(line);
		
//			points.pop();
//			points.pop();
		}
		return newNode;
	}
	
	this.find = function (mp_id,startNode) {
		if (!startNode) 
			startNode = this;
			
		for (var node = startNode.next; node != this;node = node.next) {
			if (node.mp_id == mp_id)
				return node;
		}
	}
	
	this.display = function(startPoint)
	{
		var list = "";
		
		if (!startPoint) 
			startPoint = this;
		
		if (!startPoint.next)
			return;
		
		for (var node = startPoint.next; node != this;node = node.next) {
			return node;
//			list = list + node.gs + " ";
//			if (func(node.elem)) {return node;}
		}
//		alert(list);
	}
	
	
	this.deleteList = function()
	{
		var startPoint = this;
		var node, tmp;
		
		for (node = startPoint.next; node != this;null) {
			tmp = node.next;
			node.prev.next = null;
			if (node.line)
				gMap.removeOverlay(node.line);		
			delete node;
			node = tmp;
		}

	}
		
	
	this.getDistance = function()
	{
		var dist = 0;
		var startPoint = this;
			
		for (var node = startPoint.next; node != this;node = node.next) {
			dist = dist + node.dist;
		}
		return dist;
	}
	
	this.getDuration = function()
	{
		var duration = 0;
		var startPoint = this;
			
		for (var node = startPoint.next; node != this;node = node.next) {
			duration = duration + ((node.dist * 0.0005399568) / node.gs * 60);
		}
		return Math.round(duration);
	}
	
	
	this.updatePosition = function(mp_id,startNode)
	{
		if (!startNode) 
			startNode = this;
			
		for (var node = startNode.next; node != this;node = node.next) {
				if (node.mp_id == mp_id && startNode.prev) {
					var points = [];
					points.push(gMarkers[node.prev.mp_id].getPoint());
					points.push(gMarkers[node.mp_id].getPoint());
					node.dist = points[0].distanceFrom(points[1]);
					node.bearing = calcBearing(points[0].lat(),points[0].lng(),points[1].lat(),points[1].lng());
				}
		}
	}
	
	
	this.redraw = function()
	{
		var startPoint = this;

		for (var node = startPoint.next; node != this;node = node.next) {
			if (node.line)
				gMap.removeOverlay(node.line);		
		}

		var startPoint = this;
		
		for (var node = startPoint.next; node != this;node = node.next) {
			if (node.prev.mp_id) {
				var points = [];
				points.push(gMarkers[node.prev.mp_id].getPoint());
				points.push(gMarkers[node.mp_id].getPoint());
				node.dist = points[0].distanceFrom(points[1]);
				node.bearing = calcBearing(points[0].lat(),points[0].lng(),points[1].lat(),points[1].lng());
	
				var line = new GPolyline(points,"#f2bf03",4,0.7);
				node.line = line;
				gMap.addOverlay(line);
				points.pop();
				points.pop();
			}		
		}	
	}
}







function initRouting()
{
	document.getElementById("route_display").innerHTML = "";
	document.getElementById("form_gs").value = gGS;
//	document.getElementById("form_fuel").value = gFuelConsumption;
	displayRouteInfo(0,0,0);
}



function addTrackLeg(i)
{
	if (!gRt) {
		gRt = new RouteList();
		displayRouteInfo(0,0,0);
	}
	
	gRt.add(i,gGS);
	displayRouteInfo(gRt.getDistance(),gRt.getDuration(),0);
	gMap.closeInfoWindow();
	updateRouteWindow();
}





function formatTimeHHMM(time)
{
	if (time > 59) {
		var hrs = Math.floor(time / 60);
		var mins = Math.round(time - (hrs * 60));
	}
	else {
		var hrs = 0;
		var mins = Math.round(time);
	}
	
	if (hrs < 10) 
		hrsTxt = "0" + hrs;
	else
		hrsTxt = hrs;
		
	if (mins < 10)
		minsTxt = "0" + mins;
	else
		minsTxt = mins;
		
	return (hrsTxt + ":" + minsTxt);
}



function formatBearing(brng)
{
	var b = Math.round(brng);
	
	if (b < 10)
		return "00" + b;
	if (b < 100)
		return "0" + b;

	return b;
}




function displayRouteInfo(dist,time,fuel)
{
	var timeText = formatTimeHHMM(time);
		
	var fuelText = "";
	if 	(fuel > 0)
		var fuelText = ", Fuel: " + Math.round(fuel);
		
	var timeText = "Time: " + timeText + fuelText;
	var distText = "Distance: " + Math.round(dist * 0.0005399568) + " NM (" + Math.round(dist / 1000) + " km)";
	
	
	document.getElementById("route_display").innerHTML = timeText + "<br>" + distText;
}







/* Source for bearing calculation: http://www.movable-type.co.uk/scripts/latlong.html */
function calcBearing(lat0,lng0,lat1,lng1)
{
	var dLon = (lng1 - lng0).toRad(); 
	var y = Math.sin(dLon) * Math.cos(lat1.toRad());
	var x = Math.cos(lat0.toRad())*Math.sin(lat1.toRad()) - Math.sin(lat0.toRad())*Math.cos(lat1.toRad())*Math.cos(dLon);
	return Math.atan2(y, x).toBrng();
}


Number.prototype.toBrng = function() {  // convert radians to degrees (as bearing: 0...360)
  return (this.toDeg()+360) % 360;
}

Number.prototype.toRad = function() {  // convert degrees to radians
  return this * Math.PI / 180;
}

Number.prototype.toDeg = function() {  // convert radians to degrees (signed)
  return this * 180 / Math.PI;
}
