/**
  * (c) SMARTposition 2006-2008
  *
  * http://www.smartposition.nl
  * 
  * date: 29-01-2008
  * version: 0.62
  * Author: Paul, Swen-Peter
  * -----------------
  * 0.1					basic functions
  * 0.2					more options
  * 0.3					added centering
  * 0.4					added info divs
  * 0.5 				improvement in GPX parsing
  * 0.6 	26-06-2007	added dynamic KML overlays and some overall improvements
  *	0.61	30-10-2007	added dragzoom control
  * 0.62	29-01-2008	Added show all trackers
  *
  *
  * BUGS
  * - #1	01-03-2007	Google maps does not load with API's newer than v2.82
  * - #2	29-01-2008	Show all icons must take into account the visible control boxes
  */

/*
 * initial map parameters
 */
var mapSize = "large";						//valid values; "small", "large"
var mapType = G_NORMAL_MAP;					//valid values; overwritten by user settings
var zoomLevel = 10;							//range [0-17]; overwritten by user settings in database
var initialLat = 52.281634;					//initial map position, overwritten by user settings in database
var initialLong = 6.421701;					


var baseIcon = new GIcon();					//set the properties of the base icon
	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);


/**
  * GPX parameters
  */
var gpxUrl = "./gpx.php";					//GPX basic URL
											//variables used as GET parameter for AJAX request
var tailLength = 20;						//number of history items requested per tracker
var trackStart = 20070101120159;			//NOT used, ment to determine the start of the returned GPX data
var subKey = '';							//key used for subgroups
var exportFile = '';						//only used to pass a export file

var refreshInterval = 15 * 1000;			//defines how often the GPX file is reloaded (with AJAX calls), overwritten by account settings
var reloadPageInterval = 1000* 60 * 10;		//defines at what interval the complete URL is reloaded

/*
 * marker drawing parameters
 */
var iconTable = createIcons();				//array that holds all the icons

var drawWaypoints = false;					//true or false, draw waypoints or not, function replaced by KML files
var waypointMarkerIcon = iconTable["red_pin"];
var drawRoutes = false;						//true or false, used to enable or disable drawing the routes defined in the GPX, function replaced by KML files
var drawRoutePolyLine = false;				//true or false, used to draw a line between route points, function replaced by KML files
var drawTracks = true;						//true or false, used to enable or disable drawing the tracks (tails) of trackers
var drawTrackPolyLine = true;				//true or false
var initCustomMap = true;					//true or false, set to false to disable ANY customized map (e.g. white map as well)

// route/track drawing parameters
var drawStartMarker = false; 				// draw marker at the start of a route/track
var startMarkerIcon = iconTable["flag_green.png"];
var drawEndMarker = true; 					// draw marker at the end of a route/track
var endMarkerIcon = iconTable["flag_red.png"];
var drawIntervalMarker = 1; 				// for routes and tracks, draw markers at the specified interval on the polyline; int
var intervalMarkerIcon = iconTable["dot_12_009cff.png"];

var autoCenter = false; 					// value is overwritten at init in functions.js/init()		
var focusOn = 0;							//default tracker that is selected in the interface, overwritten by database values
var focusInfo = new Array();
var isCentered = false;
var minimalCenterMovement=0.20;				//minimal movement that is required before the map is panned, define by trail and error
var minimalTrackerSpeed = 0;				//minimal speed value in km/h, might trigger an alarm (incase speedAudioFile is set and audioAlarm is true), overwritten by account settings
var maximalTrackerSpeed = 200;				//maximal speed value in km/h, might trigger an alarm (incase speedAudioFile is set and audioAlarm is true), overwritten by account settings
var audioAlarm = false;						//set this value to true and a valid id for speedAudioFile to enable adio alarm
var audioAlarmTimeout = 1;					//defines how long a alarm condition is valid (in minutes) and will cause an audio alarm

var map = null;								//variable contains the Gmaps, map object
var mapOverlays = new Array();				//array contains all gMap items added to the map, originated in the GPX. This arrays does NOT contain the geoXML files (since they don't need a refresh)

											//geoXML object to parse a KML into GMaps
var geoXml = new Array();					//array that contains the KML files that are added to the map, items are added based on user settings
var customerLogoSrc = '';					//customer logo displayed in the right bottom corner of the gmaps interface, overwritten by user settings
var eventStartDate = new Date(0000,0-1,0,0+checkTimeZone(false)-1,0,0);		//overwritten by account settings

var initGeoXml = true; 						//set this variable to false to disable loading of the KML overlay files, variable is used in function addKmlOverlay()

var markersBounds = new GLatLngBounds();	//this variable is used for the show all function

/**
  * Function to initialize the google earth map
  *
  * @param id, the id of the HTML object that is used to display the google map
  */
function initMap(id){
	if (!GBrowserIsCompatible()) {
		alert('Your browser is not compatible with the Google Maps API, please install the latest version of your webbrowser!');
		return;
	}
	
	//start the clock, and update it every second
	setInterval('updateClock(eventStartDate)',1000);
	
	//check if a customer image exists, if so enable the HTML object
	if(customerLogoSrc != ''){
		document.getElementById("customerLogo").style.display = 'block';
		document.getElementById("customerLogoImg").src = customerLogoSrc;
	}//end set custom logo

	//create new map object
	map = new GMap2(document.getElementById(id));
	
	// Add the custom opacity maps
	//addcustomMapOpacity();
	
	if (this.mapSize == "small") {
		map.addControl(new GSmallMapControl());
	}else {
		//Add map controls
		map.addControl(new GMapTypeControl());
		map.addControl(new GLargeMapControl(), 
			new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(10,45)));
		
		map.addControl(DragZoom = getDragZoomControl(), 
          new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(80,45)));
	}//end if mapSize
	
	// Enable map control properties
	map.enableInfoWindow();
	map.enableDragging();
	map.enableDoubleClickZoom();
	map.enableContinuousZoom();	
	map.enableScrollWheelZoom();
	
	//add map listeners
	GEvent.addListener(map, "moveend", function() {
	  var center = map.getCenter();
	  initialLat = center.lat();
	  initialLong = center.lng();
	});
	
	GEvent.addListener(map, "zoomend", function(oldLevel, newLevel) {
		//record the zoom level for auto refreshing
	 	zoomLevel = newLevel;
	});
	
	GEvent.addListener(map, "maptypechanged", function() {
	});
	
	zoomLevel = parseInt(zoomLevel);	//otherwise the zoomLevel will be set to 0
	
	// Set center
	map.setCenter(new GLatLng(initialLat, initialLong), zoomLevel, mapType);
	
	//add kml overlay files
	addKmlOverlay();
	
	var requestParams = getRequestParams();
	if(requestParams['subkey'] == 'kadaster'){
		addCustomMap('Kadaster','TOP25','http://85.92.147.179/~smart/resources/tiles/top25/');
	}else{
		// Add the white edition map
		addcustomMapWhite();
	}
}//end initMap


/**
  * Loads the map in view only mode
  */
function loadViewMap(id, mapSize) {
	if (mapSize) this.mapSize = mapSize;
	
	initMap(id);
}//end function loadViewMap




/**
 * Initialize data on gmaps loaded from a GPX file, cyclic called
 *
 * This function intitiates the refresh GPX data timeout
 *
 * @param data
 * @param responseCode
 *
 * @return null
 */
function onGPXLoad(data, responseCode) {
	
	var xml = GXml.parse(data);
	var gpx = new GPX();
	
	if (responseCode == 200) gpx.load(xml);
	else setStatus("Sorry, the GPX file could not be loaded");
	
	//
	//remove all overlays (except the geoXml)
	//
	
	var tmpOverlay;		// variable that temporary holds the maps overlays
	while(tmpOverlay = (mapOverlays.pop())){
		map.removeOverlay(tmpOverlay);
	}//end remove mapOverlays
	tmpOverlay = null;
	
	mapOverlays = new Array();				//reset the mapsOverlays array
	markersBounds = new GLatLngBounds();	//reset the markerBounds
	
	// Draw waypoints, function not used for live system: replaced by KML files
	if (drawWaypoints) {
		var waypoints = gpx.getWaypoints();
		var html = "";
		for (var i = 0; i < waypoints.length; i++) {
			wpt = waypoints[i];
			markerIcon = chooseIcon(GPX.wpt, "", wpt.sym);
			html = "<b>"+wpt.name+"</b>";
			if(wpt.cmt){
				html += "<br />" + wpt.cmt;
			}//end comment
			createMarker(wpt, html, markerIcon);
			
		}//end for
	}//end drawWaypoints
	
	// Draw tracks
	if (drawTracks) {
		var tracks = gpx.getTracks();
		
		centerView(GPX.trk, tracks);
		
		// Iterate through tracks
		for (var i = 0; i < tracks.length; i++) {
			if (tracks[i]) {
				
				// Iterate through track segments
				for (var s = 0; s < tracks[i].length; s++) {
					if (tracks[i][s]) {
						drawSequence(GPX.trk, tracks[i][s], tracks[i].name,tracks[i].desc,tracks[i].color);
						//if this track sequence contains some points
						if(tracks[i][s].length > 0){
							//add wpt to marker bounds	
							markersBounds.extend(tracks[i][s][0]);
						}
					}//end if
				}//end for
			}//end if
		}//end for
	}//end draw tracks
	
	// Draw routes, function replaced by KML files
	if (drawRoutes) {
		var routes = gpx.getRoutes();
		// Iterate through routes
		for (var i = 0; i < routes.length; i++) {
			if (routes[i]) {
				drawSequence(GPX.rte, routes[i], routes[i].name,tracks[i].desc,tracks[i].color);
			}//end if
		}//end for
	}//end drawroutes
	
	// set Timeout to reload GPX data!!
	window.setTimeout('loadData()', refreshInterval);
}//end function onGPXLoad

/*
 * Function that centers the map on the value of the variable "focusOn".
 * Also, the last position (and it's associated information) for each track is put
 * into the "focusInfo" array. Part of this information is also put in the DOM
 * as a div element, into the "focusInfo" div.
 *
 * @param type
 * @param tracks
 * 
 * @return null
 */
function centerView(type, tracks) {
	clearChildren(document.getElementById("focusInfo"));
	
	var today_date = new Date();

	// loop through the tracks and check if it actually contains tracksegments
	for (var i = 0; i < tracks.length; i++) {
		if (tracks[i] && tracks[i].length > 0) {
			
			var infoNode = document.createElement("div");
			infoNode.id = tracks[i].name;
			
			infoNode.className = "info";
			document.getElementById("focusInfo").appendChild(infoNode);
			
			lastSeg = tracks[i].length - 1;
			
			if (tracks[i][lastSeg].length > 0) {
				lastPoint = 0;//tracks[i][lastSeg].length - 1;

				focusInfo[tracks[i].name] = tracks[i][lastSeg][lastPoint];
				focusInfo[tracks[i].name].focusLink = "<a href='javascript:void(0)' onclick='setFocus(" + tracks[i].name + ",-1)' title=''><span style='display: %s;'>%s</span></a>";
				focusInfo[tracks[i].name].focusZoomLink = "<a href='javascript:void(0)' onclick='setFocus(" + tracks[i].name + ",17)' title=''><span style='display: %s;'>%s</span></a>";
				
				var current = focusInfo[tracks[i].name];
				
				var print_time = current.time.replace('T',' ').replace('Z','');
				var position_time = parseXmlTimeToDate(print_time);
				
				var alertClass = '';
				//check the speed of the tracker
				if(current.speed){
					if(current.speed < minimalTrackerSpeed){
						alertClass='lowAlarm';
					}
					else if(current.speed > maximalTrackerSpeed){
						alertClass='highAlarm';
					}
					//use default
				}//end speed check
				
				// format the displayed time
				if((today_date.getDate()) ==  position_time.getDate() && (today_date.getMonth()) == position_time.getMonth()){
					print_time = print_time.substring(11) + " (today)";
				}else{
					//print_time = position_time.getYear()+1900;//formatDate(position_time,'MM-dd-yyyy hh:mm:ss');
				}
				
				var infoNodeContent = "<h2 class='title "+alertClass+"'><div class='color' style='background-color: #" + tracks[i].color + ";'></div>"
										+ tracks[i].desc + current.focusLink + "</h2>" +
										"<div style='display: %s;'>" +
										"<p class='date'><span class='key'>Time:</span><span class='value'>" +
										print_time + 
										"</span></p>";
				if(current.speed){
					infoNodeContent += "<p class='speed'><span class='key'>Speed:</span><span class='value "+alertClass+"'>" + current.speed + " km/h</span></p>";
				}//end speed append
				
				if(current.distance && current.distance > 0){
					infoNodeContent += "<p class='speed'><span class='key'>Distance:</span><span class='value'>" + current.distance + " km</span></p>";
				}//end speed append
							
				if(current.cmt){
					//comments are comma seperated
					var commentArray = current.cmt.split(',');
					var comment = '';
					var tmp;
					while(tmp = (commentArray.pop())){
						comment += tmp + '<br />';
					}//end collect comments
					
					infoNodeContent += "<p class='course'><span class='key'>Info:</span><span class='value'>" +  comment + "</span></p>";
				}//end desc append
				
				infoNodeContent 	+= "</div>";
				
				// show information for focused object
				
				if (tracks[i].name == focusOn) {
					infoNode.innerHTML = printf(infoNodeContent, "inline", "centre", "block");

					// has the centered point moved more than 15% from the center of the map?
					if (autoCenter && (getPercentageFromCenter(tracks[i][lastSeg][lastPoint]) > minimalCenterMovement)) {
						map.setCenter(current);
					}
					isCentered = true;
				}else {// if this track is not focused, just show the title with follow link
					infoNode.innerHTML = printf(infoNodeContent, "inline", "follow",  "none")
				}
			}
		}
	}//end tracks forloop
	
	return true;
}//end function centerView

/*
 * Draws the actual routes and tracks on top of the map
 *
 * @param type
 * @param sequence
 * @param name
 * @description
 * @color
 *
 * @return null
 */
function drawSequence(type, sequence, name, description, color) {
	if (sequence.length > 0) {
		// Draw route as polyline
		if ((type == GPX.rte && drawRoutePolyLine) || (type == GPX.trk && drawTrackPolyLine)) {
			lineStyle = chooseLineStyle(type, name, color);
			var line = new GPolyline(sequence, lineStyle.color, lineStyle.width, lineStyle.opacity);
			
			addOverlay(line,true);
			
		}//end polyLine
		
		// Draw 1 in drawIntervalMarker waypoints as a marker
		if (drawIntervalMarker) {
			var startCount = drawStartMarker ? drawIntervalMarker : 0;
			var endCount = drawEndMarker ? sequence.length : (sequence.length + 1);
			
			for (var w = startCount; w < endCount; w += drawIntervalMarker) {
				wpt = sequence[w];
				
				html = "<div class='markerInfo'><h2 class='name'>" + description + "</h2>"
										+ "<p class='date'><span class='key'>Time:</span><span class='value'>" +
										wpt.time.replace('T',' ').replace('Z','') + 
										"</span></p>";
				if(wpt.speed){
						html += "<p class='speed'><span class='key'>Speed:</span><span class='value'>" + wpt.speed + " km/h</span></p>";
				}//end speed append

				html += "</div>";
			
				markerIcon = chooseIcon(type, "interval", color);
				createMarker(wpt, html, markerIcon);
			}//end for
		}//end interval marker
		
		// Draw first and last marker
		if (drawStartMarker) {
			wpt = sequence[sequence.length-1];
			
			markerIcon = chooseIcon(type, "start", color);
			createMarker(wpt, "<div class='markerInfo'><h2 class='name'>" + description + "</h2>" + wpt.cmt + "</div>", markerIcon);
		}//end startMarkerk
		
		if (drawEndMarker) {
			wpt = sequence[0];
			
			markerIcon = chooseIcon(type, "end", wpt.sym+'_'+color);
			html = "<div class='markerInfo'><h2 class='name'>" + description + "</h2>" 
										+ "<u>Details</u>"
										+ "<p class='date'><span class='key'>Time:</span><span class='value'>" +
										wpt.time.replace('T',' ').replace('Z','') + 
										"</span></p>";
			if(wpt.speed){
					html += "<p class='speed'><span class='key'>Speed:</span><span class='value'>" + wpt.speed + " km/h</span></p>";
			}//end speed append
			if(wpt.magvar){
					html += "<p class='course'><span class='key'>Course:</span><span class='value'>" + degreeToDirection(wpt.magvar) + ", " +  wpt.magvar + " &deg;</span></p>";
			}//end magvar append
			
			if(wpt.sat){
					html += "<p class='course'><span class='key'>Satellite:</span><span class='value'>" +  wpt.sat + " </span></p>";
			}//end sat append
			
			if(wpt.hdop){
					html += "<p class='course'><span class='key'>DOP:</span><span class='value'>" +  wpt.hdop + " </span></p>";
			}//end hdop append
			
			//voeg de controls toe
			var focusL = "<p class='focusLink'>" + printf(wpt.focusLink, "inline", "Focus and follow " + description + "") + "</p>";
			var zoomL = "<p class='focusLink'>" + printf(wpt.focusZoomLink, "inline", "Zoom to street level " + description + "") + "</p>";
			html += "<u>Controls</u>" + focusL + zoomL;
				
			html += "</div>";
			
			createMarker(wpt,html , markerIcon);
		}//end end marker
	}
}//end function drawSequence

/**
  * Set focus to a specified object
  *
  * @param focusTo
  * @param zoomLevel, zoomLevel that is selected 
  *
  * @return nothing
  */
function setFocus(focusTo,zoomLevel) {
	
	if (focusTo != focusOn) {
		focusNode = document.getElementById(focusTo);
		
		var infoNodes = focusNode.parentNode.childNodes;
		
		for (var i = 0; i < infoNodes.length; i++) {
			infoNodes[i].getElementsByTagName("div")[1].style.display = "none";
			infoNodes[i].getElementsByTagName("span")[0].style.display = "inline";
		}
		focusNode.getElementsByTagName("div")[1].style.display = "block";
		focusNode.getElementsByTagName("span")[0].style.display = "none";
		
		focusOn = focusTo;
	}
	if(zoomLevel == -1){
		map.setCenter(focusInfo[focusTo]);
	}else{
		map.setCenter(focusInfo[focusTo],zoomLevel);
	}
	
	return true;
}//end function setFocus

/**
  * Function creates a marker point with a info window
  *
  * @param point
  * @param html
  * @param icon
  *
  * @return marker
  */
function createMarker(point, html, icon){
	var marker;
	
	if (icon) marker = new GMarker(point,icon);
	else marker = new GMarker(point);
	
	//add event listners
	GEvent.addListener(marker, "dblclick", function() {
		map.setCenter(marker.getPoint());
	});
	
	if (this.mapSize == "large") {
		GEvent.addListener(marker, "click", function() {
			//open window
			marker.openInfoWindowHtml(html);
			//center map to this point
			//map.setCenter(marker.getPoint());
		});
	}
	addOverlay(marker,true);
	
	return marker;
}//end function createMarker

/**
  * Get the percentage of a specified point to the center
  *
  * @param point
  *
  * @return percentage (0.x)
  */
function getPercentageFromCenter(point) {
	mapCrossSize = map.getBounds().getNorthEast().distanceFrom(map.getBounds().getSouthWest());
	mapCenter = map.getCenter();
	if(mapCenter){
		distanceFromCenter = mapCenter.distanceFrom(point);
		//alert(distanceFromCenter/mapCrossSize);
		return distanceFromCenter/mapCrossSize;
	}
	return 0.9;
}//end function getPercentageFromCenter


/**
  * Add item to the maps
  *
  * @param overlay
  * @param isRemovable
  *
  * @return nothing
  */
function addOverlay(overlay,isRemovable){
	map.addOverlay(overlay);
	if(isRemovable){
		mapOverlays.push(overlay);
	}
}//end function addOverlay

/**
  * Add kml overlays to the map
  *
  * @return nothing
  */ 
function addKmlOverlay(){
	if(!initGeoXml && (geoXml.length == 0)) return;
	
	var tmpGeoXml;
	while(tmpGeoXml = (geoXml.pop())){
		addOverlay(tmpGeoXml,false);
	}//end add overlays
}//end function addKmlOverlay

/**
  * Function that zoom to a certain zoom level to show all added markers on the map
  *
  *
  * @return nothing
  */
function showAllMarkers(){
	if(markersBounds != null && !markersBounds.isEmpty()){
		//now try to figure out the center point and zoom level
		var showAllZoomLevel = map.getBoundsZoomLevel(markersBounds);
		var showAllCenterPoint = markersBounds.getCenter();
		//zoom out one level extra
		if(showAllZoomLevel > 0){
			showAllZoomLevel --;
		}
		map.setCenter(showAllCenterPoint,showAllZoomLevel);
	}
}//end function showAllMarkers



/**
  * function to parse a XML time stamp to javascript date (basic version)
  *
  * @param xmlDate (yyyy-mm-ddThh:mm:ssZ)
  *
  * @return javascript date object 
  *
  */
function parseXmlTimeToDate(xmlDate){
	var date = new Date(xmlDate.substring(0,4),(xmlDate.substring(5,7))-1,xmlDate.substring(8,10),xmlDate.substring(11,13),xmlDate.substring(14,16));
	return date;
}//end function parseXmlTimeToDate

/**
  * function that calculates the difference in minutes between two dates
  *
  * @param date, the date of the object
  * @param compareDate, date used as reference
  *
  * @return the difference betwee the two dates in minutes
  */
function calculateTimeDeltaMinutes(date,compareDate){
	return Math.round((compareDate.getTime()-date.getTime())/(1000*60));
}//end function calculateTimeDelta


