var LocationFinder = {
	
	// Setting lat/lng on object, so it's reusable
 	lat: '51.494851',
	lng: '-0.087204',
	zoom_level : 12,
	
	markers : {},
	distances : {},
	
	map : null,
	map_dom_id : 'map',
	json_url : '/locations_json/',
	info_window : null,
	info_window_location : null,
	
	search_term : null,
	search_location : null,
	
	init : function(autoload)
	{
		this.embedMap();
		this.createInfoWindow();
		if(autoload === true){ this.loadMapData(); }
	},
	
	initWithSearch : function()
	{
		if (this.searchTerm()) {
			LocationFinder.updateSearchLocation(this.search_term, function() {
				LocationFinder.zoom_level = 15;
				LocationFinder.init(true);
			});
		} else {
			this.init(true);
		}
	},
	
	updateSearchLocation : function(address, callback)
	{
		geocoder = new google.maps.Geocoder();
		geocoder.geocode({ address : address, region : 'UK' }, function(results, status){
			if (status == google.maps.GeocoderStatus.OK) {
				LocationFinder.search_location = results[0].geometry.location;
				LocationFinder.lat = results[0].geometry.location.lat();
				LocationFinder.lng = results[0].geometry.location.lng();
				if (callback) {
					callback();
				}
			}
		});
	},
	
	searchTerm : function()
	{
		LocationFinder.search_term = decodeURI(window.location.hash.replace('#', ''));
		return LocationFinder.search_term;
	},
	
	embedMap : function()
	{
		var latlng = new google.maps.LatLng(this.lat, this.lng);
		var options = {
			zoom: this.zoom_level,
			center: latlng,
			mapTypeId: google.maps.MapTypeId.TERRAIN,
			mapTypeControl: false,
			navigationControlOptions: {
				style: google.maps.NavigationControlStyle.ZOOM_PAN,
				position: google.maps.ControlPosition.TOP_RIGHT
			}
		};
		
		this.map = new google.maps.Map(document.getElementById(this.map_dom_id), options);
	},
	
	loadMapData : function()
	{
		google.maps.event.addListener(this.map, 'idle', function() {
			
			jQuery.getJSON(LocationFinder.json_url, LocationFinder.buildOptions(), function(data){
				LocationFinder.removeLocations(data.remove);
				LocationFinder.updateDistances(data.distances);
				LocationFinder.createLocations(data.create);
				LocationFinder.reorderSidebar();
			});
		});
	},
	
	buildOptions : function()
	{
		center = (LocationFinder.search_location) ? LocationFinder.search_location : LocationFinder.map.getCenter();
		
		options = LocationFinder.getMinMaxBounds(LocationFinder.map.getBounds());
		options.markers = LocationFinder.listMarkers();
		options.center_lat = center.lat();
		options.center_lng = center.lng();
		
		return options;
	},
	
	createLocations : function(data)
	{
		jQuery.each(data, function(i){
			
			if (!LocationFinder.markerExists(this)) {
				marker = LocationFinder.addMarker(this);
				LocationFinder.attachInfoWindow(marker, this);
				LocationFinder.addToSidebar(this);
			}
		});
	},
	
	removeLocations : function(data)
	{
		var length = data.length;
		for ( var i=0, len=length; i<len; ++i ){
			
			location_id = data[i];
			LocationFinder.markers[location_id].setMap(null);
			delete LocationFinder.markers[location_id];
			jQuery('#location_'+location_id).remove();
			if (LocationFinder.info_window_location == location_id) {
				LocationFinder.info_window.close();
				LocationFinder.info_window_location = null;
			}
		}
	},
	
	updateDistances : function(data)
	{
		LocationFinder.distances = data;
		
		jQuery.each(data, function(location_id, distance){
			jQuery('#location_'+location_id+' p.distance small').text(LocationFinder.distanceText(distance));
		});
	},
	
	reorderSidebar : function()
	{
		elements = [];
		jQuery.each(LocationFinder.distances, function(location_id, distance){
			elements.push(jQuery('#location_'+location_id)[0]);
		});
		jQuery('#sidebar').empty().append(elements);	
	},
	
	getMinMaxBounds : function(bounds)
	{
		var southWest = bounds.getSouthWest();
		var northEast = bounds.getNorthEast();
		
		return {
			min_lat : southWest.lat(),
			max_lat : northEast.lat(),
			min_lng : southWest.lng(),
			max_lng : northEast.lng()
		};
	},
	
	addMarker : function(location)
	{
		var marker = new google.maps.Marker({
			position : new google.maps.LatLng(location.latitude, location.longitude), 
			map : LocationFinder.map, 
		 	title : location.name
		});
		
		if (location.id) {
			LocationFinder.markers[location.id] = marker;
		}
		
		return marker;
	},
	
	markerExists : function(location)
	{
		if (!location.id) return true;
		if (LocationFinder.markers[location.id]) {
			return true;
		} else {
			return false;
		}
	},
	
	createInfoWindow : function()
	{
		this.info_window = new google.maps.InfoWindow({ maxWidth : 200 });
		google.maps.event.addListener(this.info_window, 'closeclick', function(){
			LocationFinder.info_window_location = null;
			jQuery('#sidebar li').removeClass('current');
		});
	},
	
	attachInfoWindow : function(marker, location)
	{	
		google.maps.event.addListener(marker, 'click', function() {
			LocationFinder.displayInfoWindow(marker, location);
		});
	},
	
	displayInfoWindow : function(marker, location)
	{
		var content = '<h2 style="font-size:1.4em"><strong>'+location.name+'</strong></h2>';
		if (location.address) content += '<p style="padding-top:6px;">'+location.address+'</p>';
		content += '<p style="padding-top:6px;"><a href="'+location.permalink+'">View table details</a></p>';
		
		jQuery('#sidebar li').removeClass('current');
		jQuery('#location_'+location.id).addClass('current');
		LocationFinder.map.panTo(new google.maps.LatLng(location.latitude, location.longitude));
		LocationFinder.info_window.setContent(content);
		LocationFinder.info_window.open(LocationFinder.map, marker);
		LocationFinder.info_window_location = location.id;
	},
	
	addToSidebar : function(location)
	{
		var content = '<li id="location_'+location.id+'">';
		content += '<a href="#">';
		content += '<h3>'+location.name+'</h3>';
		content += '<p class="distance"><small>'+LocationFinder.distanceText(LocationFinder.distances[location.id])+'</small></p>';
		content += '</a>';
		content += '</li>';
		
		jQuery('#sidebar').append(content);
		jQuery('#location_'+location.id).live('click', function() {
			LocationFinder.displayInfoWindow(LocationFinder.markers[location.id], location);
		});
	},
	
	distanceText : function(distance)
	{
		if (distance > 0) {
			text = 'Approximately '+distance+' miles';
			if (!LocationFinder.search_location) text += ' from map center';
		} else {
			text = 'Located at map center';
		}

		return text;
	},
	
	listMarkers : function()
	{
		markers = [];
		for (var location_id in LocationFinder.markers) markers.push(location_id);
		return markers.join(',');
	}
};

jQuery(function() {
	// Checking DOM element exists before trying to load Google map into it
	if(jQuery('#' + LocationFinder.map_dom_id).size() > 0){
		LocationFinder.initWithSearch();
	}
});
