function ieArrayFix() {
  Array.prototype.ieIndexOf = function(k){
    var len = this.length;
    for(i=0;i<len;i++){
      if(this[i] == k){
        return i;
      }
    }
    return -1;
  };
}

function getLocationsByCoords(northeast, southwest, center) {
	// Lookup locations by latitude and longitude
	var max_lat = northeast.lat().toFixed(4);
	var min_lat = southwest.lat().toFixed(4);
	var max_lng = northeast.lng().toFixed(4);
	var min_lng = southwest.lng().toFixed(4);
	var ctr_lat = center.lat().toFixed(4);
	var ctr_lng = center.lng().toFixed(4);
	
	$.getJSON('/locations/', {'max_lat': max_lat, 'min_lat': min_lat, 'max_lng': max_lng, 'min_lng': min_lng, 'ctr_lat': ctr_lat, 'ctr_lng': ctr_lng},
		function (all_locations) {
		    min_distance = 50;
			addLocationsToMap(all_locations, false);
			$("#events").trigger("getLocationsByCoordsComplete");
		}
	);
}


function getLocationsByAddress(address, max_distance, max_results) {
	// Lookup locations by address (python handles geocode)
	$.getJSON('/locaddress/', {'address': address, 'max_distance': max_distance, 'max_results': max_results },
		function (response) {
			$("#locations").html('');
			map.clearOverlays();
		    var all_locations = response.locations;
		    min_distance = response.min_distance;
			addLocationsToMap(all_locations, true);
			$("#events").trigger("getLocationsByAddressComplete");
		}
	);
}


function addLocationsToMap(location_data,is_first_load) {
	// Take location data for points and put them on the map
	
	var locations = new Array();
	location_list_html = '';
	if (existing_locations.length < 1) {
	    $("#locations").html('');
	}
	locations_bounds = new GLatLngBounds();
	unBindEventListeners();
	ieArrayFix();
    if (typeof(min_distance) == 'undefined') {
        min_distance = 50;
    }
	
	if ((location_data.length < 1) && (existing_locations.length < 1)) {
		$("#locations").prepend('<li id="noresults"><div class="info">No results available</div></li>');
		bindEventListeners();
	} else if ((location_data.length > 0) && (location_data[0].error == 'bad_address')) {
	    $("#locations").prepend('<li id="noresults"><div class="info" style="color: #d63333;">Could not find the address you entered. Please re-enter as Address, City, State Zip.</div></li>');
	} else if ((location_data.length > 0) && (location_data[0].error == 'none')) {
	    // This happens when no locations are returned on a map pan/zoom
	    // Just reenable bindings and move on
	    $("#events").trigger("addLocationsToMapComplete");
	} else {
		if ((location_data.length > 99) && (existing_locations.length < 1)) {
			$("#locations").prepend('<li id="100results"><div class="info"><b>More than 100 results returned. Only showing the first 100. Please refine your search or zoom in.</b></div></li>');
		}
		
		for (var i=0; ((i <= location_data.length) && (existing_locations.length < 100)); i++) {
			if (i != location_data.length) {
			    if (existing_locations.ieIndexOf(location_data[i].pk) == '-1') {
				    // Add the point
				    pk = location_data[i].pk
				    var point = convertLatLngToPoint(location_data[i].latitude, location_data[i].longitude);
    				locations[pk] = new createMarker(point, is_marker_clickable=true);
    				map.addOverlay(locations[pk]);
    				locations_bounds.extend(point);
    				marker_html = generateMarkerBubbleHTML(pk, location_data[i]);
    				locations[pk].bindInfoWindowHtml(marker_html);
    				GEvent.bind(locations[pk], 'click', {'pk': pk}, markerClickHandler);
			
    				location_list_html = generateLocationListHTML(pk, location_data[i]);
    				$("#locations").append(location_list_html);
    				$("#location" + pk).bind("mousedown", {'marker': locations[pk]}, locationListClickHandler);
    				if (typeof(instant_pop_location) != 'undefined') {
				        if (instant_pop_location == true) {
        				    GEvent.trigger(locations[pk], 'click');
        				    instant_pop_location = false;
        				}
    				}
    				$("#location" + pk).addClass("clickable");
    				existing_locations.push(pk);
    			} else {
    			    var point = convertLatLngToPoint(location_data[i].latitude, location_data[i].longitude);
    			    locations_bounds.extend(point);
    			}
			} else {
				if (is_first_load == true) { 
					showInitialMarkers(); 
				} else {
					showAllMarkers();	
				}
				
				$("#events").trigger("addLocationsToMapComplete");
				
			}
		}
		
		if ((existing_locations.length > 99) && (typeof(are_too_many_locations_displayed) == 'undefined')) {
	        are_too_many_locations_displayed = true
	        $("#locations").prepend('<li id="100results"><div class="info"><b>More than 100 results returned. Only showing the first 100. Please try a new search.</b></div></li>');
	    }
	    
		if (min_distance > 50) {
		    if (min_already_visible == false) {
		        min_already_visible = true;
		        $("#locations").prepend('<li id="overmaxdistance"><div class="info"><b>No locations found within 50mi. Showing the closest locations.</b></div></li>');
		    } else {
		        $("#overmaxdistance").remove();
		        $("#locations").prepend('<li id="overmaxdistance"><div class="info"><b>No locations found within 50mi. Showing the closest locations.</b></div></li>');
		    }
		}
	}
}


function showInfoWindow(marker, marker_html) {
	marker.openInfoWindowHtml(marker_html);
}


function markerClickHandler() {
	// Handle a click on a map marker
	unHighlightLocation($(".selected").attr('id'));
	highlightLocation(this.pk);

	if ($('#locations').length > 0) {
	    $("#locations").scrollTo($("#location" + this.pk), 1000);
    }
	
	$("#events").trigger("markerClickHandlerComplete");
}


function locationListClickHandler(event) {
	// Trigger a click event on a marker
	GEvent.trigger(event.data.marker, 'click');
	
	$("#events").trigger("locationListClickHandlerComplete");
}


function highlightLocation(element_id) {
    unHighlightLocation($(".selected").attr('id'));
    selectLocation(element_id);
    
	$("#location" + element_id).addClass("selected");
}


function unHighlightLocation(element_id) {
	$('#' + element_id).removeClass("selected");
}


function showAllMarkers() {
	// Resets the map zoom and center to include all bounds
	unBindEventListeners();
	//map.setZoom(map.getBoundsZoomLevel(locations_bounds));
	//map.setCenter(locations_bounds.getCenter());
	bindEventListeners();
	
	$("#events").trigger("showAllMarkersComplete");
}

function showInitialMarkers() {
	// Resets the map zoom and center to include all bounds
	unBindEventListeners();
	map.setZoom(map.getBoundsZoomLevel(locations_bounds));
	map.setCenter(locations_bounds.getCenter());
	bindEventListeners();
	
	$("#events").trigger("showAllMarkersComplete");
}

function bindEventListeners() {
	GEvent.addListener(map, 'zoomend', updateMapOnZoom);
	GEvent.addListener(map, 'dragend', updateMapOnDrag);
}


function unBindEventListeners() {
	GEvent.clearListeners(map, 'zoomend');
	GEvent.clearListeners(map, 'dragend');
}


function updateMapOnDrag() {
	// When the map is dragged look for all locations within the map bounds
	// Only updates if the map was moved more than ~20%
	unBindEventListeners();
	var map_bounds = map.getBounds();
	var map_ctr = map.getCenter();
	var map_ne = map_bounds.getNorthEast();
	var map_sw = map_bounds.getSouthWest();
	var bounds_ne = locations_bounds.getNorthEast();
				
	var move_distance = distance_between_points(map_ne, bounds_ne);
	var map_size = distance_between_points(map_ne, map_sw);
	var percent_change = move_distance / map_size;
	
	if (percent_change > 0.2) {	
		var new_center = map.getCenter();
		var latitude = new_center.lat();
		var longitude = new_center.lng();
		
		getLocationsByCoords(map_ne, map_sw, map_ctr);
	}
	$("#events").trigger("updateMapOnDragComplete");
}


function updateMapOnZoom() {
	// When the zoom level changes look for all locations within map bounds
	unBindEventListeners();
	var map_bounds = map.getBounds();
	var map_ctr = map.getCenter();
	var map_ne = map_bounds.getNorthEast();
	var map_sw = map_bounds.getSouthWest();
	
	getLocationsByCoords(map_ne, map_sw, map_ctr);
}


function distance_between_points(point1, point2) {
	// Calculate the distance in km between two points
	var lat1 = point1.lat();
	var lon1 = point1.lng();
	var lat2 = point2.lat();
	var lon2 = point2.lng();
	
	var radius = 6371;
	var distance = Math.acos(
					Math.sin(lat1)
					* Math.sin(lat2)
					+ Math.cos(lat1)
					* Math.cos(lat2)
					* Math.cos(lon2-lon1))
					* radius;
              
    return distance;
}


function processNewSearch() {
	// Look for values on page and handle the search
	address_search = $("#address").val();
	max_distance = $("#max_distance").val();
	max_results = $("#max_results").val();
	locations_bounds = new GLatLngBounds();
	existing_locations = new Array();
	min_already_visible = false;
	
	if (address_search == null) {
		address_search = "50 Bramblewood Lane, Gates, NY";
	}
	
	if (max_distance == null) {
		max_distance = 25;
	}
	
	if (max_results == null) {
		max_results = 5;
	}
	
	getLocationsByAddress(address_search, max_distance, max_results);
	//$("#locationsdiv").html('');
	
	$("#events").trigger("processNewSearchComplete");
}


function geoCodeLocation(address) {
	// Geocode the address using Maps API
	geocoder.getLatLng(
  		address,
  		function(point) {
  			latlng = {'lat': point.lat(), 'lng': point.lng()};
  			$("#messages").append("geoCodeComplete<br>");
  		}
	);
	
	$("#events").trigger("geoCodeLocationComplete");
}


function addMapToPage(map_id) {
	// Initialize the map
	map = new GMap2(document.getElementById(map_id));
	map.setCenter(new GLatLng(39.238128, -96.183553), 4);
	map.addControl(new GSmallZoomControl3D());
	map.addControl(new GScaleControl());
	map.setMapType(G_NORMAL_MAP);
	buttons = new Array();
	button_listeners = false;
	existing_locations = new Array();
	min_already_visible = false;
	onFullyLoaded();
	
	$("#events").trigger("addMapToPageComplete");
}


function createMarker(point, is_marker_clickable) {
	// Create marker objects
	if ((is_marker_clickable == null) || (is_marker_clickable == '')) {
		is_marker_clickable = true;
	}
	
	this.marker = new GMarker(point, {clickable: is_marker_clickable});
	
	return this.marker;
}


function convertLatLngToPoint(lat, lng) {
	// Create a GLatLng object from coordinates
	point = new GLatLng(lat, lng);
	
	return point;
}


function selectLocation(location_id) {
    // Set location in session
    location_selected = false;
    if (map_page == 'checkout') {
        $("#spinnerdiv").show();
        $(".order_details_text").hide();
    }
    $.getJSON('/set-location/', {'location_id': location_id},
        function(response) {
            if (response.pk == location_id) {
                if (map_page == 'checkout') {
                    // Update location in sidebar
                    location_selected = true;
                    locsummary = generateSummaryLocationHTML(response);                
                    $("#summarylocation").html(locsummary);
                }
            } else {
                if (map_page == 'checkout') {
                    // Indicate that location didn't update
                    $("#summarylocation").html('<span class="orderlabel"><strong>Could not set your location at this time.</strong></span>');
                }
            }
            if (map_page == 'checkout') {
                $("#spinnerdiv").hide();
                $(".order_details_text").show();
            }
        }
    );
}


function generateSummaryLocationHTML(location) {
    // Generate HTML for the location in checkout summary
    if ((location.address2 != null) && (location.address2 != '')) {
		st_address = location.address1 + '<br>' + location.address2;
	} else {
		st_address = location.address1;
	}
    this.html = '<span class="orderlabel">Location:</span><span class="item">';
    this.html += st_address;
    this.html += '<br>' + location.city + ', ' + location.state + ' ' + location.zip;
    this.html += '<br></span><hr class="space" />';
    
    return this.html;
}


function generateLocationListHTML(index, data) {
	// HTML for location list bar
	this.index = index;
	this.data = data;
	
	if (this.data.address2 != null) {
		this.st_address = this.data.address1 + this.data.address2;
	} else {
		this.st_address = this.data.address1;
	}
	
	this.content = '';
	this.content += '<li id="location' + this.data.pk + '">';
	this.content += '<div class="info">';
	this.content += '<a href="#" onHover="highlightLocation(' + this.index + ');return false;">';
	this.content += '<div class="address" style="color:#222;font-weight:bold;">';
	this.content += '<div>' + this.st_address + '</div>';
	this.content += '<div>' + this.data.city + ', ' + this.data.state + ' ' + this.data.zip + '</div>';
	this.content += '</div></a>';
	if (this.data.distance) {
    	this.content += '<div>Distance: ' + Math.round(this.data.distance) + ' mi.</div>';
	}
	this.content += '<div>Hours: ' + this.data.hours + '</div>';
	this.content += '<div><a href="/std-test-pricing/" class="location_button" style="text-decoration:;font-size:125%; font-weight:bold;color:#2b7ebf;">Order &amp; Test Here</a></div>';
	this.content += '<a class="directions" style="color:#2b7ebf;" href="http://maps.google.com/maps?daddr=' + this.st_address + this.data.city + ', ' + this.data.state + ' ' + this.data.zip + '" target="_blank">Get Driving Directions</a>';
	this.content += '<button class="select_location_button" style="margin:3px 0 0 0;">Select Location</button>';
	this.content += '</div>';
	this.content += '</li>';
	
	return this.content;
}


function generateMarkerBubbleHTML(index, data) {
	// HTML for marker bubble
	this.index = index;
	this.data = data;
	
	
	if (this.data.address2 != null) {
		this.st_address = this.data.address1 + '<br>' + this.data.address2;
	} else {
		this.st_address = this.data.address1;
	}
	
	this.content = '<div class="map-caption"">';
	this.content += '<div class="mapbubble">';
	this.content += '<div class="address">';
	this.content += '<div>' + this.st_address + '</div>';
	this.content += '<div>' + this.data.city + ', ' + this.data.state + ' ' + this.data.zip + '</div>';
	this.content += '</div>';
	this.content += '<div><a href="/std-test-pricing/" style="text-decoration:none;font-size:125%; font-weight:bold;" class="location_button">Order &amp; Test Here</a></div>';
	this.content += '<a class="directions" href="http://maps.google.com/maps?daddr=' + this.st_address + this.data.city + ', ' + this.data.state + ' ' + this.data.zip + '" target="_blank">Get Driving Directions</a>';
	this.content += '<div id="selected-indicator" class="green" style="margin-top:5px;font-weight:bold;"><img src="/static/i/green_check.gif"> Location Selected.</div>';
	
	return this.content;
}

function changeZoom(zoom_delta) {
    // Easily increase or decrease zoom level of map
    current_zoom = map.getZoom();
    new_zoom = current_zoom + zoom_delta;
    map.setZoom(new_zoom);
}