var map, om, geocoder, gdir, markers, now, speeds;
startZoom = 12, busy = false;
var normalProj;
var contextmenu, route, ID;
var resizable = false;
var mouseX, mouseY, drawnX, drawnY, resizedX, resizedY;
var weatherOverlay = null;
var chosen = [];
var layers = [];

function load_xml_file(xmlFilePath) {
	try {
		if (window.ActiveXObject) {
			// for IE
			xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
			xmlDoc.async = false;
			xmlDoc.load(xmlFilePath);
			return xmlDoc;
		} else if (document.implementation
				&& document.implementation.createDocument) {
			// for Mozilla
			xmlDoc = document.implementation.createDocument("", "", null);
			xmlDoc.async = false;
			xmlDoc.load(xmlFilePath);
			return xmlDoc;
		}
	} catch (e) {
		try // Google Chrome
		{
			var xmlhttp = new window.XMLHttpRequest();
			xmlhttp.open("GET", xmlFilePath, false);
			xmlhttp.send(null);
			xmlDoc = xmlhttp.responseXML.documentElement;
			return xmlDoc;
		} catch (e) {
			error = e.message;
		}
	}
}

function PrintThisPage() {
	try {
		// internet explorer
		var frame = document.frames;
		frame.focus();
		frame.print();
	} catch (e) {
		// firefox
		var frame = window.frames;
		frame.focus();
		frame.print();
	}
}
function AJAXInteraction(url, callback) {
	var req = init();
	req.onreadystatechange = processRequest;
	function init() {
		try {
			// Opera 8.0+, Firefox, Safari
			return new XMLHttpRequest();
		} catch (e) {
			// Internet Explorer Browsers
			try {
				return new ActiveXObject("Msxml2.XMLHTTP");
			} catch (e) {
				try {
					return new ActiveXObject("Microsoft.XMLHTTP");
				} catch (e) {
					// Something went wrong
					alert("Your browser broke!");
					return false;
				}
			}
		}
	}
	function processRequest() {
		// readyState of 4 signifies request is complete
		if (req.readyState == 4) {
			// status of 200 signifies sucessful HTTP call
			if (req.status == 200) {
				if (callback) {
					if (req.responseXML == null) {
						callback(req.responseText);
					} else {
						callback(req.responseXML);
					}
				}
			}
		}
	}
	this.doGet = function() {
		// make a HTTP GET request to the URL asynchronously
		req.open("GET", url, true);
		req.send(null);
	}
}
function waitWhileBusy() {
	// wait until all markers are positioned
	if (busy == false) {
		sendform();
		window.setTimeout("arrow('none')", 10);
	} else {
		window.setTimeout('waitWhileBusy()', 20);
	}
}
function sendform() {
	clearError();
	// time
	var dateselector = document.getElementById('dateselector');
	var hourselector = document.getElementById('hourselector');
	var minuteselector = document.getElementById('minuteselector');
	var date = new Date(dateselector.value);
	var value = date.getFullYear().toString()
			+ zeropadd((date.getMonth() + 1).toString())
			+ zeropadd(date.getDate().toString());
	time = value + hourselector.value + minuteselector.value;
	// start address
	var zip_from = document.getElementById('zip_from').value;
	zip_from = zip_from.replace(" ", "");
	// destination address
	var zip_to = document.getElementById('zip_to').value;
	zip_to = zip_to.replace(" ", "");
	// departure or arrival
	var depart = document.getElementById('departselector').value;
	// reliability
	var reli = document.getElementById('reliabilityselector').value;
	var queryString = "TripCast?id=" + ID + "&fromlat="
			+ markers[0].getLatLng().lat() + "&fromlng="
			+ markers[0].getLatLng().lng() + "&tolat="
			+ markers[1].getLatLng().lat() + "&tolng="
			+ markers[1].getLatLng().lng() + "&depart=" + depart + "&time="
			+ time + "00" + "&reliability=" + reli;
	var url = './php_proxy.php?yws_path=' + encodeURIComponent(queryString);
	// display information while calculation traveltime

	clearMessage();
	changeBodyClass('loading');
	// call tripcast and display results
	var ajax = new AJAXInteraction(url, printTravelTime);
	ajax.doGet();
}
function returnTrip() {
	// interchange source and destination in form
	var zip_from = document.getElementById('zip_from').value;
	var zip_to = document.getElementById('zip_to').value;
	document.getElementById('zip_from').value = zip_to;
	document.getElementById('zip_to').value = zip_from;
	// interchange marker positions
	var latlon = markers[0].getLatLng();
	markers[0].setLatLng(markers[1].getLatLng());
	markers[1].setLatLng(latlon);
	// recalculate route
	clearAll();
	showRoute();
}
function setStartPoint() {
	// start address
	busy = true;
	var zip_from = document.getElementById('zip_from').value;
	showAddress(zip_from, 0);
}
function setEndPoint() {
	// destination address
	busy = true;
	var zip_to = document.getElementById('zip_to').value;
	showAddress(zip_to, 1);
}
function disablesubmit() {
	document.getElementById('submitbutton').disabled = false;
}
function showAddress(address, index) {
	if (geocoder) {
		
		// detect dutch zipcode
		var match = new RegExp(/\b[1-9]{1}[0-9]{3}\s*[A-Za-z]{2}\b/);
		// if dutch zipcode is used remove space
		if (match.test(address)) {
			address = match.exec(address) + "";
			// maak er een string van
			address = address.replace(/ /, "");
		}

		labels = [ 'zip_from', 'zip_to' ];
		geocoder
				.getLocations(
						address,
						function(response) {
							if (!response || response.Status.code != 200) {
								// wrong address
								document.getElementById(labels[index]).style.backgroundColor = '#FF0000';
								// red
							} else {
								place = response.Placemark[0];
								// if
								// (place.AddressDetails.Country.CountryNameCode
								// .toUpperCase() != "NL") {
								// }
								point = new GLatLng(place.Point.coordinates[1],
										place.Point.coordinates[0]);
								busy = false;
								// correct address
								document.getElementById(labels[index]).style.backgroundColor = '#F5F5F5';
								// grey
								markers[index].setLatLng(point);
								markers[index].show();
								showRoute();
								clearAll();
							}
						});
	}
}
function showRoute() {
	if (markers[0].isHidden() | markers[1].isHidden()) {
		window.setTimeout("arrow('none')", 10);
	} else {
		window.setTimeout("arrow('inline')", 10);
	}
	gdir.loadFromWaypoints( [ markers[0].getLatLng(), markers[1].getLatLng() ],
			{
				getPolyline :true,
				getSteps :true
			});
	try {
		map.removeOverlay(route);
	} catch (err) {
	}
}
function arrow(arg) {
	var tering = document.getElementById("arrow-left.gif");
	tering.style.display = arg;
}
function handleErrors(xml) {
	// result/code == 0 means no error
	var err = (xml.getElementsByTagName("code")[0].childNodes[0].nodeValue != 0);
	return err;
}
function printTravelTime(xml) {
	
	clearMessage();
	changeBodyClass('standby');
	if (!handleErrors(xml)) {
		displayResultMessage(xml);
		var bounds = route.getBounds();
		// ===== determine the zoom level from the bounds =====
		map.setZoom(map.getBoundsZoomLevel(bounds));
		// ===== determine the centre from the bounds ======
		map.setCenter(bounds.getCenter());
	} else {
		showError(xml);
	}
}
function rand(n) {
	return (Math.floor(Math.random() * n + 1));
}
// This function is called when window is loaded and handles initialization
function load() {
	// temporary ID
	ID = rand(1000);
	// Default values
	var lat = 52.100;
	var lng = 5.625;
	var zoom = 7;
	var maptype = 0;

	// create map with controls
	map = new GMap2(document.getElementById("map_container"));
	map.addControl(new GLargeMapControl());
	map.setCenter(new GLatLng(lat, lng), zoom, map.getMapTypes()[maptype]);
	map.addControl(new GMapTypeControl());
	map.enableScrollWheelZoom();
	map.enableContinuousZoom();

	// create geocoder object
	geocoder = new GClientGeocoder();
	geocoder.setBaseCountryCode("nl");

	// for conversion between LatLng and screen pixels
	normalProj = G_NORMAL_MAP.getProjection();

	// mouseover listener shows controls
	GEvent.addListener(map, "mouseover", function() {
		map.showControls();
	});
	// mouseout listener hides controls
	GEvent.addListener(map, "mouseout", function() {
		map.hideControls();
	});

	// add control for map resizing
	map.addControl(new ResizeControl());
	map.addControl(new LayerControl());

	// Register mouse move listener
	document.onmousemove = watchMouse;

	// gdirections object for calculating routes, note: no map or panel attached
	gdir = new GDirections();
	GEvent.addListener(gdir, "load", function() {
		route = gdir.getPolyline();
		map.addOverlay(route);
	});

	// create markers for start and end points
	createMarkers();
	
	// create contextmenu
	new ContextMenu(map);
	window.setTimeout("clearRouteDescription()", 10);
	initLayers();
	initForm();
	initFileInfo();
	resize();

}
function initLayers() {

	var southWest = new GLatLng(48.895, 0);
	var northEast = new GLatLng(55.974, 10.856);
	var bounds = new GLatLngBounds(southWest, northEast);
	var lngDelta = (northEast.lng() - southWest.lng());
	var latDelta = (northEast.lat() - southWest.lat());
	var rectBounds = new GLatLngBounds(new GLatLng(southWest.lat() + latDelta,
			southWest.lng() + lngDelta), new GLatLng(
			northEast.lat() - latDelta, northEast.lng() - lngDelta));

	layers = [
			{
				name :"Files",
				active :true,
				obj :new GGeoXml("http://www.tripcast.nl/speeds/speeds.kml?"
						+ (new Date()).getMilliseconds())
			},
			{
				name :"Buienradar",
				active :false,
				obj :new GGroundOverlay(
						"http://mijn.buienradar.nl/gps/maps.gif", bounds)
			} ];

	var boxes = document.getElementsByName("mark");
	for ( var i = 0; i < boxes.length; i++) {
		boxes[i].checked = layers[i].active;
		switchLayer(layers[i].active, layers[i].obj);
	}
}

function initFileInfo() {
	try {
		// get div to display filefeed
		var filefeed = document.getElementById('filefeed');
		// read xml on server
		var xmlDoc = load_xml_file("../feeds/filefeedCrd.xml");

		if (xmlDoc.getElementsByTagName("melding").length == 0) {
			filefeed.innerHTML = "";
			return
		}

		var html = "<p><center><b><big>Actuele files:</b></big></center>"
				+ xmlDoc.getElementsByTagName("tekst")[0].childNodes[0].nodeValue
				+ "</p>";
	} catch (e) {
		alert(e)
	}
	;
	// process all "melding"
	var meldingen = xmlDoc.getElementsByTagName("melding");
	for ( var i = 0; i < meldingen.length; i++) {
		try {
			html += "<p class='odd'>";
			html += "<b>"
					+ meldingen[i].getElementsByTagName("wegnr")[0].childNodes[0].nodeValue
					+ " ";
			html += meldingen[i].getElementsByTagName("van")[0].childNodes[0].nodeValue
					+ " - ";
			html += meldingen[i].getElementsByTagName("naar")[0].childNodes[0].nodeValue
					+ " ";
			html += "<nobr>"
					+ meldingen[i].getElementsByTagName("afstand")[0].childNodes[0].nodeValue
					+ " km.</b></nobr> ";
			html += meldingen[i].getElementsByTagName("gevolg")[0].childNodes[0].nodeValue
					+ " ";
			html += "tussen ";
			html += meldingen[i].getElementsByTagName("vansub")[0].childNodes[0].nodeValue;
			html += " en ";
			html += meldingen[i].getElementsByTagName("naarsub")[0].childNodes[0].nodeValue
					+ ". ";
			// trendtekst is not always available
			try {
				html += meldingen[i].getElementsByTagName("trendtekst")[0].childNodes[0].nodeValue;
			} catch (e) {
			}
			;
		} catch (e) {
		}
		html += "<\p>";
	}
	filefeed.innerHTML = html;

}

function changeBodyClass(to) {
	// change body class, to make busy indicator visible
	document.body.className = to;
	document.getElementById('alert').style.top = parseFloat(map.getContainer().style.height) / 2 + 'px';
	return false;
}
// === route duration ===
function routeDuration(xml) {
	// get results from xml
	var date = xml.getElementsByTagName("preformat")[0].childNodes[0].childNodes[0].nodeValue;
	var depart = xml.getElementsByTagName("preformat")[0].childNodes[1].childNodes[0].nodeValue;
	var duration = xml.getElementsByTagName("preformat")[0].childNodes[2].childNodes[0].nodeValue;
	var arrive = xml.getElementsByTagName("preformat")[0].childNodes[3].childNodes[0].nodeValue;
	var mean = Math
			.ceil(xml.getElementsByTagName("mean")[0].childNodes[0].nodeValue);
	// traveltime
	var length = xml.getElementsByTagName("length")[0].firstChild.nodeValue;
	var lengthObserved = xml.getElementsByTagName("lengthObserved")[0].firstChild.nodeValue;
	var rekenmethode = xml.getElementsByTagName("rekenmethode")[0].firstChild.nodeValue;
	var arrive_p95 = xml.getElementsByTagName("arrive_p95")[0].childNodes[0].nodeValue;
	// .95 percentile
	var arrive_p05 = xml.getElementsByTagName("arrive_p05")[0].childNodes[0].nodeValue;
	// .05 percentile
	var googleMin = Math.round(parseFloat(gdir.getDuration().seconds) / 60);
	var durationMin = parseFloat(xml.getElementsByTagName("durationmin")[0].firstChild.nodeValue);
	var durationnow = xml.getElementsByTagName("durationnow")[0].firstChild.nodeValue;
	var verschil = durationMin - googleMin;
	var msg = "<fieldset>"
			+ "<legend> Uw reistijd </legend>"
			+ "<TABLE title=\"Reistijdverwachting\" style=\"border: 1px solid #999; background-color: rgb(238, 238, 238); border-collapse: collapse; color: rgb(0, 0, 0); width: 100%; background-color: #EAF2FF;\">"
			+ " <TR >"
			+ "  <TD style=\"text-align: right;\"><b>Vertrek:</b></TD>"
			+ "  <TD>"
			+ depart
			+ " </TD>"
			+ " <TR>"
			+ "  <TD style=\"text-align: right;\"><b>Reistijd:</b></TD>"
			+ "  <TD>"
			+ duration
			+ "*</TD>"
			+ " <TR >"
			+ "  <TD style=\"text-align: right;\"><b>Afstand:</b></TD>"
			+ "  <TD>"
			+ gdir.getRoute(0).getDistance().html
			+ "</TD>"
			+ " <TR>"
			+ "  <TD style=\"text-align: right;\"><b>Aankomst:</b></TD>"
			+ "  <TD>"
			+ arrive
			+ "</TD>"
			+ "</TABLE>"
			+ "*<font style='font-size:small;'>"
			+ rekenmethode
			+ "</font><br>"
			+ "<br>";
	if (isNaN(verschil)) {
		msg += "<div title=\"Marge van de reistijdverwachting\" style=\"border: 1px solid #999; background-color: rgb(238, 238, 238); border-collapse: collapse; color: rgb(0, 0, 0); width: 100%; font-size: smaller; background-color: #EAF2FF; \">";
		msg += "De reistijd volgens Google is <b>" + googleMin
				+ " min</b> </div>" + "<br>";
		msg += "<b>Reistijd op dit moment:</b>"
				+ "<br>"
				+ "<div title=\"Actuele reistijd\" style=\"border: 1px solid #999; background-color: rgb(238, 238, 238); border-collapse: collapse; color: rgb(0, 0, 0); width: 100%; font-size: smaller; background-color: #EAF2FF; \">"
				+ "<b><font color=#009F00>" + durationnow
				+ ".</b></font></div>" + "</fieldset><br>";
		return msg;
	}
	if (verschil < 0) {
		verschil = "de door Tripcast berekende reistijd is " + "<b>"
				+ Math.abs(verschil) + " min korter." + "</b>";
	} else if (verschil > 0) {
		verschil = "de door Tripcast berekende reistijd is " + "<b>" + verschil
				+ " min langer." + "</b>";
	} else {
		verschil = "dit is gelijk aan de door Tripcast berekende reistijd.";
	}
	msg += "<div title=\"Marge van de reistijdverwachting\" style=\"border: 1px solid #999; background-color: rgb(238, 238, 238); border-collapse: collapse; color: rgb(0, 0, 0); width: 100%; font-size: smaller; background-color: #EAF2FF; \">";
	msg += "Voor <b>"
			+ Math.round(100 * parseFloat(lengthObserved) / parseFloat(length))
			+ "%</b> van deze route is reistijdhistorie beschikbaar. ";
	msg += "De kans dat u voor <b>" + arrive_p05
			+ "</b> aankomt is circa <b>5%</b>. " + "De kans dat u na <b>"
			+ arrive_p95 + "</b> aankomt is circa <b>5%</b>. ";
	msg += "De reistijd volgens Google is <b>" + googleMin + " min</b>, "
			+ verschil + "</div>" + "<br>";
	msg += "<b>Reistijd op dit moment:</b>"
			+ "<br>"
			+ "<div title=\"Actuele reistijd\" style=\"border: 1px solid #999; background-color: rgb(238, 238, 238); border-collapse: collapse; color: rgb(0, 0, 0); width: 100%; font-size: smaller; background-color: #EAF2FF; \">"
			+ "<b><font color=#009F00>"
			+ "De actuele reistijd op dit traject is: " + durationnow
			+ ".</b></font></div>" + "</fieldset>";
	// return trip
	now = new Date(getTime());
	var millis = now.getTime();
	if (document.getElementById('departselector').value == true) {
		// if depart add traveltime
		millis = millis + mean * 1000;
		// mean is in seconds
	}
	now.setTime(millis + 60 * 60 * 1000);
	// add one hour
// msg += "<div style=\"font-size: smaller; border: none;\"><br><i>Snel een
// nieuwe berekening uitvoeren?</i></div>";
// msg += addTimeButtons();
// msg += "<div style=\"font-size: smaller; border: none;\"><i>Uw berekening
// herhalen met een andere zekerheidsmarge?</i></div>";
// msg += addReliabilityButtons();
// msg += "<div style=\"font-size: smaller; border: none;\"><i><br>Gegevens van
// een nieuwe rit invoeren? Gebruik het formulier in de linker
// kolom.<i></div><br>";

	return msg;
}
function addTimeButtons() {
	var selectedIndex = document.getElementById('departselector').selectedIndex;
	var depart = document.getElementById('departselector').options[selectedIndex].text;
	msg = "<table border=\"0\" width=\"100%\" cellpadding=\"0\" >";
	msg += "<tr>";
	msg += "<td><input type=\"button\" value=\"1 uur eerder\" class=\"send1\" onclick=\"changeTime(-60*60*1000)\"></td>";
	msg += "<td><input type=\"button\" value=\"1 uur later\" class=\"send1\" onclick=\"changeTime(60*60*1000)\"></td>";
	msg += "<td><input type=\"button\" value=\"Terug om "
			+ zeropadd(now.getHours().toString()) + ":"
			+ zeropadd(now.getMinutes().toString())
			+ "\" class=\"send1\" + onclick=\"changeRoute()\"></td>";
	msg += "</tr>";
	msg += "</table>";

	return msg;
}
function addReliabilityButtons() {
	msg = "<table border=\"0\" width=\"100%\" cellpadding=\"0\">";
	msg += "<tr>";
	msg += "<td><input type=\"button\" value=\"80%\" class=\"send1\"  onclick=\"changeReliability(1)\"></td>";
	msg += "<td><input type=\"button\" value=\"90%\" class=\"send1\"  onclick=\"changeReliability(2)\"></td>";
	msg += "<td><input type=\"button\" value=\"95%\" class=\"send1\"  onclick=\"changeReliability(3)\"></td>";
	msg += "<td><input type=\"button\" value=\"97.5%\" class=\"send1\"  onclick=\"changeReliability(4)\"></td>";
	msg += "</tr>";
	msg += "</table>";

	return msg;
}
function changeRoute() {
	document.getElementById('departselector').selectedIndex = 0;
	setDateFields(now);
	returnTrip();
	sendform();
}
function changeTime(deltat) {
	var time = getTime();
	var millis = time.getTime();
	// milliseconds from 1970
	millis = millis + deltat;
	time.setTime(millis);
	setDateFields(time);
	sendform();
}
function changeReliability(index) {
	var reliabilityfield = document.getElementById("reliabilityselector");
	reliabilityfield.selectedIndex = index;
	sendform();
}
function getRouteDescription(xml) {
	// get results from xml
	var date = xml.getElementsByTagName("preformat")[0].childNodes[0].childNodes[0].nodeValue;
	var depart = xml.getElementsByTagName("preformat")[0].childNodes[1].childNodes[0].nodeValue;
	var duration = xml.getElementsByTagName("preformat")[0].childNodes[2].childNodes[0].nodeValue;
	var arrive = xml.getElementsByTagName("preformat")[0].childNodes[3].childNodes[0].nodeValue;
	var html = "";
	// ===== local functions =====
	// === waypoint banner ===
	function waypoint(point, address, time) {
		var target = '"' + "map.showMapBlowup(new GLatLng("
				+ point.toUrlValue(6) + "))" + '"';
		html += '<table style="border: 1px solid silver; margin: 10px 0px; background-color: rgb(238, 238, 238); border-collapse: collapse; color: rgb(0, 0, 0);">';
		html += '  <tr style="cursor: pointer;" onclick=' + target + '>';
		html += '    <td style="padding: 4px 15px 0px 5px; vertical-align: middle; width: 20px;">';
		html += ' </td>';
		html += '    <td style="vertical-align: middle; width: 100%;">';
		html += address;
		html += '    </td> ' + '<td>' + time + '</td>';
		html += '  </tr>';
		html += '</table>';
	}
	// === route distance ===
	function routeDistance(dist) {
		html += '<div style="text-align: right; padding-bottom: 0.3em;">' + dist + '</div>';
	}
	// === step detail ===
	function detail(point, num, description, dist) {
		var oddeven;
		if (num % 2 == 1) {
			oddeven = "odd";
		} else {
			oddeven = "even";
		}
		var target = '"' + "map.showMapBlowup(new GLatLng("
				+ point.toUrlValue(6) + "))" + '"';
		html += '<table style="margin: 0px; padding: 0px; border-collapse: collapse;">';
		html += '  <tr style="cursor: pointer;" onclick=' + target + '>';
		html += '    <td class=' + oddeven + ' style="border-top: 1px solid rgb(205, 205, 205); margin: 0px; padding: 0.3em 3px; vertical-align: top; text-align: right;">';
		html += '      <a href="javascript:void(0)"> ' + num + '. </a>';
		html += '    </td>';
		html += '    <td class=' + oddeven + ' style="border-top: 1px solid rgb(205, 205, 205); margin: 0px; padding: 0.3em 3px; vertical-align: top; width: 100%;">';
		html += description;
		html += '    </td>';
		html += '    <td class=' + oddeven + ' style="border-top: 1px solid rgb(205, 205, 205); margin: 0px; padding: 0.3em 3px 0.3em 0.5em; vertical-align: top; text-align: right;">';
		html += dist;
		html += '    </td>';
		html += '  </tr>';
		html += '</table>';
	}
	// === Copyright tag ===
	function copyright(text) {
		html += '<div style="font-size: 0.64em;">' + text + "</div>";
	}
	// === the copyright text ===
	copyright(gdir.getCopyrightsHtml());
	// === read through the GRoutes and GSteps ===
	for ( var i = 0; i < gdir.getNumRoutes(); i++) {
		var route = gdir.getRoute(i);
		var geocode = route.getStartGeocode();
		var point = route.getStep(0).getLatLng();
		// === Waypoint at the start of each GRoute
		var vertrek = "";
		if (depart.toString() != " - ") {
			vertrek = 'Vertrek:<b>' + depart + '</b>';
		}
		waypoint(point, document.getElementById('zip_from').value, vertrek);
		for ( var j = 0; j < route.getNumSteps(); j++) {
			var step = route.getStep(j);
			// === detail lines for each step ===
			detail(step.getLatLng(), j + 1, step.getDescriptionHtml(), step
					.getDistance().html);
		}
		routeDistance("<b>Totaal: " + route.getDistance().html + "</b>");
	}
	// === the final destination waypoint ===
	var geocode = route.getEndGeocode();
	var point = route.getEndLatLng();
	var aankomst = "";
	if (arrive.toString() != " - ") {
		aankomst = 'Aankomst:<b>' + arrive + '</b>';
	}
	waypoint(point, document.getElementById('zip_to').value, aankomst);
	return html;
}
// ============ fill details tab ===============
function getDetails(xml) {
	var html = "";
	// get results from xml
	var perc = xml.getElementsByTagName("perc")[0].firstChild.nodeValue;
	var length = xml.getElementsByTagName("length")[0].firstChild.nodeValue;
	var lengthObserved = xml.getElementsByTagName("lengthObserved")[0].firstChild.nodeValue;
	var freeflow = xml.getElementsByTagName("freeflow")[0].firstChild.nodeValue;
	var freeflowObserved = xml.getElementsByTagName("freeflowObserved")[0].firstChild.nodeValue;
	// === drop the whole thing into the target div
	if (lengthObserved == 0) {
		return html;
	}
	html += "<div id=\"Extra_routeinfo\"> Voor "
			+ Math.round(100 * parseFloat(lengthObserved) / parseFloat(length))
			+ " procent van deze route is de reistijdhistorie beschikbaar. Met behulp van deze historische reistijden en de dag van de week, seizoen, vakantieperiodes, zonsopkomst en -ondergang en weersverwachting wordt de verwachte reistijd bepaald. Op het gedeelte waar geen reistijdhistorie bekend is wordt gerekend met de normale snelheid.<br><br>De onderstaande tabel geeft de verdeling van de historische reistijden voor de opgegeven route.";
	perc = perc.split(' ');
	var oddeven;
	var percentage;
	html += '<table border="1" style="font-size: 10pt; margin: 0px; padding: 0px; border-collapse: collapse;">';
	html += '<tr><td><b> Reistijd (min)</b> </td> <td><b> Kans dat de reis langer duurt</b> </td> </tr>';
	for ( var i = 0; i < perc.length; i++) {
		if (i % 2 == 1) {
			oddeven = "odd";
		} else {
			oddeven = "even";
		}
		if (i == 0) {
			percentage = ">95%"
		} else if (i == perc.length - 1) {
			percentage = "<5%";
		} else {
			percentage = (100 - (i * 5)) + '%';
		}
		html += '<tr>';
		html += '<td class=' + oddeven + ' style=\"text-align: center;\">'
				+ Math.round(parseFloat(perc[i]) / 60) + '</td>';
		html += '<td class=' + oddeven + ' style=\"text-align: center;\">'
				+ percentage + '</td>';
		html += '</tr>';
	}
	html += '</table></div>';
	return html;
}
// ============ end details tab ===========
function clearDetails(xml) {
	document.getElementById("content_container").innerHTML = "";
}
function createMarkers() {
	// initialise array with start and end markers
	markers = new Array(2);
	markers[0] = createMarker(0);
	GEvent.addListener(markers[0], "dragend", function() {
		clearAll();
		doReverseGeoCoding(this.getLatLng(), 0);
		showRoute();
	});
	GEvent.addListener(markers[0], "click", function() {
		markers[0].showMapBlowup();
	});
	markers[1] = createMarker(1);
	GEvent.addListener(markers[1], "dragend", function() {
		clearAll();
		doReverseGeoCoding(this.getLatLng(), 1);
		showRoute();
	});
	GEvent.addListener(markers[1], "click", function() {
		markers[1].showMapBlowup();
	});
}
function createMarker(i) {
	var baseIcon = new GIcon();
	baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
	baseIcon.iconSize = new GSize(20, 34);
	baseIcon.shadowSize = new GSize(37, 34);
	baseIcon.iconAnchor = new GPoint(9, 34);
	baseIcon.infoWindowAnchor = new GPoint(9, 2);
	baseIcon.infoShadowAnchor = new GPoint(18, 25);
	var letter = String.fromCharCode("A".charCodeAt(0) + i);
	var letteredIcon = new GIcon(baseIcon);
	letteredIcon.image = "http://www.google.com/mapfiles/marker" + letter
			+ ".png";
	markerOptions = {
		icon :letteredIcon,
		draggable :true
	};
	var marker = new GMarker(new GPoint(0, 0), markerOptions);
	map.addOverlay(marker);
	marker.hide();
	return marker;
}

function setDateFields(time) {
	var hourselector = document.getElementById("hourselector");
	var minuteselector = document.getElementById("minuteselector");
	var dateselector = document.getElementById('dateselector');
	hourselector.selectedIndex = (time.getHours()) % 24;
	minuteselector.selectedIndex = Math.ceil((time.getMinutes()) / 5) % 12;
	// 5 minute intervals
	var time = new Date(time.getFullYear(), time.getMonth(), time.getDate());
	for ( var i = 0; dateselector.options.length; i++) {
		if (time == dateselector.options[i].value) {
			dateselector.selectedIndex = i;
			break;
		}
	}
}
function getTime() {
	var hourselector = document.getElementById("hourselector");
	var minuteselector = document.getElementById("minuteselector");
	var dateselector = document.getElementById('dateselector');
	var time = new Date(dateselector.value);
	time.setHours(hourselector.value);
	time.setMinutes(minuteselector.value);
	return time;
}
function zeropadd(nr) {
	if (nr.length == 1) {
		nr = "0" + nr;
	}
	return nr;
}
// fill the time field
function printNow(text) {
	// get time field
	var timefield = document.getElementById("time");
	var datefield = document.getElementById("date");
	// get year, month, day, hour and minute from xml and add 0 if necessary
	var yearstring = zeropadd(text.getElementsByTagName("year")[0].childNodes[0].nodeValue);
	var monthstring = zeropadd(text.getElementsByTagName("month")[0].childNodes[0].nodeValue);
	var daystring = zeropadd(text.getElementsByTagName("day")[0].childNodes[0].nodeValue);
	var hourstring = zeropadd(text.getElementsByTagName("hour")[0].childNodes[0].nodeValue);
	var minutestring = zeropadd(text.getElementsByTagName("minute")[0].childNodes[0].nodeValue);
	timefield.value = hourstring + ":" + minutestring;
	datefield.value = daystring + "/" + monthstring + "/" + yearstring;
}
function clearRouteDescription() {
	document.getElementById("content_container").innerHTML = "";
}
function clearMessage() {
	var msg_container = document.getElementById("msg_container");
	msg_container.style.display = 'none';
	msg_container.innerHTML = "";
}
function showMessage(msg) {
	var msg_container = document.getElementById("msg_container");
	msg_container.style.display = 'block';
	msg_container.innerHTML = msg;
}
function clearError() {
	var error_container = document.getElementById("error_container");
	error_container.style.display = 'none';
	error_container.innerHTML = "";
}
function showError(xml) {
	var text = xml.getElementsByTagName("text")[0].childNodes[0].nodeValue;
	var code = xml.getElementsByTagName("code")[0].childNodes[0].nodeValue;
	var error_container = document.getElementById("error_container");
	error_container.style.display = 'block';
	error_container.innerHTML = text;
	clearMessage();
}
function clearAll() {
	clearMessage();
	clearError();
	clearDetails();
	showPrintButton(false);
	clearRouteDescription();
}
function showPrintButton(b) {
	var button = document.getElementById("printbutton");
	if (b == true) {
		button.style.display = 'inline';
	} else {
		button.style.display = 'none';
	}
}

function displayResultMessage(xml) {
	showMessage(routeDuration(xml));
	document.getElementById("content_container").innerHTML = getRouteDescription(xml);
	showPrintButton(true);
	document.getElementById("Extrainfo_container").innerHTML = getDetails(xml);
}

function ContextMenu(oMap) {
	this.initialize(oMap);
}
// Construct the DOM tree of the menu
ContextMenu.prototype.initLink = function(oMap) {
	var that = this;
	a_link = document.createElement("li");
	a_link.innerHTML = "<a href='javascript:void(0);'>&raquo;Route vanaf dit punt</a>";
	GEvent.addDomListener(a_link,
					'click',
					function() {
						// correct address
					clearAll();
					document.getElementById("zip_from").style.backgroundColor = 'F5F5F5';
					// grey
					var point = map.fromContainerPixelToLatLng(
							that.clickedPixel, map.getZoom());
					markers[0].setLatLng(point);
					markers[0].show();
					that.contextmenu.style.display = 'none';
					window.setTimeout("showRoute()", 10);
					window
							.setTimeout(
									"doReverseGeoCoding(markers[0].getLatLng(), 0)",
									10);
				});
	this.ul_container.appendChild(a_link);
	a_link = document.createElement("li");
	a_link.innerHTML = "<a href='javascript:void(0);'>&raquo;Route naar dit punt</a>";
	GEvent.addDomListener(a_link, 'click', function() {
		// correct address
			clearAll();
			document.getElementById("zip_to").style.backgroundColor = 'F5F5F5';
			// grey
			var point = map.fromContainerPixelToLatLng(that.clickedPixel, map
					.getZoom());
			markers[1].setLatLng(point);
			markers[1].show();
			that.contextmenu.style.display = 'none';
			window.setTimeout("showRoute()", 10);
			window.setTimeout("doReverseGeoCoding(markers[1].getLatLng(), 1)",
					10);
		});
	this.ul_container.appendChild(a_link);
}

function doReverseGeoCoding(point, index) {
	var labels = [ 'zip_from', 'zip_to' ];
	var reversegeocoder;
	// reverse geocoder object
	try {
		reversegeocoder = new GReverseGeocoder(map);
	} catch (e) {
		document.getElementById(labels[index]).value = "Zie kaart";
		return;
	}
	// add listeners for the results
	GEvent
			.addListener(reversegeocoder,
					"load",
					function(placemark) {
						if (placemark.AddressDetails.Country.CountryNameCode
								.toUpperCase() != "NL") {
							// buitenland
					document.getElementById(labels[index]).style.backgroundColor = '#F5F5F5';
					// grey
				} else {
					document.getElementById(labels[index]).style.backgroundColor = 'F5F5F5';
					// grey
				}
				document.getElementById(labels[index]).value = placemark.address;
			});
	GEvent
			.addListener(
					reversegeocoder,
					"error",
					function() {
						document.getElementById(labels[index]).style.backgroundColor = 'FF0000';
						// red
						document.getElementById(labels[index]).value = "Onbekende locatie";
					});
	// reverse geocode this point
	reversegeocoder.reverseGeocode(point);
}
function goodresult(placemark) {
	var address = placemark.address;
	document.getElementById("zip_to").style.backgroundColor = 'F5F5F5';
	// grey
	document.getElementById("zip_to").value = placemark.address;
	// grey
}
function badresult() {
	alert("error");
}
ContextMenu.prototype.bind = function(method) {
	var self = this;
	var opt_args = [].slice.call(arguments, 1);
	return function() {
		var args = opt_args.concat( [].slice.call(arguments));
		return method.apply(self, args);
	}
}
// The object 'constructor'
ContextMenu.prototype.initialize = function(oMap) {
	this.map = oMap;
	var that = this;
	this.contextmenu = document.createElement("div");
	this.contextmenu.style.display = "none";
	// CSS class name of the menu
	this.contextmenu.className = "contextmenu";
	this.ul_container = document.createElement("ul");
	this.ul_container.id = "context_menu_ul";
	this.contextmenu.appendChild(this.ul_container);
	this.initLink();
	this.map.getContainer().appendChild(this.contextmenu);
	// Event listeners that will interact with our context menu
	GEvent.addListener(oMap, "singlerightclick", function(pixel, tile) {
		that.clickedPixel = pixel;
		var x = pixel.x;
		var y = pixel.y;
		// Prevents the menu to go out of the map margins, in this case the
			// expected menu size is 150x110
			if (x > that.map.getSize().width - 160) {
				x = that.map.getSize().width - 160
			}
			if (y > that.map.getSize().height - 120) {
				y = that.map.getSize().height - 120
			}
			var pos = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(x, y));
			pos.apply(that.contextmenu);
			that.contextmenu.style.display = "";
		});
	GEvent.addListener(oMap, "move", function() {
		that.contextmenu.style.display = "none";
	});
	GEvent.addListener(oMap, "click", function(overlay, point) {
		that.contextmenu.style.display = "none";
	});
}
function ResizeControl() {
}
ResizeControl.prototype = new GControl();
ResizeControl.prototype.initialize = function(map) {
	var resizeButton = document.createElement("div");
	resizeButton.style.width = "20px";
	resizeButton.style.height = "20px";
	resizeButton.style.backgroundImage = "url(img/resize_orange.gif)";
	resizeButton.onmousedown = function() {
		resizable = true;
	}
	resizeButton.onmouseup = function() {
		resizable = false;
	}
	var container = map.getContainer();
	container.appendChild(resizeButton);
	/*
	 * Move the Copyright 25px to the left to make sure that it's fully readable
	 */
	var copyrightdiv = container.firstChild.nextSibling;
	copyrightdiv.style.marginRight = "25px";
	return resizeButton;
}
ResizeControl.prototype.getDefaultPosition = function() {
	return new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(0, 0));
}
var typecontrol = new GMapTypeControl(true);
// Resizes the map's width and height by the given increment
function changeMapSize(dx, dy) {
	var mapdiv = map.getContainer();
	var height = parseInt(mapdiv.style.height);
	/*
	 * Take care that the map's width or height do not get too small
	 */
	if (height < 300) {
		height = 300;
		resizable = false;
	}
	mapdiv.style.height = (height + dy) + "px";
}
// Mouse move listener
function watchMouse(e) {
	// Include possible scroll values
	var sx = window.scrollX || document.documentElement.scrollLeft || 0;
	var sy = window.scrollY || document.documentElement.scrollTop || 0;
	if (!e) {
		e = window.event;
	}
	// IEs event definition
	mouseX = e.clientX + sx;
	mouseY = e.clientY + sy;
	// How far has the box been resized?
	var deltaX = mouseX - resizedX;
	var deltaY = mouseY - resizedY;
	// Store the difference in global variables
	resizedX = mouseX;
	resizedY = mouseY;
	if (resizable == true) {
		// The resize button is being held
		changeMapSize(deltaX, deltaY);
	}
}
function LayerControl() {
};
LayerControl.prototype = new GControl();
LayerControl.prototype.initialize = function(map) {

	var layer = document.createElement("div");
	layer.style.border = "1px solid black";
	layer.title = "Show/Hide Layers";
	layer.onmouseover = showLayerbox;
	layer.onmouseout = setClose;
	layer.onclick = toggleLayers;

	var inner = document.createElement("div");
	inner.id = "more_inner";
	inner.appendChild(document.createTextNode("Weer en Verkeer"));
	layer.appendChild(inner);

	map.getContainer().appendChild(layer);
	return layer;
}

LayerControl.prototype.getDefaultPosition = function() {
	return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(278, 7));
}

function showLayerbox() {

	var layerbox = document.getElementById("box");
	// Left size of more control plus mapdiv.style.left
	var offsetX = 278;
	// Top size of more control plus mapdiv.style.top plus more button height
	var offsetY = 7 + 18;

	var lpos = new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(offsetX,
			offsetY));
	try {

		lpos.apply(layerbox);
		if (window.timer)
			clearTimeout(timer);
		layerbox.style.display = "block";
	} catch (e) {
		alert(e)
	}
	;

}

function toggleLayers() {

	if (chosen.length > 0) {
		/*
		 * Make an independent copy of chosen array since switchLayer() resets
		 * the chosen array, which may not be useful here.
		 */
		var copy = chosen.slice();
		for ( var i = 0; i < copy.length; i++) {
			var index = parseInt(copy[i]);
			switchLayer(true, layers[index].obj);
			document.getElementsByName("mark")[index].checked = true;
		}
	} else {
		hideAll();
	}
}

function hideAll() {

	var boxes = document.getElementsByName("mark");
	for ( var i = 0; i < boxes.length; i++) {
		if (boxes[i].checked) {
			boxes[i].checked = false;
			switchLayer(false, layers[i].obj);
			chosen.push(i);
		}
	}
}

function checkChecked() {

	/*
	 * Returns true if a checkbox is still checked otherwise false
	 */
	var boxes = document.getElementsByName("mark");
	for ( var i = 0; i < boxes.length; i++) {
		if (boxes[i].checked)
			return true;
	}
	return false;
}

function switchLayer(checked, layer) {

	/*
	 * Function was originally borrowed from Esa:
	 * http://esa.ilmari.googlepages.com/dropdownmenu.htm
	 */
	var layerbox = document.getElementById("box");
	var boxlink = document.getElementById("boxlink");
	var button = document.getElementById("more_inner");

	if (checked) {
		map.addOverlay(layer);
		// Reset chosen array
		chosen.length = 0;
		/*
		 * Highlight the link and make the button font bold.
		 */
		boxlink.className = "highlight";
		layerbox.className = "highlight";
		button.className = "highlight";
	} else {
		map.removeOverlay(layer);
		/*
		 * Reset the link and the button if all checkboxes were unchecked.
		 */
		if (!checkChecked()) {
			boxlink.blur();
			boxlink.className = "";
			layerbox.className = "";
			button.className = "";
		}
	}
}

function setClose(e) {

	if (!e)
		e = window.event;
	var layerbox = document.getElementById("box");

	if (checkMouseLeave(layerbox, e))
		timer = setTimeout( function() {
			layerbox.style.display = "none";
		}, 200);
}

function checkMouseLeave(element, evt) {

	/*
	 * Avoid firing a mouseout event when the mouse moves over a child element.
	 * Borrowed from:
	 * http://www.faqts.com/knowledge_base/view.phtml/aid/1606/fid/145
	 */
	if (element.contains && evt.toElement) {
		return !element.contains(evt.toElement);
	} else if (evt.relatedTarget) {
		return !containsDOM(element, evt.relatedTarget);
	}
}

function containsDOM(container, containee) {

	var isParent = false;
	do {
		if ((isParent = container == containee))
			break;
		containee = containee.parentNode;
	} while (containee != null);
	return isParent;
}

function initForm() {
	var zip_from = "";
	var zip_to = "";	
	// scan url for arguments
	var questionlocation = location.href.indexOf('?');
	if (questionlocation > 0) {
		var q = location.href.substr(questionlocation + 1);
		var list = q.split('&');
		for ( var i = 0; i < list.length; i++) {
			var kv = list[i].split('=');
			kv[1] = unescape(kv[1]);
			if (kv[1].indexOf('"') > -1) {
				var re = /"/g;
				kv[1] = kv[1].replace(re, '\\"');
			}
			if (kv[0] == "zip_from" || kv[0] == "from") {
				zip_from = kv[1];
			} else if (kv[0] == "zip_to" || kv[0] == "to") {
				zip_to = kv[1];
			}
		}
	}
	document.getElementById('zip_from').value = zip_from;
	if (zip_from != "") {
		setStartPoint();
	}
	document.getElementById('zip_to').value = zip_to;
	if (zip_to != "") {
		setEndPoint();
	}
	// Fill selectors with options (depending on the time)
	populateSelectors();
	
	var time = new Date();
	// today
	var millis = time.getTime();
	// milliseconds from 1970
	millis = millis + 0 * 60 * 1000;
	// add 0 minutes
	time.setTime(millis);
	setDateFields(time);
}
function windowHeight() {
	var myWidth = 0, myHeight = 0;
	if (typeof (window.innerWidth) == 'number') {
		// Non-IE
		myHeight = window.innerHeight;
	} else if (document.documentElement
			&& (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
		// IE 6+ in 'standards compliant mode'
		myHeight = document.documentElement.clientHeight;
	} else if (document.body
			&& (document.body.clientWidth || document.body.clientHeight)) {
		// IE 4 compatible
		myHeight = document.body.clientHeight;
	}
	return myHeight;
}
function screenHeight() {
	return screen.height;
}

function resize() {
	map.getContainer().style.height = Math.max(300, screenHeight() * 2 / 4)
	+ "px";

}

function populateSelectors() {
	populateDaySelector();
	populateHourSelector();
	populateMinuteSelector();
	populateDepartSelector();
}

function populateDaySelector() {
	var daynames = [ 'Zondag', 'Maandag', 'Dinsdag', 'Woensdag', 'Donderdag',
			'Vrijdag', 'Zaterdag' ];
	var monthnames = [ 'januari', 'februari', 'maart', 'april', 'mei', 'juni',
			'juli', 'augustus', 'september', 'oktober', 'november', 'december' ];
	var day = new Date();
	// today
	var millis = day.getTime();
	// milliseconds from 1970
	var dateselector = document.getElementById("dateselector");
	// populate dateselector
	for ( var i = 0; i < 31; i++) {
		var text;
		if (i == 0) {
			text = "Vandaag";
		} else if (i == 1) {
			text = "Morgen";
		} else {
			text = daynames[day.getDay()];
		}
		text = text + " " + day.getDate() + " " + monthnames[day.getMonth()];
		dateselector.options[i] = new Option(text, new Date(day.getFullYear(),
				day.getMonth(), day.getDate()));
		millis = millis + 24 * 60 * 60 * 1000;
		// add one day
		day.setTime(millis);
	}

}

function populateHourSelector() {
	var hourselector = document.getElementById("hourselector");
	var value;
	for ( var i = 0; i < 24; i++) {
		value = zeropadd(i.toString());
		hourselector.options[i] = new Option(value, value);
	}
}

function populateMinuteSelector() {
	var minuteselector = document.getElementById("minuteselector");
	var value;
	for ( var i = 0; i < 12; i++) {
        // WIJZ ZIJPP 20090827 5 min time steps
        p=5*i;
        value = zeropadd(p.toString());
        minuteselector.options[i] = new Option(value, value);

	}
}

function populateDepartSelector() {
	var departselector = document.getElementById("departselector");
	departselector.options[0] = new Option("Aankomst", 0);
	departselector.options[1] = new Option("Vertrek", 1);
	
	departselector.selectedIndex = 1;
}

window.onload = load();
window.onmouseup = function() {
	resizable = false;
}
window.onresize = resize;
