// Google Maps Javascript
//var markers_list = new Array();
var markers_list = {};
var markers_list_infowindow = new Array();
var markers_list_doubles; //holds a list of marker id's pointing to already existing marker id's on same position
var timeoutID;
var mouseoverTime = 0;
var lastBusinessMouseOver;
var map; //object holds the Google Map
var mgr = null; //object holds Google Map API MarkerManager
var iconPosition;
var iconObject;
var currentPostion; // holds GLatLng object for the current position
var geocoder = new GClientGeocoder();
var controllarge = new GLargeMapControl()
var controlsmall = new GSmallZoomControl()

// Next: declare the variables that are returned by the server 
var markersListServer = new Array(); //holds the list of markers info as send by the server
var pointSW; //holds the most SW point of the first 10 markers
var pointNE; //holds the most NE point of the first 10 markers

// Using a class to emulate a dictionary
// see: http://4guysfromrolla.com/webtech/100800-1.shtml
function dictAdd() {
	for (c=0; c < dictAdd.arguments.length; c+=2) {
		this[dictAdd.arguments[c]] = dictAdd.arguments[c+1];
	}
}

function dict() {
	this.Add = dictAdd;
}
// ---END---

markers_list_doubles = new dict();

function showEntryOnMap(elementID, position, positionEntry) {
	if (GBrowserIsCompatible()) {
		el = document.getElementById(elementID);
		var map = new GMap2(el);
		map.setCenter(positionEntry, 13);
		map.addControl(controllarge);
		map.addControl(new GMapTypeControl());
		
		// Create our base object icon
		iconBase = new GIcon();
		iconBase.image = GM_GREEN;
		iconBase.shadow = GM_SHADOW;
		iconBase.iconSize = new GSize(16, 28);
		iconBase.shadowSize = new GSize(28, 28);
		iconBase.iconAnchor = new GPoint(8, 28);
		iconBase.infoWindowAnchor = new GPoint(8, 1);

		// Create our 'current position' marker icon
		iconPosition = new GIcon(iconBase);
		iconPosition.image = GM_LOCATION;
		iconPosition.shadow = '';
		iconPosition.iconSize = new GSize(30,30);
		iconPosition.iconAnchor = new GPoint(15,15);
		iconPosition.infoWindowAnchor = new GPoint(15, 15);

		// Add 'current position' to the map
		map.addOverlay(new GMarker(position, iconPosition));
		// Create our object icon
		iconObject = new GIcon();
		iconObject.image = GM_GREEN;
		iconObject.shadow = GM_SHADOW;
		iconObject.iconSize = new GSize(16, 28);
		iconObject.shadowSize = new GSize(28, 28);
		iconObject.iconAnchor = new GPoint(8, 28);
		iconObject.infoWindowAnchor = new GPoint(8, 1);
		// Add marker for blog entry position
		map.addOverlay(new GMarker(positionEntry, iconObject));
		return map
	}
}

function drawCurrentLocation(map, position) {
	// Create our 'current position' marker icon
	iconPosition = new GIcon(iconBase);
	iconPosition.image = GM_LOCATION;
	iconPosition.shadow = '';
	iconPosition.iconSize = new GSize(30.3,30.3);
	iconPosition.iconAnchor = new GPoint(15.1,15.1);
	iconPosition.infoWindowAnchor = new GPoint(15.1, 15.1);
	
	// Add 'current position' to the map
	//map.addOverlay(new GMarker(position, iconPosition)); //using addOverlay instead of addMarker causes added markers to possibly 'overwrite' the position marker. That is what we want. For now.
	marker = new GMarker(position, iconPosition);
        map.addOverlay(marker);
}

function drawMarker(map, position, iconlocation, infowindowhtml, openinfowindow) {
	// Draw a marker on the map:
	// iconlocation is typically an global variable set on the base template, ie: GM_YELLOW = "{{ STATIC_MEDIA_PREFIX }}graphics/wifidog/gm_yellow.png";
	// position is a GLatLng object
	// openinfowindow is a boolean
	iconPosition = new GIcon();
	iconPosition.image = iconlocation;
	iconPosition.shadow = GM_SHADOW;
	iconPosition.iconSize = new GSize(16, 28);
	iconPosition.shadowSize = new GSize(28, 28);
	iconPosition.iconAnchor = new GPoint(8, 28);
	iconPosition.infoWindowAnchor = new GPoint(8, 1);
	
	marker = new GMarker(position, iconPosition);
	marker.bindInfoWindowHtml(infowindowhtml);
        map.addOverlay(marker);
	if (openinfowindow) {
		marker.openInfoWindowHtml(infowindowhtml);
	}
}

function drawMap(elementID) {
	return drawMap2(elementID, controlsmall);
}

function drawMap2(elementID, zoomcontrol) {
	if (GBrowserIsCompatible()) {
		el = document.getElementById(elementID);
		map = new GMap2(el);
		map.addControl(zoomcontrol);
		map.addControl(new GMapTypeControl());
		
		// Create our base object icon
		iconBase = new GIcon();
		iconBase.image = GM_GREEN;
		iconBase.shadow = GM_SHADOW;
		iconBase.iconSize = new GSize(16, 28);
		iconBase.shadowSize = new GSize(28, 28);
		iconBase.iconAnchor = new GPoint(8, 28);
		iconBase.infoWindowAnchor = new GPoint(8, 1);
		
		return map;
	}
}

function showMap(elementID, position) {
	return showMap2(elementID, position, controlsmall);
}

function showMap2(elementID, position, zoomcontrol) {
    return showMap3(elementID, position, zoomcontrol, true)
}

function showMap3(elementID, position, zoomcontrol, show_current_position) {
	if (GBrowserIsCompatible()) {
		el = document.getElementById(elementID);
		map = new GMap2(el);
		map.setCenter(position, 13);
		map.addControl(zoomcontrol);
		map.addControl(new GMapTypeControl());
		mgr = new GMarkerManager(map);
		
		GEvent.addListener(map, "click", function(marker, point) {
			if (marker) {
				//marker.openInfoWindowHtml(marker.html);
				if (marker.id != null) {
					marker.openInfoWindowHtml(markers_list_infowindow[marker.id]);
				}
			}
			if (!marker) {
				//if user clicks on a map and not a marker, just close the current open InfoWindow
				map.closeInfoWindow();
			}
		});
	
		// Create our base object icon
		iconBase = new GIcon();
		iconBase.image = GM_GREEN;
		iconBase.shadow = GM_SHADOW;
		iconBase.iconSize = new GSize(16, 28);
		iconBase.shadowSize = new GSize(28, 28);
		iconBase.iconAnchor = new GPoint(8, 28);
		iconBase.infoWindowAnchor = new GPoint(8, 1);

		// Create our 'current position' marker icon
		iconPosition = new GIcon(iconBase);
		iconPosition.image = GM_LOCATION;
		iconPosition.shadow = '';
		iconPosition.iconSize = new GSize(30.3,30.3);
		iconPosition.iconAnchor = new GPoint(15.1,15.1);
		iconPosition.infoWindowAnchor = new GPoint(15.1, 15.1);
		
		if (show_current_position == true) {
            // Add 'current position' to the map
            //map.addOverlay(new GMarker(position, iconPosition)); //using addOverlay instead of addMarker causes added markers to possibly 'overwrite' the position marker. That is what we want. For now.
            mgr.addMarker(new GMarker(position, iconPosition), 0);
        }
		
		// Create our default object icon
		iconObject = new GIcon(iconBase);
		iconObject.image = GM_GREEN;
		// Create our object icon - GREEN
		iconObjectGreen = new GIcon(iconBase);
		iconObjectGreen.image = GM_GREEN;
		// Create our object icon - RED
		iconObjectRed = new GIcon(iconBase);
		iconObjectRed.image = GM_RED;
		// Create our object icon - BLUE
		iconObjectBlue = new GIcon(iconBase);
		iconObjectBlue.image = GM_BLUE;
		// Create our object icon - Yellow
		iconObjectYellow = new GIcon(iconBase);
		iconObjectYellow.image = GM_YELLOW;
		// Create our object icon - Purple
		iconObjectPurple = new GIcon(iconBase);
		iconObjectPurple.image = GM_PURPLE;
		// Create our object icon - Brown
		iconObjectBrown = new GIcon(iconBase);
		iconObjectBrown.image = GM_BROWN;
		// Create our object icon - Citron
		iconObjectCitron = new GIcon(iconBase);
		iconObjectCitron.image = GM_CITRON;
		
		return map
	}
}


function getTextIconObject(icontext, iconurl, iconwidth, iconheight) {
	// Create our object icon
	icon = new GIcon();
	icon.image = iconurl;
	icon.iconSize = new GSize(iconwidth, iconheight);
	icon.iconAnchor = new GPoint(iconwidth/2, iconheight);
	icon.infoWindowAnchor = new GPoint(iconwidth/2, iconheight/2);
	icon.shadow = GM_SHADOW;
	icon.shadowSize = new GSize(28, iconheight);
	return icon
}

// following function is here for backwards compatibility, please use getGLatLng instead
//function setCurrentPosition(gpsLat, gpsLon) {
//	var currentPosition = new GLatLng(gpsLat, gpsLon);
//	return currentPosition;
//}
function getGLatLng(gpsLat, gpsLon) {
	var currentPosition = new GLatLng(gpsLat, gpsLon);
	return currentPosition;
}

function recenterMap(position, pointSW, pointNE) {
	// 11  nov 2006: introduced a better way to find the correct 
	// zoom level. Even works if pointSW and pointNE are not really
	// pointSW and pointNE. See: http://mapki.com/wiki/APIv2
	var bounds = new GLatLngBounds;
	bounds.extend(pointSW);
	bounds.extend(pointNE);
	var level = map.getBoundsZoomLevel(bounds);
	map.setCenter(position, level);
}

function markerOnMap(id, markersList) {
	// Check if marker exists already in markersList
	function testID(element, index, array) {
		return (element.id == id)
	}
	return markersList.some(testID)
}

// Create a marker whose info window displays the given number.
function createMarker(map, markersList, id, list) {
	//document.write('ID:' + id.toString() + 'mlist:' + markersList);
	point = new GLatLng(list[0], list[1]);
	
	//if (!(markerOnMap(list[4], markersList))) {
	if (!(list[4] in markersList)) {
		classname = list[3]
		//markers_list_infowindow[list[4]] = '<div style="white-space:nowrap;"><br/>' + list[2] + '</div>';
		markers_list_infowindow[list[4]] = list[2];
		var foundDoubles = 0;
		/*
		for (var i=0; i < markersList.length && foundDoubles == 0; i++) {
			if (markersList[i].getPoint().lat() == point.lat() && markersList[i].getPoint().lng() == point.lng()) {
				markers_list_doubles.Add(id, i);
				foundDoubles = 1;
				//document.write('found double');
			}
		}
		*/
		// 20060711: Creation of textmarker temporarely disabled due to a bug in IE that causes IE to freeze on fetching the textmarkers.
		//if (list[3] != null) {
		//	// we now have icon text info so create text marker
		//	iconObject = getTextIconObject(list[3], list[4], list[5], list[6]);
		//}
		if (foundDoubles == 0) {
			//document.write('add m');
			if (classname == 'Business') {
				var marker = new GMarker(point, iconObjectGreen);
			}else if (classname == 'Entry') {
				var marker = new GMarker(point, iconObjectBrown);
			}else if (classname == 'MisdaadKaart') {
				var marker = new GMarker(point, iconObjectBlue);
			}else if (classname == 'CrimeReport') {
				var marker = new GMarker(point, iconObjectBlue);
			}else if (classname == 'GasStation') {
				var marker = new GMarker(point, iconObjectYellow);
			}else if (classname == 'Postcode6Price') {
				var marker = new GMarker(point, iconObjectRed);
			}else if (classname == 'Postcode6StreetPrice') {
				var marker = new GMarker(point, iconObjectRed);
			}else if (classname == 'Cam') {
				var marker = new GMarker(point, iconObjectPurple);
			}else if (classname == 'MissingAnimal') {
				var marker = new GMarker(point, iconObjectCitron);
			}else if (classname == 'UserProfile') {
				var marker = new GMarker(point, iconObjectYellow);
			}else if (classname == 'Event') {
				var marker = new GMarker(point, iconObjectYellow);
			}else if (classname == 'Discussion') {
				var marker = new GMarker(point, iconObjectYellow);
			} else {
				var marker = new GMarker(point, iconObject);
			}
			marker.id = list[4];
			markersList[list[4]] = marker;
			//markersList.push(marker);
			
			//map.addOverlay(markersList[id]);
			//mgr.addMarker(markersList[id], 0);
		}
		return marker;
	} else {
		return false;
	}
}

function createMarkerOBSOLETE(map, markersList, id, list) {
	point = new GLatLng(list[0], list[1]);
	markers_list_infowindow[id] = '<div style="white-space:nowrap;"><br/>' + list[2] + '</div>';
	if (list[3] != null) {
		// we now have icon text info so create text marker
		iconObject = getTextIconObject(list[3], list[4], list[5], list[6]);
	}
	var marker = new GMarker(point, iconObject);
	marker.id = id;
	markersList[id] = marker;
	map.addOverlay(markersList[id]);
}

// This function is called by a mouseover on the list of businesses and opens the corresponding info window on the map
function showInfoWindow(i) {
	//to accommodate for overview which contains blocks of 10 links
	//i can be just a number or could be a sum: 10+i where i is a number

	if ((i).toString().indexOf("+") != -1) {
		id = eval(i);
	} else {
		id = i;
	}
	timeout = 500; //in milliseconds
	clearTimeout(timeoutID);
	lastBusinessMouseOver = id;
	//alert(lastBusinessMouseOver);
	timeoutID = setTimeout("doShowInfoWindow()", timeout);
}

function doShowInfoWindow() {
	GEvent.trigger(markers_list[lastBusinessMouseOver], 'click');
}

function getDataFromServer(url, zoom) {
	// This generic function fetches JSON data from a url
	// evaluates the data received and
	// then calls the function handleDataFromServer
	GDownloadUrl(url, function(responseText, status) {
		if (status == 200) {
			eval(responseText); // returned are the variables: markersListServer, pointSW and pointNE and pointCenter
			//alert(markersListServer);
			handleDataFromServer(zoom);
		}
	});
}

function getViewportDataFromServer(url) {
	// This generic function fetches JSON data from a url
	// evaluates the data received and
	// then calls the function handleDataFromServer
	GDownloadUrl(url, function(responseText, status) {
		if (status == 200) {
			eval(responseText); // returned are the variables: markersListServer
			//alert(markersListServer);
			handleViewportDataFromServer();
		}
	});
}

function handleDataFromServer(zoom) {
	if (typeof zoom == 'undefined') {
		zoom = true;
	}
	// Put the markers on the map and
	// recenter and rezoom map after receiving the data from the server!
	setMarkersOnMap(map, markers_list, markersListServer);
	//markersListServer.length = 0; // list can be emptied now
	if (zoom) {
		recenterMap(pointCenter, pointSW, pointNE);
	}
}

function handleViewportDataFromServer() {
	// Put the markers on the map and
	setMarkersOnViewPort(map, markers_list, markersListServer);
	//markersListServer.length = 0; // list can be emptied now
}

function removeMarkersFromMap(map, markersList) {
	// close any open infowindows
	iw = map.getInfoWindow();
	iw.hide();
	// remove existing markers from map
	for (var i=0; i < markersList.length; i++) {
		map.removeOverlay(markersList[i]);
	}
	// clear Arrays
	markers_list.length = 0;
	markers_list_infowindow.length = 0;
}

function clearMarkers(map, mgr, markers_list) {
	map.clearOverlays();
	markers_list = {};
	mgr = new GMarkerManager(map);
	mgr.refresh();
}

function setMarkersOnMap(map, markersList, markersListFromServer) {
	//removeMarkersFromMap(map, markersList);
	for (var i = 0; i < markersListFromServer.length; i++) {
		var cur = markersListFromServer[i];
		//createMarker(map, markersList, i, cur);
		m = createMarker(map, markersList, i, cur);
		if (m != false) {
			mgr.addMarker(m,0);
		}
	}
	//mgr.addMarkers(markersList, 0);
	//mgr.refresh();
	/*
	for (var i in markers_list_doubles) {
		document.write(i+'=' + markers_list_doubles[i] + '|');
	}
	*/
}

function setMarkersOnViewPort(map, markersList, markersListFromServer) {
	//removeMarkersFromMap(map, markersList);
	for (var i = 0; i < markersListFromServer.length; i++) {
		var cur = markersListFromServer[i];
		m = createMarker(map, markersList, i, cur);
		//map.addOverlay(m);
		if (m != false) {
			mgr.addMarker(m,0);
		}
	}
	/*
	for (var i in markers_list_doubles) {
		document.write(i+'=' + markers_list_doubles[i] + '|');
	}
	*/
}

/* =================================*/
/* Directions                                                           */
/* =================================*/

function showDirections(map, arrayOfWaypoints) {
	// this function show the directions between
	// an array of waypoints (GLatLng). It only 
	// show the router. No Google start or end icons and
	// no Google infowindow.
	gdr = new GDirections();
	GEvent.addListener(gdr, "load", handleDirectionsLoad);
	gdr.loadFromWaypoints(arrayOfWaypoints,{getPolyline:true});

        function handleDirectionsLoad()
        {
		map.addOverlay(gdr.getPolyline());
		if (document.getElementById('directions_distance')) {
			document.getElementById('directions_distance').innerHTML = gdr.getDistance().html;
			document.getElementById('directions_duration').innerHTML = gdr.getDuration().html;
			document.getElementById('directions').style.display = 'inline';
		}
        } 
}

/* =================================*/
/* The beginning of a client site geocoding function */
/* =================================*/

//function setGeoPoint(point) {
	//This function is merely here as a placeholder
	//Please implement this function in the pages code.
//}

//function showAddressErrorMessage(message) {
	//This function is merely here as a placeholder
	//Please implement this function in the pages code.
//}

function showAddress(map, address) {
	geocoder.getLatLng(
		address,
		function(point) {
			if (!point) {
				alert(address + " not found");
			} else {
				map.setCenter(point, 13);
				var marker = new GMarker(point);
				map.addOverlay(marker);
				marker.openInfoWindowHtml(address);
				setGeoPoint(point);
			}
		}
	);
}

function htmlifyaddress(address) {
	return address.replace(/, /g, '<br/>'); //add g for global replace
}

function addAddressToMap(response) {
      //map.clearOverlays();
      if (!response || response.Status.code != 200) {
        showAddressErrorMessage("NORESPONSE");
      } else {
        place = response.Placemark[0];
        point = new GLatLng(place.Point.coordinates[1],
                            place.Point.coordinates[0]);
        setGeoPoint(point);
        
        // Create our object icon - GREEN
		var iconObjectGreen = new GIcon(iconBase);
		iconObjectGreen.image = GM_GREEN;
        // Create draggable green marker
        var marker = new GMarker(point, {icon:iconObjectGreen, draggable: true});
        
        GEvent.addListener(marker, "dragstart", function() {
          map.closeInfoWindow();
        });
        GEvent.addListener(marker, "dragend", function() {
            drag_marker_update_location(marker); // function needs to be defined in HTML page script for example
        });
        map.addOverlay(marker);
	var accuracy = place.AddressDetails.Accuracy;
	if (accuracy == 6) {
		accuracytext = ', Accuracy: ' + accuracy + ' (good)';
	}else if (accuracy == 8) {
		accuracytext = ', Accuracy: ' + accuracy + ' (best)';
	} else {
		accuracytext = ', Accuracy: ' + accuracy + ' (provide more information)';
	}
        marker.openInfoWindowHtml(htmlifyaddress(place.address + accuracytext));
      }
    }

function showLocation(address) {
	geocoder.getLocations(address, addAddressToMap);
}

function toggleHeight(map, position, buttonTextArray, zoomlevel, small, large) {
	//buttonTextArray holds values for the button when small, first value
	//and for when the map is enlarged, second value.

	map.savePosition()
	if ($('#map').css('height') == small) {
		//$('#map').css('height', large);
		$('#map').animate({'height': large}, 400, 'swing', function() {
			map.checkResize();
			map.returnToSavedPosition();
			$('#enlarge a').html(buttonTextArray[1]);
		});
	} else {
		//$('#map').css('height', small);
		$('#map').animate({'height': small}, 400, 'swing', function() {
			map.checkResize();
			if (position) {
				map.setCenter(position, zoomlevel);
			} else {
				map.returnToSavedPosition();
			};
			$('#enlarge a').html(buttonTextArray[0]);
		});
	}
	
}