﻿// JavaScript Document

// defines the map container
var map = null;
var map2 = null;

// This determines how far the map will pan when the North, South, East, or West buttons are pressed.
// It will scroll the screen by the percentage below * the current screen width or height.
var panPercentage = 0.5;

// This holds all of the points to be included in the default view.  Google Maps can automatically
// adjust the default view to include all of the points in this variable.
var mapBounds;


////////////////////////////
//
// zoomIn()
//
// This zooms the map in by 1 level
// It retrieves the current zoom level and subtracts 1 from it.
// maximum zoom level is 17; minimum zoom level is 0
//
////////////////////////////

function zoomIn() {
	map.setZoom(map.getZoom() + 1);
}
function zoomIn2() {
	map2.setZoom(map2.getZoom() + 1);
}


//////////////////////////////
//
// zoomOut()
//
// This zooms the map out by 1 level
// It retrieves the current zoom level and adds 1 to it.
// maximum zoom level is 17; minimum zoom level is 0
//
////////////////////////////

function zoomOut() {
	map.setZoom(map.getZoom() - 1);
}
function zoomOut2() {
	map2.setZoom(map2.getZoom() - 1);
}

/////////////////////////////
//
// setMapType()
//
// This sets the display type of the map.  The default map formats for standard Google Map are:
// G_NORMAL_MAP
// G_SATELLITE_MAP
// G_HYBRID_MAP
// One of these values needs to be passed into this function to set the map type.
// Custom map types can be created and called through the Google Maps API.
//
////////////////////////////

function setMapType(mapType) {
	map.setMapType(mapType);
}

///////////////////////////
//
// aroundTheWorldLngSpan()
//
// This function adjusts calculation of the visible longitudinal span when the view crosses the 
// +/-180 degree line.  It insures that the width of the view (in degrees) is calculated correctly.
// NE = the North-East corner of the span.
// SW = the South-West corner of the span.
//
////////////////////////////

function aroundTheWorldLngSpan(NE,SW) {
	if (SW > NE) {
		NE = NE + 360;			
	}
	return Math.abs(NE - SW);
}	

////////////////////////////
//
// aroundTheWorldLngPan()
//
// This function adjusts the calculation for the new view point when panning East or West across
// the +/-180 degree line.  It insures the map will pan correctly across this boundary.
//
////////////////////////////

function aroundTheWorldLngPan(lng) {
	if (lng < -180) {
		lng = lng + 360;			
	}
	else if (lng > 180) {
		lng = lng - 360;
	}
	return lng;
}	

////////////////////////////
//
// limitNS(lat)
//
// This ensures that the map does not scroll beyond +/- 85 degrees latitudinally.
// Using  +/- 90 degrees as a limit creates a problem.  The spherical coordinates
// become so flattened out at the extreme norhtern and southern boundaries
// it takes a lof of N-S movement to change 1 degree.  (At least this what I'm assuming
// the problem is.)
//
////////////////////////////

function limitNS(lat) {
	if (lat > 85) {
		lat = 85;
	}
	else if (lat < -85) {
		lat = -85;
	}
	return lat;
}

//////////////////////
//
// lngSpan()
//
// This calculates the latitudinal span of the current view.
// It takes into account calculating across the +/- 180 degree line.
//
////////////////////////////

function lngSpan() {
	var bounds = map.getBounds(); // the boundary coordinates for the current view
	var southWest = bounds.getSouthWest(); // the South-West corner of the boundary
	var northEast = bounds.getNorthEast(); // the North-East corner of the boundary
	return aroundTheWorldLngSpan(northEast.lng(), southWest.lng());
}

/////////////////////
//
// latSpan()
//
// This calculates the latitudinal span of the current view.
//
////////////////////////////

function latSpan() {
	var bounds = map.getBounds(); // the boundary coordinates for the current view
	var southWest = bounds.getSouthWest(); // the South-West corner of the boundary
	var northEast = bounds.getNorthEast(); // the North-East corner of the boundary
	return Math.abs(northEast.lat() - southWest.lat());		
}
	
///////////////////////
//
// panWest()
//
// This function will pan the map West by a set % of the current visible width.
// The percentage is set in the variable panPercentage.
// It takes the current visible longitudinal span, multiplies it by panPercentage, and pans the map to the new longitudinal location
// The pan will be smooth if the new location is in the current view.
//
// NOTE: When the map is zoomed nearly all the way out, the panWest() will actually appear to move East.
// This is presumable because when Google Maps receives the new coordinates for the center,
// It is actually shorter to pan to the East rather than to the West, even though the coordinates
// given are to the West.
//
////////////////////////////

function panWest () {
	map.panTo(new GLatLng(map.getCenter().lat(), aroundTheWorldLngPan(map.getCenter().lng() - (lngSpan() * panPercentage))));
}
function panWest2 () {
	map2.panTo(new GLatLng(map2.getCenter().lat(), aroundTheWorldLngPan(map2.getCenter().lng() - (lngSpan() * panPercentage))));
}

/////////////////////////
//
// panEast()
//
// This function will pan the map East by a set % of the current visible width.
// The percentage is set in the variable panPercentage.
// It takes the current visible longitudinal span, multiplies it by panPercentage, and pans the map to the new longitudinal location
// The pan will be smooth if the new location is in the current view.
//
////////////////////////////

function panEast () {
	map.panTo(new GLatLng(map.getCenter().lat(), aroundTheWorldLngPan(map.getCenter().lng() + (lngSpan() * panPercentage))));
}
function panEast2 () {
	map2.panTo(new GLatLng(map2.getCenter().lat(), aroundTheWorldLngPan(map2.getCenter().lng() + (lngSpan() * panPercentage))));
}

////////////////////////////////
//
// panNorth()
//
// This function will pan the map North by a set % of the current visible width.
// The percentage is set in the variable panPercentage.
// It takes the current visible latitudinal span, multiplies it by panPercentage, and pans the map to the new latitudinal location
// The pan will be smooth if the new location is in the current view.
//
////////////////////////////

function panNorth () {
	map.panTo(new GLatLng(limitNS(map.getCenter().lat() + (latSpan() * panPercentage)), map.getCenter().lng()));
}
function panNorth2 () {
	map2.panTo(new GLatLng(limitNS(map2.getCenter().lat() + (latSpan() * panPercentage)), map2.getCenter().lng()));
}

//////////////////////////////////
//
// panSouth()
//
// This function will pan the map South by a set % of the current visible width.
// The percentage is set in the variable panPercentage.
// It takes the current visible latitudinal span, multiplies it by panPercentage, and pans the map to the new latitudinal location
// The pan will be smooth if the new location is in the current view.
//
////////////////////////////

function panSouth () {
	map.panTo(new GLatLng(limitNS(map.getCenter().lat() - (latSpan() * panPercentage)), map.getCenter().lng()));
}
function panSouth2 () {
	map2.panTo(new GLatLng(limitNS(map2.getCenter().lat() - (latSpan() * panPercentage)), map2.getCenter().lng()));
}

/////////////////////////////////
//
// createMarker(baseIcon, point, index)
//
// This creates a pushpin based on the baseIcon.  The index defines what number
// will appear on the pushpin.  The images for the pushpins with the numbers on them
// must be created in advance.
//
/////////////////////////////////

function createMarker(baseIcon, point, pinLabel, infoWindow, printFriendly) {

	// Can define your own icon but I'm going to use the Google standard ones
	//var icon = new GIcon(baseIcon);
	//icon.image = "/common/images/icons/map_pushpin.png";
	//var marker = new GMarker(point, icon);
	var marker = new GMarker(point);
		
	// Show info bubble if marker is clicked (non-print pages only)
	if ( !printFriendly ) {		
		GEvent.addListener(marker, "click", function() {
			marker.openInfoWindowHtml("<b>" + infoWindow + "</b>");
		});
	}	
	
	return marker;
}


//////////////////////////////
//
// defineCustomPushPin()
//
// This creates a base icon for all of our markers that specifies the
// image to use, the dimensions of the image, and where to position the 
// message box.
//
//////////////////////////////

function defineCustomPushPin() {

	var baseIcon = new GIcon();
	baseIcon.iconSize = new GSize(34, 59);
	baseIcon.iconAnchor = new GPoint(17, 59);
//	baseIcon.shadow = "/common/images/icons/shadow.png";
	baseIcon.shadowSize = new GSize(65, 59);
	baseIcon.infoWindowAnchor = new GPoint(17, 0);
	baseIcon.infoShadowAnchor = new GPoint(17, 0);
	return baseIcon;
}


///////////////////////////////
//
// adjustView()
//
// This will adjust the view of the map to include all of the points in the bounds variable.
//
///////////////////////////////

function adjustView () {
	map.setZoom(map.getBoundsZoomLevel(mapBounds));
	var clat = (mapBounds.getNorthEast().lat() + mapBounds.getSouthWest().lat()) /2;
	var clng = (mapBounds.getNorthEast().lng() + mapBounds.getSouthWest().lng()) /2;
	map.setCenter(new GLatLng(clat,clng));
}

function adjustViewDefaultZoom () {
	map.setZoom(12);
	var clat = (mapBounds.getNorthEast().lat() + mapBounds.getSouthWest().lat()) /2;
	var clng = (mapBounds.getNorthEast().lng() + mapBounds.getSouthWest().lng()) /2;
	map.setCenter(new GLatLng(clat,clng));
}

///////////////////////////////
//
// showAddress(address, mapPointLabel, customPushPin, infoWindow)
//
// This translates a street address into a set of longitude and latitude points.  It then
// plots that point on the map.
//
// Currently it calls adjustView() after each point is plotted.  This seems to be a lot of overhead
// and I think I ought to be able to call it once after all the points have been mapped.  When I 
// do that though it doesn't work.  I'm not sure why yet.
//
///////////////////////////////

function showAddress(address, mapPointLabel, customPushPin, infoWindow, adjustNow, printFriendly) {

	geocoder = new GClientGeocoder();
	
	geocoder.getLatLng(
	address,
	function(point) {
	  if (!point) {
	    alert(address + " not found");
	
	  } else {
	    var marker = new GMarker(point);
	
		map.addOverlay(createMarker(customPushPin, point, mapPointLabel, infoWindow, printFriendly));
		
		if ( printFriendly ) {
			map2.addOverlay(createMarker(customPushPin, point, mapPointLabel, infoWindow, printFriendly));	
		}
		
		// adds the point to the set of points that need to be made visible in the current view
		mapBounds.extend(point);
	
		// adjusts the view to include all the points that are supposed to be visible
		if ( adjustNow ){
			adjustView();	
		}	
	  }
	}
	);

}

function showAddressByPoint(point, mapPointLabel, customPushPin, infoWindow, adjustNow, printFriendly) {

        var marker = new GMarker(point);

		map.addOverlay(createMarker(customPushPin, point, mapPointLabel, infoWindow, printFriendly));
	
		if ( printFriendly ) {
			map2.addOverlay(createMarker(customPushPin, point, mapPointLabel, infoWindow, printFriendly));	
		}
		
		// adds the point to the set of points that need to be made visible in the current view
		mapBounds.extend(point);

		// adjusts the view to include all the points that are supposed to be visible
		if ( adjustNow ){
			adjustViewDefaultZoom();	
		}		
}

//////////////////////////////
//
// parseDOMforMapDataAndPlot()
//
///////////////////////////////

function parseDOMforMapDataAndPlot(customPushPin, printFriendly) {

		var	mapPointLatitude = null; // holds the latitude from the DOM parsing
		var mapPointLongitude = null; // holds the longitude from the DOM parsing
		var mapPointAddr = null; // holds the address from the DOM parsing
		
		// keeps count of how many map points there are so the correct custom pushpin gets used
		var mapPointsCount = 0;
		//var mapPointsTotalCount = 0;
		
		// find the mapLocations div tag		
		var mapPoints = document.getElementById("mapLocations");
		
		// Deterine whether to adjust view (only do it there is only 1)
		var adjustNow = false;

		// To ensure browser compatibility, use getElementsByTagName rather than childNodes				
		if ( mapPoints != null ){
			liNodes = mapPoints.getElementsByTagName("li");
			ulNodes = mapPoints.getElementsByTagName("ul");	
		}
		
		for (var i = 0; liNodes != null && i < liNodes.length; i++) {
			if (liNodes[i].className == "mapItem") {
				mapPointsCount ++;
			}
		}
		
		if ( mapPointsCount == 1){
			adjustNow = true;
		}		
		
		// Loop round the list of branches
		for (var i = 0; ulNodes != null && i < ulNodes.length; i++) {
			if (ulNodes[i].className == "mapItemData") {
				
				// extract the label for the pin
				mapPointLabel = ulNodes[i].getAttribute("branchname");
				
				liNodes2 = ulNodes[i].getElementsByTagName("li");		
							
				for (var j = 0; j < liNodes2.length; j++) {
					
					if (liNodes2[j].firstChild != null) {
						// extract the latitude
						if (liNodes2[j].className == "lat") {
							mapPointLatitude = liNodes2[j].firstChild.nodeValue;
							mapPointLabel += "<br /><br />GPS Latitude &nbsp;&nbsp; " + mapPointLatitude;
						}
						// extract the longitude
						else if (liNodes2[j].className == "lng") {
							mapPointLongitude = liNodes2[j].firstChild.nodeValue;
							mapPointLabel += "<br />GPS Longitude " + mapPointLongitude;
						}				
						// extract the address
						else if (liNodes2[j].className == "addr") {
							mapPointAddr = liNodes2[j].firstChild.nodeValue;
						}
						// extract the sub label
						else if (liNodes2[j].className == "subLabel") {
							mapPointLabel += "<br />" + liNodes2[j].firstChild.nodeValue;
						}
						// extract the URL
						else if (liNodes2[j].className == "labelLink") {
							mapPointLabel += "<br /><br />" + "<a href=\"" + liNodes2[j].firstChild.getAttribute("href") + "\">"+liNodes2[j].firstChild.firstChild.nodeValue+"</a>";
						}

					}
				}				

				// If available, use the latitude and longitude
				if (mapPointLatitude == null || mapPointLongitude == null) { 

					showAddress(mapPointAddr, mapPointsCount, customPushPin, mapPointLabel, adjustNow, printFriendly);				
				}
				// if no address is given, it assumes a longitude and latitude were in the DOM
				else {
					// add the point from a longitude and latitude
					var point = new GLatLng(mapPointLatitude, mapPointLongitude);
					showAddressByPoint(point, mapPointsCount, customPushPin, mapPointLabel, adjustNow, printFriendly);				
				}
				
				// reset the variables
				mapPointLatitude = null;
				mapPointLongitude = null;
				mapPointAddr = null;
				mapPointLabel = null;

			}			
		}     	
}

//////////////////////////////
//
// load()
//
////////////////////////////

function load(printFriendly) {
	
	if (GBrowserIsCompatible()) {
		// This creates an instance of the map and positions it at the
		// div tag id="map" within the body of the HTML.
		// The size of the map is defined by the boundary of the div tag.
		map = new GMap2(document.getElementById("map"));
		
		// adds the zoom and pan controls within the map
		map.addControl(new GLargeMapControl());

		if ( printFriendly ){
			// Create second map for printFriendly view
			map2 = new GMap2(document.getElementById("map2"));
			map2.addControl(new GLargeMapControl());
			map2.setCenter(new GLatLng(54.5,-2.5),5);
		} else{	
			// adds the "Normal", "Satellite", and "Hybrid" view buttons within the map
			map.addControl(new GMapTypeControl()); 
		}

		// This centers the map on 0,0 at the maximum zoom out level.
		// The coordinates are (latitude, longitude).
		// The zoom level is from 0 to 17, with 0 being zoomed out, and 17 being zoomed in.
		//map.setCenter(new GLatLng(0,0),0);
		// SXB - Center the map so UK is shown fully
		map.setCenter(new GLatLng(54.5,-2.5),5);
		mapBounds = new GLatLngBounds();

		// parse the DOM and plot the points using a custom pushpin
		parseDOMforMapDataAndPlot(defineCustomPushPin(), printFriendly)
		
		if ( printFriendly ){
			map.setCenter(map.getCenter(),16);	
			// Set 2nd printer friendly map to be at same place as 1st map with different zoom level
			map2.setCenter(map.getCenter(),13);	
		}
		
	}
}

