/**
 * @fileoverview
 * Provides all of the supporting JavaScript functionality for Kinetic's geocoding and mapping
 * web applications.
 * 
 * Documentation isn't overdone here, you should find the code pretty readable.
 * 
 * @author donnie@kinetic.com
 * @version 1.0.0
 * @requires jQuery Should be version 1.4.2 (or later)
 * @requires GoogleMapsAPI Requires the Google Maps API for geocoding and mapping functionality
 */


/**
 * The base Location constructor, it is preffered that only full locations be created (ie no
 * empty constructor should be necessary).  The individual functions attached to the object are
 * not documented, it should be pretty obvious what they do. ;)
 * 
 * @param {int}		id		Unique database ID (PK)
 * @param {string}	number	Organization specific location number (such as store number)
 * @param {string}	name	Human-readable location name
 * @param {string}	address	Full street address (we don't break it into lines)
 * @param {string}	city	City
 * @param {string}	state	State
 * @param {string}	zip		ZIP
 * @param {string}	phone	Phone number
 * @param {string}	lat		Latitude
 * @param {string}	lng		Longitude
 * @param {int}		i		Where in the support arrays the location is located (index)
 */
function Location(id, number, name, address, city, state, zip, phone, lat, lng, i) {
	this.id			= id;
	this.number		= number;
	this.name		= name;
	this.address	= address;
	this.city		= city;
	this.state		= state;
	this.zip		= zip;
	this.phone		= phone;
	this.lat		= lat;
	this.lng		= lng;
	this.point		= new GLatLng(lat, lng);
	this.i			= i;
	
	this.distanceFromCurrentPoint = 0;
	
	this.milesFromCurrentPoint = function() {
		return Math.round(this.distanceFromCurrentPoint / 1609);
	}
	
	this.createMarker = function() {
		var icon = new GIcon(G_DEFAULT_ICON);
		icon.image = "http://labs.google.com/ridefinder/images/mm_20_red.png";
			icon.iconSize = new GSize(9, 15);
		icon.shadowSize = new GSize(20, 15);
		icon.iconAnchor = new GPoint(6, 20);
		icon.infoWindowAnchor = new GPoint(7, 0);
			markerOptions = { icon:icon };
			var marker = new GMarker(this.point, markerOptions);
		var html = '';
		html += '<div class="location-popup">';
		html += '<span class="name">' + this.name + '</span>';
		html += '<span class="address street-address">' + this.address + '</span>';
		html += '<span class="address city-state-zip">' + this.city + ', ' + this.state + ' ' + this.zip + '</span>';
		html += '<span class="phone">' + this.phone + '</span>';
		if (this.distanceFromCurrentPoint != 0) { 
			html += '<span class="distance">Distance: Approx ' + this.milesFromCurrentPoint() + ' miles</span>';
		}
		html += '</div>';

        GEvent.addListener(marker, "click", function() {
			marker.openInfoWindowHtml(html);
        });
		this.marker = marker;
        return this.marker;
	};
	
	this.createSidebarEntry = function() {
		var html = '';
		html += '<div class="sidebar-location">';
		html += '<span class="name"><a href="javascript:locations[' + this.i + '].displayMarkerDetails();">' + this.name + '</a></span>';
		html += '<span class="address street-address">' + this.address + '</span>';
		html += '<span class="address city-state-zip">' + this.city + ', ' + this.state + ' ' + this.zip + '</span>';
		html += '<span class="phone">' + this.phone + '</span>';
		if (this.distanceFromCurrentPoint != 0) {
			html += '<span class="distance">Distance: Approx ' + this.milesFromCurrentPoint() + ' miles</span>';
		}
		html += '</div>';
		$("#sidebar").append(html);
	}
	
	this.displayMarkerDetails = function() {
		GEvent.trigger(this.marker, "click");
	}
}	

var map;
var locations = new Array();
var currentCenter = new GLatLng(33.448734, -86.841698);
var reasons=[];
reasons[G_GEO_SUCCESS]            = "Success";
reasons[G_GEO_MISSING_ADDRESS]    = "Missing Address: The address was either missing or had no value.";
reasons[G_GEO_UNKNOWN_ADDRESS]    = "Unknown Address:  No corresponding geographic location could be found for the specified address.";
reasons[G_GEO_UNAVAILABLE_ADDRESS]= "Unavailable Address:  The geocode for the given address cannot be returned due to legal or contractual reasons.";
reasons[G_GEO_BAD_KEY]            = "Bad Key: The API key is either invalid or does not match the domain for which it was given";
reasons[G_GEO_TOO_MANY_QUERIES]   = "Too Many Queries: The daily geocoding quota for this site has been exceeded.";
reasons[G_GEO_SERVER_ERROR]       = "Server error: The geocoding request could not be successfully processed.";
reasons[403]                      = "Error 403: Probably an incorrect error caused by a bug in the handling of invalid JSON.";

$(document).ready(function() {
	var geo = new GClientGeocoder();
	
	$("#recenter").bind("click", function() {
		geo.getLocations($("#criteria").val(), function(r) {
			if (r.Status.code == G_GEO_SUCCESS) {
				var p = r.Placemark[0].Point.coordinates;
				currentCenter = new GLatLng(p[1], p[0]);
				map.setCenter(currentCenter, 11);
				filterPoints();
			} else {
				alert(r.Status.code);
			}
		});
	});
	
	$("#allLocations").bind("click", function() {
		displayAllLocations();
	});
	
	if (GBrowserIsCompatible()) {
		
		map = new GMap2(document.getElementById("map"));
		map.addControl(new GLargeMapControl());
		map.addControl(new GMapTypeControl());
		
		 if (window.location.href.indexOf('?') > 0){  //if there are parameters...
		 
			if (getURLParameter('city') != 'City%2C+State' || getURLParameter('zip') != 'Zip+Code'){

			    if (getURLParameter('city') != 'City%2C+State') {
					$("#criteria").val(getURLParameter('city'));
	                    } else if (getURLParameter('zip') != 'Zip+Code') {
						$("#criteria").val(getURLParameter('zip'));
						}

						if (getURLParameter('within') != '%23') {
					  $("#within").val(getURLParameter('within'));
					  }
					  
				  $("#recenter").click();	
			    }
			} else {  //if there are no parameters
		displayAllLocations();
	  }
	}
});

function filterPoints() {
	var pointsToDisplay = 5;
	map.clearOverlays();
	clearSidebar();
	
	for (var i = 0; i < locations.length; i++) {
		locations[i].distanceFromCurrentPoint = currentCenter.distanceFrom(locations[i].point);
	}
	
	locations.sort(sortPointsByDistance);
	
	buildLocationIndexes();
	
	if ($("#within").val() == "") { // the drop-down indicates the user wants whatever locations are closest
		for (var i = 0; i < pointsToDisplay; i++) {
			map.addOverlay(locations[i].createMarker());
			locations[i].createSidebarEntry();
		}	
	} else {
		for (var i = 0; i < locations.length; i++) {
			if (locations[i].milesFromCurrentPoint() < $("#within").val()) {
				map.addOverlay(locations[i].createMarker());
				locations[i].createSidebarEntry();
			}
		}
	}
}

function sortPointsByDistance(a, b) {
	return a.distanceFromCurrentPoint - b.distanceFromCurrentPoint;
}

function sortPointsByStoreNumber(a, b) {
	return a.number - b.number;
}

function displayAllLocations() {
	currentCenter = new GLatLng(33.448734, -86.841698);
	map.setCenter(currentCenter, 7);
	map.clearOverlays();
	clearSidebar();
	
	locations.sort(sortPointsByStoreNumber);
	buildLocationIndexes();
		
	for (var i = 0; i < locations.length; i++) {
		locations[i].distanceFromCurrentPoint = 0;
		map.addOverlay(locations[i].createMarker());
		locations[i].createSidebarEntry();
	}
}

function clearSidebar() {
	$("#sidebar").text("");
}

/*
 * This function is needed to make sure that once we do array manipulation the
 * location's individual index reference is accurate.
 */
function buildLocationIndexes() {
	for (var i = 0; i < locations.length; i++) {
		locations[i].i = i;
	}
}

function getURLParameter(strParamName) {
       var strReturn = "";
       var strHref = window.location.href;
       var bFound = false;
       
       var cmpstring = strParamName + "=";
       var cmplen = cmpstring.length;
       
       if (strHref.indexOf("?") > -1) {
              var strQueryString = strHref.substr(strHref.indexOf("?") + 1);
              var aQueryString = strQueryString.split("&");
              
              for (var iParam = 0; iParam < aQueryString.length; iParam++) {
                     if (aQueryString[iParam].substr(0, cmplen) == cmpstring) {
                           var aParam = aQueryString[iParam].split("=");
                           strReturn = aParam[1];
                           bFound = true;
                           break;
                     }
              }
       }
       if (bFound == false) return null;
       return strReturn.replace("#", "");
}
