
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 * INITIALISE MAP DISPLAY
 * As a Google Map can only be drawn when the external API has been fully loaded, methods
 * which want to use the DrawGoogleMap functionality must call InitialiseMapDisplay with
 * their map's attributes - this is then added to the DeferredCall list which are
 * each called in turn when the window.onload event fires.
 *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
	
function InitialiseMapDisplay(attributes) {
	AddFunctionToDeferredCalls(function() { DrawGoogleMap(attributes); });
	}


/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 * DRAW GOOGLE MAP
 * Display the map, based on the passed attributes. If the array attributes.locations is not empty,
 * then a map needs to be plotted with those locations on it, and include the links on the map
 *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

function DrawGoogleMap(attributes) {

 	/*-----------------------------------------------------------------------------------------------------
	 * Determine the terrain type (default is ROADMAP)
	 *-----------------------------------------------------------------------------------------------------*/

	switch (attributes.mapType.toUpperCase()) {
		case "TERRAIN":
			googleMapType = google.maps.MapTypeId.TERRAIN;
			break;
		case "SATELLITE":
			googleMapType = google.maps.MapTypeId.SATELLITE;
			break;
		case "HYBRID":
			googleMapType = google.maps.MapTypeId.HYBRID;
			break;		
		case "ROADMAP":
		default:
			googleMapType = google.maps.MapTypeId.ROADMAP;
			break;
		}

 	/*-----------------------------------------------------------------------------------------------------
	 * Set the default mapping options
	 *-----------------------------------------------------------------------------------------------------*/
		
	var zoomLevel = (attributes.zoom != undefined) ? attributes.zoom : 12;
	var showPanControl = (attributes.panControl != undefined) ? attributes.panControl : false;
	var showZoomControl = (attributes.zoomControl != undefined) ? attributes.zoomControl : true;
	var showScaleControl = (attributes.scaleControl != undefined) ? attributes.scaleControl : false;
	var showStreetViewControl = (attributes.streetViewControl != undefined) ? attributes.streetViewControl : false;
	var showOverviewMapControl = (attributes.overviewMapControl != undefined) ? attributes.overviewMapControl : false;
	var showMapTypeControl = (attributes.mapTypeControl != undefined) ? attributes.mapTypeControl : true;
	var showInfoWindow = (attributes.showInfoWindow != undefined) ? attributes.showInfoWindow : false;
	var infoWindowTemplate = (attributes.infoWindowTemplate != undefined) ? attributes.infoWindowTemplate : "";
	var plotCircle = (attributes.plotCircle != undefined) ? attributes.plotCircle : false;
	var circleRadius = (attributes.circleRadius != undefined) ? attributes.circleRadius : 0;
	var strokeColor = (attributes.strokeColor != undefined) ? attributes.strokeColor : "#FF0000";
	var strokeOpacity = (attributes.strokeOpacity != undefined) ? attributes.strokeOpacity / 100 : 1;
	var strokeWidth = (attributes.strokeWidth != undefined) ? attributes.strokeWidth : 1;
	var fillColor = (attributes.fillColor != undefined) ? attributes.fillColor : "#FF0000";
	var fillOpacity = (attributes.fillOpacity != undefined) ? attributes.fillOpacity / 100 : 0.4;
	
	if (showInfoWindow) {
		var infoWindow = new google.maps.InfoWindow();
		}
		
 	/*-----------------------------------------------------------------------------------------------------
	 * Multiple locations to be displayed. Calculate the map scale to show all the locations, 
	 * draw the map and add markers.
	 *-----------------------------------------------------------------------------------------------------*/

	if (attributes.locations != undefined && attributes.locations.length > 0) {
		// There are a number of locations to display
		var latlng = new google.maps.LatLng(attributes.latitude, attributes.longitude);
		var myOptions = {	zoom: zoomLevel,
							center: latlng,
							mapTypeId: googleMapType,
							panControl: showPanControl, 
							zoomControl: showZoomControl,
							scaleControl: showScaleControl,
							mapTypeControl: showMapTypeControl,
							streetViewControl: showStreetViewControl,
							overviewMapControl: showOverviewMapControl
							};	

		var map = new google.maps.Map($(attributes.canvas), myOptions);
		for (var i = 0; i < attributes.locations.length; i++) { 
			var thisLocation = attributes.locations[i];
			var latlng = new google.maps.LatLng(thisLocation.latitude, thisLocation.longitude);
			var id = (thisLocation.id != undefined) ? thisLocation.id : 0;
			var marker = new google.maps.Marker({ position: latlng, map: map, title: thisLocation.title, itemID: id });
			if (showInfoWindow && infoWindowTemplate != "") {
				// Prototype to the rescue - 'burn' the current states of the parameters into the function call as the Maps API doesn't pass
				// any parameters apart from the coordinates of the marker clicked to the callback
				google.maps.event.addListener(marker, 'click', LoadInfoWindow.curry(map, marker, infoWindow, id, infoWindowTemplate) );
				}
			}
		}


 	/*-----------------------------------------------------------------------------------------------------
	 * Single location to display. Draw the map and add a marker as necessary.
	 *-----------------------------------------------------------------------------------------------------*/

	else {
		// There is a single location to display
		var latlng = new google.maps.LatLng(attributes.latitude, attributes.longitude);
		var myOptions = {	zoom: zoomLevel,
							center: latlng,
							mapTypeId: googleMapType,
							panControl: showPanControl, 
							zoomControl: showZoomControl,
							scaleControl: showScaleControl,
							mapTypeControl: showMapTypeControl,
							streetViewControl: showStreetViewControl,
							overviewMapControl: showOverviewMapControl
							};	
		var map = new google.maps.Map($(attributes.canvas), myOptions);
		if (attributes.usePin) {
			var marker = new google.maps.Marker({ position: latlng, map: map, title: attributes.pinTitle });
			}
		}
		
 	/*-----------------------------------------------------------------------------------------------------
	 * Draw the circle on the map as necessary
	 *-----------------------------------------------------------------------------------------------------*/
		
	if (plotCircle) {
		var circleOptions = {
			strokeColor: strokeColor,
			strokeOpacity: strokeOpacity,
			strokeWeight: strokeWidth,
			fillColor: fillColor,
			fillOpacity: fillOpacity,
			map: map,
			center: new google.maps.LatLng(attributes.latitude, attributes.longitude),
			radius: circleRadius
			};
		var circle = new google.maps.Circle(circleOptions);
	
		}
		
	}


function LoadInfoWindow(map, marker, infoWindow, id, infoWindowTemplate) {
	infoWindow.close(); // Close any currently open window
	infoWindow.setContent("");
	infoWindow.open(map, marker);
	var params = { cardID : id };
	new Ajax.Request("/index.php", {
		method: "post",
		parameters: params,
		requestHeaders: { Request: "fetch-card-by-id", templateType: infoWindowTemplate, outputType: "HTML" },
		onSuccess: function(response) { 
			var html = response.responseText; 
			infoWindow.setContent(html);
			}
		});
	}
	
	
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 * GOOGLE MAPS GEOCODING
 * Class which interacts with Google Maps to lookup latitude and longitude for a location
 *+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
		
var Geocoding = Class.create ( {

	ZOOM_LEVEL: 14,
	
 	/*-----------------------------------------------------------------------------------------------------
	 * INITIALIZE
	 * Initialise and display the map
	 *-----------------------------------------------------------------------------------------------------*/

	initialize: function(el, settings) {
		this.id = el;
		var obj = this;
		this.formName = (settings.formName != undefined) ? settings.formName : "";
		this.mapContainer = $(el + "-map");
		//this.mapContainer.setStyle({visibility: "visible"});
		this.currentLocation = this.GetLocation();
		this.zoomLevel = (this.currentLocation.lat() != 0 && this.currentLocation.lng() != 0) ? this.ZOOM_LEVEL : 1;
		
		var mapOptions = {
		  zoom: this.zoomLevel,
		  center: this.currentLocation,
		  mapTypeId: google.maps.MapTypeId.ROADMAP
		};
		
		// Generate the map based on the current location and other settings
		this.map = new google.maps.Map(this.mapContainer, mapOptions);
		this.map.setCenter(this.currentLocation);
		
		// Add a single marker to the map 
		this.marker = new google.maps.Marker({
              position: this.currentLocation,
              map: this.map
          });

		// Get a geocoder
        this.geocoder = new google.maps.Geocoder();  
         
        // Add an event listener for when the user clicks on the map - update the location of the marker
        google.maps.event.addListener(this.map, 'click', function(event) { obj.SetMarkerFromClick(event); });
    
    	// Set the 'View' and 'Geocode' buttons...
        var buttonsContainer = new Element("div", {'class': "form-buttons-container"});
        this.mapContainer.insert({after: buttonsContainer});
		this.viewButton = new Element('input', {type: "submit", value: "View", 'class': "form-map-buttons"});
		this.viewButton.observe("click", function(event) { obj.LookupLocation(); } );
		buttonsContainer.insert(this.viewButton);
		this.geocodeButton = new Element('input', {type: "submit", value: "Geocode", 'class': "form-map-buttons"});
		this.geocodeButton.observe("click", function(event) { obj.SetLocation(obj.currentLocation); } );
		buttonsContainer.insert(this.geocodeButton);
		
		// Set up the error message container
		this.errorMessage = new Element("div", {'class': "form-map-error-message"}).update("");
		buttonsContainer.insert(this.errorMessage);
		},

	/*-----------------------------------------------------------------------------------------------------
	 * LOOK UP LOCATION
	 * Use the Google Geocoder to look up the address that the user has entered
	 *-----------------------------------------------------------------------------------------------------*/

	LookupLocation: function() {
		var obj = this;
		var address = $(this.id).getValue().stripScripts().stripTags().trim();
		if (address != "") {
			this.geocoder.geocode({address: address}, function(results, status) {
				if (status == google.maps.GeocoderStatus.OK && results.length) {
					if (status != google.maps.GeocoderStatus.ZERO_RESULTS) {
						obj.errorMessage.update("");
						obj.currentLocation = results[0].geometry.location;
						obj.map.setCenter(obj.currentLocation);
						if (obj.map.getZoom() < 6) {
							obj.map.setZoom(obj.ZOOM_LEVEL);
							}
						console.log(obj.currentLocation);
						obj.marker.setPosition(obj.currentLocation);
						}
					}
				else {
					obj.errorMessage.update("Geocode was unsuccessful.");
					}
				});
			}
		},
	
	
	/*-----------------------------------------------------------------------------------------------------
	 * SET LOCATION
	 * Set the latitude and longitude fields using the current location data 
	 *-----------------------------------------------------------------------------------------------------*/

	SetLocation: function(location) {
		$(this.formName + ".Latitude").setValue(this.currentLocation.lat());
        $(this.formName + ".Longitude").setValue(this.currentLocation.lng());
		},


	/*-----------------------------------------------------------------------------------------------------
	 * GET LOCATION
	 * Get the location based on the latitude and longitude fields
	 *-----------------------------------------------------------------------------------------------------*/
		
	GetLocation: function() {
		var lat = $(this.formName + ".Latitude").getValue();
		var lng = $(this.formName + ".Longitude").getValue();
		return new google.maps.LatLng(lat, lng);
		},


	/*-----------------------------------------------------------------------------------------------------
	 * SET MARKER FROM CLICK
	 * The user has clicked on the map - set the marker's position and update the current location
	 * and the latitude and longitude fields
	 *-----------------------------------------------------------------------------------------------------*/
	
	SetMarkerFromClick: function(event) {
		if (event.latLng != undefined) {
			this.currentLocation = event.latLng;
			this.SetLocation();
			this.marker.setPosition(this.currentLocation);
			}
		},
		
	Terminate: function() {
		return;
		}
		
	});


