/**
HubOnline Map Search
version 1.0

namespace: jQuery.hubContactMap

functions:
 - init
 - pageData
 - populate
 - createMarker
 - focusListing
 - getData
 
private members:
 - Tooltip
 - HTMLControl
 
*/

;(function($){

	// Initialise hubContactMap Object
	$.hubContactMap = {};
	
	/**
		errorMessages:
		 - the global object for standard error messages
	*/
	$.hubContactMap.errorMessages = {
		en : {
			functionDoesNotExist : "hubContactMap Error 1: The function does not exist",
			addressNotFound: "This address cannot be found.  Please modify your search.",
			browserNotCompatible: "This browser is reported as being not compatible with Google Maps.",
			cannotLoad: "Cannot load the Google Maps API at this time.  Please check your connection.",
			invalidLatLng: "Invalid Latitude and Longitude entered for Google Map"
		}
	};
	
	/**
	defaultOptions:
	 - override by passing an anon object to the map constructor
	*/
	$.hubContactMap.defaultOptions = {
		// Initial type of map to display
		language: "en",
		// mapType options: "map", "sat", "hybrid"
		mapType: "map",
		// default map center is Australia
		mapCenter: [-25.274395,133.775136],
		mapDimensions: [600, 600],
		mapZoom: 3,
		toggleButton: 'toggleMap',
		// mapControlSize options: "large", "small"	
		mapControlSize: "large",		

		// GMap settings
		mapEnableType: true,
		mapEnableOverview: false,
		mapEnableDragging: true,
		mapEnableInfoWindows: true,
		mapEnableDoubleClickZoom: false,
		mapEnableScrollZoom: false,
		mapEnableSmoothZoom: false,
		mapEnableGoogleBar: false,
		mapEnableScaleControl: false,
		mapShowjMapIcon: true,

		// Map Search settings
		mapShowPaginationControl: true,
		mapShowResultControl: true,
		agentID: 2045,
		iconImagePath: '/img/gmaps/markers/',
		agentsFolderPath: 'http://media.hubonline.com.au/agents_folder/',
		resultsPerPage: 50,
		xslID: 2045,

		// Street View Defaults
		streetViewContainer: 'streetView',
		streetViewSuccess: true,
		
		// Office Details Defaults
		detailsContainer:'officeContactDetails',
		
		// Marker Cluster Icon
		markerIcon: [{
									height: 50,
									width: 58,
									url: '/img/gmaps/contactmap/cluster.png'
								}]
	};
	
	$.hubContactMap.init = function(el, options, callback) {
		var options = $.extend({}, $.hubContactMap.defaultOptions, options);
		var options = this.options = $.meta ? $.extend({}, options, $(this).data()) : options;
		
		// Remove all offices that don't have valid map data
		for(var i = 0; i < options.listings.length; i++) {
			if(options.listings[i].latitude === 0 || options.listings[i].longitude === 0 || options.listings[i].mapCenterLat === 0 || options.listings[i].mapCenterLng === 0 ) {
				options.listings.splice(i, 1);
			}
		}
		
		// We do this to reduce overhead from making multiple $(el) calls
		var GMSelector = $(el);
		
		this.mapElement = el;
		this.listings = options.listings;
					
		// TODO
		// check for any other instances of the map and bail, or at least until there's sufficient encapsulation
		
		// Check for valid Google Map lat/lng values
		// IF values aren't numbers (eg. string) return FALSE
		// IF values are === to int 0 (the number zero) return FALSE
		var validGoogleMap = $.hubContactMap.isNumber(this.listings);
		
		if(!validGoogleMap) {
			GMSelector.text(this.errorMessages[options.language].invalidLatLng).css({
				color: "#f00"
			});
			throw Error(this.errorMessages[options.language].invalidLatLng);
		}
		
		// Check for GMap compatibility  
		if (typeof google.maps.BrowserIsCompatible == 'undefined') {
			GMSelector.text(this.errorMessages[options.language].cannotLoad).css({
				color: "#f00"
			});
			throw Error(this.errorMessages[options.language].cannotLoad);
		}
			
		if (!GBrowserIsCompatible()) {
			GMSelector.text(this.errorMessages[options.language].browserNotCompatible).css({color: "#f00"});
			throw Error(this.errorMessages[options.language].browserNotCompatible);
		}
		
		// Create our Google Map Object
		$.hubContactMap.addGoogleMap(el);
		
		// Add Map Marker (Uses MarkerClusterer v1.0 not Marker Manager v1.0 like the other maps...)
		$.hubContactMap.attachMarker(el);
		
		$.hubContactMap.createOfficeDetails();
		
		if (typeof callback == 'function') return callback(el, options);
	};
	
	$.hubContactMap.createOfficeDetails = function() {
		var options = this.options;
		var container = $("div#" + options.detailsContainer);
		var html = "";
		var mailingAddress = "";
		
		for(var i = 0; i < options.listings.length; i++) {
			if (options.listings[i].address2.length > 0) {
				var mailingAddress = 	"<dt class='secondaryAddress'><strong>Mailing Address</strong></dt>" +
										"<dd>" + options.listings[i].address2 + "<br/>" + options.listings[i].suburb2 + ", " + options.listings[i].state2 + " " + options.listings[i].postcode2 + "</dd>";
			}
			if(options.listings[i].showMarker) {
				// HTML for Office Details
				html = 	"<dl class='officeDetails' id='" + options.listings[i].agentId + "'>" + 
							"<dt><strong>" + options.listings[i].name + "</strong></dt>" +
							"<dd>" + options.listings[i].address + "<br/>" + options.listings[i].suburb + ", " + options.listings[i].state + " " + options.listings[i].postcode + "</dd>" +
							"<dd><strong>ph:</strong> " + options.listings[i].phone + "</dd>" +
							"<dd><strong>fax:</strong> " + options.listings[i].fax + "</dd>" +		
							"<dd><a href='mailto:" + options.listings[i].email + "'>Email our office</a></dd>" +
							"<!--dd><a href='http://" + options.listings[i].website + "' target='_blank'>" + options.listings[i].website + "</a></dd-->" +
							"<dd class='locate'><a href='/'>[ View on Map ]</a></dd>" +
							mailingAddress +
						"</dl>";
				// Append HTML to container DIV
				container.append(html);
			}
		}
		
		$("div#" + options.detailsContainer + " dd.locate a").click(function() {
			var GMap2 = $.hubContactMap.GMap2;
			// Find Agent ID
			var currentId = $(this).parent().parent().attr("id").match(/\d+$/);
			
			for(var i = 0; i < options.listings.length; i++) {
				if(options.listings[i].agentId == currentId[0]) {
					var currentDetails = options.listings[i];
				}
			}
			
			var latlng = new google.maps.LatLng(currentDetails.latitude, currentDetails.longitude);
			GMap2.setZoom(currentDetails.mapZoom);
			GMap2.panTo(latlng);
			return false;
		});
	};
	
	$.hubContactMap.attachMarker = function(el) {
		var bounds = new GLatLngBounds();
		var markers = [];
		
		for(var i = 0; i < this.listings.length; i++) {
			if(this.listings[i].showMarker) {
				// Save LatLng Values
				var lat = this.listings[i].latitude;
				var lng = this.listings[i].longitude;
				
				// Create new Point
				var newPoint = new google.maps.LatLng(lat, lng);
				
				// Exten map bounds
				bounds.extend(newPoint);
				
				// Add Marker to Array
				var marker = new GMarker(newPoint,{'clickable':true});
				marker.propertyDetails = this.listings[i];
				markers.push(marker);
				
				// Add event to markers
				google.maps.Event.addListener(marker, "click", function() {
					var details = this.propertyDetails;
					
					// HTML for info Window
					var html = 	"<div id='popupText'>" +
											"<p id='name'><strong>Office: </strong>" + details.name + "</p>" +
											"<p id='address'><strong>Address: </strong>" + details.address + ", " + details.suburb + ", " + details.state + " " + details.postcode + "</p>" +
											"<p id='phone'><strong>Phone: </strong>" + details.phone + "</p>" +
											"<p id='fax'><strong>Fax: </strong>" + details.fax + "</p>" +
											"<p id='email'><strong>Email: </strong><a href='mailto:" + details.email + "'>" + details.email + "</a></p>" +
											"<p id='website'><strong>Website: </strong><a href='http://" + details.website + "' target='_blank'>" + details.website + "</a></p>" +
											"</div>";
					
					// Create Info Window
					var GMap2 = $.hubContactMap.GMap2;
					GMap2.openInfoWindowHtml(new google.maps.LatLng(details.latitude, details.longitude), html);
				});
			}
		}
		
		// Add markers to Map (clustering)
		var markerCluster = new MarkerClusterer(this.GMap2, markers, {styles: this.options.markerIcon});

		// Set Zoom level so all markers are displayed (also center map)
		var newZoom = this.GMap2.getBoundsZoomLevel(bounds);
		
		// Fix for zoom of map
		var options = this.options;
		for(var i = 0; i < options.listings.length; i++) {
			if(i == 0){
				this.GMap2.setZoom(options.listings[i].mapZoom);
			}else{
				this.GMap2.setZoom(newZoom);
			}
		}
		
		this.GMap2.setCenter(bounds.getCenter());
	};
		
	$.hubContactMap.createStreetView = function(streetView) {
		// Store the streetView container for easy access
		var container = this.options.streetViewContainer;
		
		// Get our Width / Height to match our Google Map
		var width = this.options.mapDimensions[0];
		var height = this.options.mapDimensions[1];
		
		// Create DIV for Street View
		$('<div id="' + container + '"></div>')
			.insertAfter(this.mapElement)
			.width(width)
			.height(height)
			.css('display','none');
		
		// Create our Street View Object
		var svClient = this.svClient = new google.maps.StreetviewClient();
		var svObject = this.svClient = new google.maps.StreetviewPanorama($('#' + container).get(0));
		
		// Set Lat/Lng + Options
		if(streetView.latitude && streetView.longitude) {
			var svLatlng = new google.maps.LatLng(streetView.latitude,streetView.longitude);
			var svOptions = {yaw:streetView.pov.yaw,pitch:streetView.pov.pitch,zoom:streetView.pov.zoom};
			// Set Location + POV
			svObject.setLocationAndPOV(svLatlng, svOptions);
			// Add a button to toggle between Google Maps and Street View
			$.hubContactMap.addToggle();
		} else {
			$.hubContactMap.findStreetNode(svObject,svClient);
		}
	};
	
	$.hubContactMap.findStreetNode = function(svObject,svClient) {
		var currentMarker = new google.maps.Marker(new google.maps.LatLng(this.listings.latitude,this.listings.longitude));
		var functionVar = function(panoramaData) {
      if (panoramaData.code != 200) {
				$.hubContactMap.streetViewSuccess = false;
				return
			} else {
				var angle = $.hubContactMap.computeAngle(currentMarker.getLatLng(),panoramaData.location.latlng);
				svObject.setLocationAndPOV(panoramaData.location.latlng, {yaw: angle});
				// Add a button to toggle between Google Maps and Street View
				$.hubContactMap.addToggle();
			}
		};
		svClient.getNearestPanorama(currentMarker.getLatLng(),functionVar);
	};
	
	$.hubContactMap.computeAngle = function(endLatLng, startLatLng) {
      var DEGREE_PER_RADIAN = 57.2957795;
      var RADIAN_PER_DEGREE = 0.017453;

      var dlat = endLatLng.lat() - startLatLng.lat();
      var dlng = endLatLng.lng() - startLatLng.lng();
      // We multiply dlng with cos(endLat), since the two points are very closeby,
      // so we assume their cos values are approximately equal.
      var yaw = Math.atan2(dlng * Math.cos(endLatLng.lat() * RADIAN_PER_DEGREE), dlat) * DEGREE_PER_RADIAN;
      return $.hubContactMap.wrapAngle(yaw);
   };
	 
	$.hubContactMap.wrapAngle = function(angle) {
    if (angle >= 360) {
      angle -= 360;
    } else if (angle < 0) {
     angle += 360;
    }
    return angle;
  };
	
	$.hubContactMap.addToggle = function() {
		var container = this.options.streetViewContainer;
		$('<div id="' + this.options.toggleButton + '"><a href="javascript:void(0)">Street View</a></div>')
			.insertAfter('#' + container)
			.click(function(){
				// Get our containers
				var svContainer = $('#' + container);
				var mapContainer = $('#' + $.hubContactMap.mapElement.id);
				// Toggle our containers
				mapContainer.toggle();
				svContainer.toggle();
				//Swap our Link text
				if($('#' + container + ':visible').size()) {
					$('#' + this.id + ' a').html('Google Map');
				} else {
					$('#' + this.id + ' a').html('Street View');
				}
			});
	};
	
	$.hubContactMap.isNumber = function(numbers) {
		for(var i = 0; i < numbers.length; i++) {
			var lat = numbers[i].latitude;
			var lng = numbers[i].longitude;
			var mLat = numbers[i].mapCenterLat;
			var mLng = numbers[i].mapCenterLng;
			if(isNaN(lat)) {
				return false;
			}
			if(isNaN(lng)) {
				return false;
			}
			if(isNaN(mLat)) {
				return false;
			}
			if(isNaN(mLng)) {
				return false;
			}
		}
		return true;
	};
	
	$.hubContactMap.addGoogleMap = function(el) {
		// Set DIV dimensions
		$(el).width(this.options.mapDimensions[0]).height(this.options.mapDimensions[1]);
		
		// initialise the GMap2 object
			
		el.hubContactMap = this.GMap2 = new google.maps.Map2(el);
			
		// cleanup crew to window.unload please
		
		$(window).unload(function(){
				google.maps.Unload();
		});
		
		// Set Default
		var mapType = G_NORMAL_MAP;
		
		switch(this.options.mapType) {
			case "map":
				mapType = G_NORMAL_MAP;
				break;
			case "sat":
				mapType = G_SATELLITE_MAP;
				break;
			case "hybrid":
				mapType = G_HYBRID_MAP;
				break;
		}
		
		for(var i = 0; i < this.listings.length; i++) {
			if(this.listings[i].mapCenterLat !== 0 && this.listings[i].mapCenterLng !== 0) {
				var lat = this.listings[i].mapCenterLat;
				var lng = this.listings[i].mapCenterLng;
			}
		}
		
		el.hubContactMap.setCenter(
			new google.maps.LatLng(lat,lng), 
			5, 
			mapType
		);
		
		// Set map options
		var mapControls = el.hubContactMap.getDefaultUI();
				mapControls.zoom.scrollwheel = false;
		
		switch (this.options.mapControlSize) {
			case "small":
				mapControls.controls.smallzoomcontrol3d = true;
				mapControls.controls.largemapcontrol3d = false;
				mapControls.controls.scalecontrol = false;
				break;
			case "large":
				mapControls.controls.smallzoomcontrol3d = false;
				mapControls.controls.largemapcontrol3d = true;
				break;
		}
		el.hubContactMap.setUI(mapControls);
	
		if (this.options.mapEnableType) {
			el.hubContactMap.addControl(new google.maps.MapTypeControl()); 
		}
			
		if (this.options.mapEnableOverview) {
			el.hubContactMap.addControl(new google.maps.OverviewMapControl());
		}
		
		if (!this.options.mapEnableDragging) {
			el.hubContactMap.disableDragging(); 
		}
		
		if (!this.options.mapEnableInfoWindows) {
			el.hubContactMap.disableInfoWindow(); 
		}
		
		if (this.options.mapEnableDoubleClickZoom) {
			el.hubContactMap.enableDoubleClickZoom(); 
		}
		
		if (this.options.mapEnableScrollZoom) {
			el.hubContactMap.enableScrollWheelZoom();
		}
		
		if (this.options.mapEnableSmoothZoom) {
			el.hubContactMap.enableContinuousZoom();
		}
		
		if (this.options.mapEnableGoogleBar) {
			el.hubContactMap.enableGoogleBar();
		}
		
		if (this.options.mapEnableScaleControl) {
			el.hubContactMap.addControl(new google.maps.ScaleControl());
		}
	};
	
	/**
	jQuery(expr).hubContactMap(options)
	 - bind the sucker to the jQuery object and off we go
	*/
	$.fn.hubContactMap = function(options, callback) {
		return this.each(function(){
			$.hubContactMap.init(this, options, callback);
		});
	};
})(jQuery);
