/**
 * Cofee House Locator
 * Locates 10 nearest coffee houses
 * the google maps v2 api.
 * @author: Chris Reeves <chris@chris-reeves.com> for Poke London
 */

var localSearch = new GlocalSearch();																		// Load Googles Ajax Search API
google.load("maps", "2");																								// Load Google Maps (API v2x)

$(document).ready(function(){																						// On Document Ready
	
	var myPostcodeMarker = null;																					// Uses Postcide Marger Objects
	var poMarkers = Array();																							// Stores the Post Office Objects
	var poMarkersDistances = Array();																			// Stores Post Office Markers
	
	$("#form").hide();																										// Hide the Form
	$("#loading").show();																									// Show the loading bar
	$("#jsoff").hide();																										// Remove this and tbe <p> tag in the index page with the same to enable the JS version

	// Initialise map
	var map = new GMap2(document.getElementById('map'));									// Use the V2 API (new API v3 just released by google)
	map.addControl(new GLargeMapControl());																// Add the zome control
	map.addControl(new GMapTypeControl());																// Add the map type control (terain, map, hybrid)
	//map.enableScrollWheelZoom();																					// Enables mouse zoom scrolling on the map
	var location = new GLatLng(51.516007,-0.10643); 											// UK Lat, Lng
	
	map.setCenter(location, 10);																						// Set the map to center and default zoom level to 5
	var bounds = map.getBounds();																					// Define Map Bounds
	
	// Custom Icon
	var baseIcon = new GIcon(G_DEFAULT_ICON);															// Create a new icon for PO icons
	baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";			// Default shadow
	baseIcon.iconSize = new GSize(20, 34);																// Icon Size
	baseIcon.shadowSize = new GSize(37, 34);															// Shadow Size
	baseIcon.iconAnchor = new GPoint(9, 34);															// Icon Anchor
	baseIcon.infoWindowAnchor = new GPoint(9, 2);													// Info window anchor
	
	// thumbs icon
	var thumbIcon = new GIcon();
	thumbIcon.iconSize = new GSize(58, 64);																// Icon Size
	thumbIcon.iconAnchor = new GPoint(58, 64);														// Icon Anchor
	thumbIcon.infoWindowAnchor = new GPoint(29, 63);
	
	/** 
	 * Load XML Document of branches, loop through and populate map with them
	 */
	$.get('coffee_shops.php', {}, function(xml) {
		var total = $('shop', xml).length;																// Get the total number of branches
		var count = 1;																											// Set counter
		$("#branchCount").html(total);																			// Set the branch count tot total
		getBranch();																												// Run getBranch func
		function getBranch(){
			if(count<=total){																									// if count is less than or equal to total
				window.setTimeout(function() {getBranch();}, 1);								// Create a timeout for IE so it dosn't crash (1ms)
				var branch = $($('shop', xml).get((count-1)));									// Get the branch xml
				processBranch(branch, count, total);														// Call process Branch func parsing the branch JQ
				count++;																												// Increment count
			
			}
		}
	});
	
	/**
	 * Process a branch from the XML document
	 * @param jquery object of the branch
	 * @param int current counter position
	 * @prarm int total branches
	*/
	function processBranch(branch, count, total) {
		var latlng = branch.find('latlong').text().split(',');							// Get the lat and lng from string (lat,lng)
		poMarkers[poMarkers.length] = {																			// Create new array object (poMarkeers[4].branch_name etc)
			branch_name: branch.find('name').text(),
			address: branch.find('address').text(),
			postcode: branch.find('postcode').text(),
			lat: branch.find('lat').text(),
			lng: branch.find('lng').text(),
			up: branch.find('thumbsup').text(),
			dw: branch.find('thumbsdw').text(),
			html: "<b>"+branch.find('name').text()+"</b>"+
				"<br /><span class=\"red\">Distance: {distance} miles</span>"+
				"<br /><br /><b>Address</b><br />"+branch.find('address').text()
		};
		var percent = Math.round((count / total) * 100);										// Calculate percent
		$('#loading').find('hr').attr('width', percent+"%");								// Update laoding HR width
		$("#percent").html(percent);																				// Set the percentage
		$("#currentCount").html(count);																			// Set current count
		if(count == total) {																								// If count == total
			$("#loading").hide();																							// Hide Loader
			$("#form").show();																								// Show Form
			//$("#mapwrapper").show();
			//$("#map").show();
		}
	}
	
	/**
	 * On postcode submit, search for the postcode
	 * place marker and pan to location
	 */
	$("#postcodeForm").submit(function() {
		var postcodePoint = '';
		var postcode = $(this).find('#postcode').val();											// Get the Postcode
		
		
		if(postcode == "") {																								// If post code is empty alert user to error
			$("#Messages").slideDown();
			$("#Messages").find("h2").text("Error");
			$("#Messages").find("ul").html("<li>Please enter a postcode</li>");
		} else {
			$("#Messages").slideUp();
			usePointFromPostcode(postcode, function(point) {									// Get the users postcode 
				map.clearOverlays();																						// Clear all current overlays
				postcodePoint = point;																					// set the users current postcode to point
				var marker = new GMarker(point);																// Create a new marker for the users postcode
				myPostcodeMarker = marker;																			// Set the myPostcodeMarker to users postcode
				map.addOverlay(marker);																					// Add the user psotcode marker overlay
				map.panTo(marker.getLatLng());																	// Pan the map to the users postcode
				map.setCenter(point, 14);																				// Center the map and zoom to 14
				bounds.extend(marker.getPoint());																// Exntend the map bounds
				getNearest(postcodePoint);																			// Get the nearest postcodes
				$("#mapwrapper").show();																				// Show the map
				$(".key").show();																								// Show Key
				$("#map").slideDown(function() {																// Slide the map down
					map.checkResize();																						// Re initialise the map
					map.setCenter(point, 14);																			// Re center the map
				});
			});
		}
		return false;																												// Prevent the form submiting
	});
	
	/**
	 * Creates Post Office Market
	 * @param point GLatLng object
	 */
	function createMarker(point, i) {
		var poIcon = new GIcon(thumbIcon);																																	// Create a new custom Icon
		poIcon.image = poMarkers[i].up > poMarkers[i].dw ? "assets/images/thumbup.gif" : "assets/images/thumbdw.gif";								// Set image source
		var markerOptions = { icon:poIcon };																															// Create new marker options object
		var marker = new GMarker(point, markerOptions);																										// Create new marker using custom icon
		GEvent.addListener(marker, "click", function() {																									// On Click of the marker
			if(myPostcodeMarker) {																																					// If myPostcodeMarker is set
				var latlng = new GLatLng(poMarkers[i].lat, poMarkers[i].lng);																	// Get the lat and lng of the marker
				var meters = Math.round(latlng.distanceFrom(myPostcodeMarker.getPoint()));										// Use googles distance from function and round the number
				marker.openInfoWindowHtml(poMarkers[i].html.replace('{distance}', calculateMiles(meters)));		// Open new info window replacing branch.html {distance} with the current distance in miles
			} else {
				marker.openInfoWindowHtml("Enter a postcode to see how far this branch is from you.");				// If no marker something went wrong
			}
		});
		return marker;
	}
	
	/**
	 * Get the nearest post offices from the users current location
	 * @param Glatlng object of users current postcode
	 */	
	function getNearest(point) {
		poMarkersDistances = Array();																				// Declare arrat for holding branch distances
		$.each(poMarkers ,function(i) {																			// For each branch
			var latlng = new GLatLng(poMarkers[i].lat, poMarkers[i].lng);			// Get a new latlng point
			var meters = Math.round(latlng.distanceFrom(point));
					
			poMarkersDistances.push({																					// Push the distance into an array of objects
				distance: calculateMiles(meters),																// Set distance
				index: i																												// Set index
			});
		});
		poMarkersDistances.sort(function(aObject, bObject) {								// Sort the array by distance
			if(aObject.distance > bObject.distance) {
				return 1;
			} else if(aObject.distance < bObject.distance) {
				return -1;
			}
			return 0;
		});
		var nearest = poMarkersDistances.slice(0, 10);											// Get the 10 nearest only by sliceing the array
		$("#list").empty();																									// Empty the ul
		var distances = Array();																						// Declare a distances array
		$.each(nearest, function(i) {																				// Foreach nearest branches
			distances[i] = poMarkersDistances[i].distance;
			$('<li></li>').html($('<a></a>').attr('href', '#').click(function() {		// Creat list item with A tag and assign click event
				map.panTo(point);																											// Pan to the pount
				map.openInfoWindowHtml(point, poMarkers[poMarkersDistances[i].index].html.replace('{distance}', distances[i])); // Open map info window with distance in miles
				return false;																													// Prevent link for going anywhere
			}).html(poMarkers[poMarkersDistances[i].index].branch_name))
			.append($('<p></p>').html('Distance: '+distances[i]+' miles'))					// Add distance after link
			.appendTo('#list');																											// Append to the list
			var point = new GLatLng(poMarkers[poMarkersDistances[i].index].lat, poMarkers[poMarkersDistances[i].index].lng); // Get point by branch lat and lng
			map.addOverlay(createMarker(point, poMarkersDistances[i].index));			// Add the overlay
		});	
		$('#listWrapper').hide();
	}

	/**
	 * Postcode Search function
	 * @param string postcode
	 * @param function callback
	 */
	function usePointFromPostcode(postcode, callbackFunction) {
		localSearch.setSearchCompleteCallback(null,												// Perform search on post code
			function() {																										// callback function
				if (localSearch.results[0]) {    															// if there is a result
					var resultLat = localSearch.results[0].lat;									// Get the Latitude
					var resultLng = localSearch.results[0].lng;									// Get the longitude
					var point = new GLatLng(resultLat,resultLng);								// Crreate new point
					callbackFunction(point);
					
					// Parse point to call back function
				}else{
					$("#Messages").slideDown();
					$("#Messages").find("h2").text("Error");
					$("#Messages").find("ul").html("<li>Postcode not found!</li>");															// Alet psotcode not found
				}
			});  
		localSearch.execute(postcode + ", UK");														// Execute the search
	}
	
	/**
	 * Convert meters into miles and return miles
	 * @param float meters
	 */
	function calculateMiles(meters) {
		var meterMile = 0.000621371;																			// Number of miles in 1 meter
		var miles = meterMile * meters;																		// Calculate miles
		miles = Math.round(miles*1000)/1000;
		return miles;
	}
	
});