function isMobileDevice()
{
	var a = navigator.userAgent||navigator.vendor||window.opera;

        // Allow iPad access to full page
        if (navigator.userAgent.match(/iPad/i) != null) return false;
        //Other mobile devices are redirected
        if(/android|avantgo|blackberry|blazer|compal|elaine|fennec|hiptop|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile|o2|opera m(ob|in)i|palm( os)?|p(ixi|re)\/|plucker|pocket|psp|smartphone|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce; (iemobile|ppc)|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) return true;

	return false;
}

    // Prevents map idle event from occuring while geolocation request is pending
    var _enableMapIdle = true;

  $j(document).ready( function() {
		// set user preferences
		if (typeof(setUserPreferences) != "undefined") {
			if ($j.isFunction(setUserPreferences)) setUserPreferences();
		}
		// set user preferences
		if (typeof(setPageSpecificVars) != "undefined") {
			if ($j.isFunction(setPageSpecificVars)) setPageSpecificVars();
		}

		// namespace for our vars
		$j.elementVars = {};  

		// Miscellaneous setup for page 
		miscFormSetup();

		// Init some vars
		$j.elementVars.AJAXhandler = '/features/storeLocatorAjax.php';	
		
		$j.elementVars.map = null;
		$j.elementVars.mapHasBeenInitialized = false;
		$j.elementVars.infowindow = null;
		$j.elementVars.trafficLayer = new google.maps.TrafficLayer();
		$j.elementVars.geocoder = null;
		$j.elementVars.directionsService = new google.maps.DirectionsService();
		$j.elementVars.directionsRenderer = new google.maps.DirectionsRenderer();
		$j.elementVars.directionsRendererModal = new google.maps.DirectionsRenderer();
		$j.elementVars.startLat = null;
		$j.elementVars.startLng = null;
		$j.elementVars.centerLat = null;
		$j.elementVars.centerLng = null;
		$j.elementVars.mapBounds = null;
		$j.elementVars.searchRadius = null;
		$j.elementVars.mapRadius = null;
		$j.elementVars.userSpecifiedStartAddress = null;
		$j.elementVars.userSpecifiedSearchRadius = null;
		$j.elementVars.queryType = 'map_change';
		$j.elementVars.startMarkersArray = [];
		$j.elementVars.locationMarkersArray = [];
		$j.elementVars.lastSearchResultsType = 'APPROXIMATE';
		$j.elementVars.UserHasSearched = false;
		$j.elementVars.locationsHTML = '';
		$j.elementVars.usersLat = null;
		$j.elementVars.usersLng = null;
		$j.elementVars.userLatLng = null;
		$j.elementVars.lastGeoLocateAddress = null;
		
		// DEFAULT PREFERENCES
		$j.elementVars.LayoutType = 'full';
		$j.elementVars.StartupMode = 'Search Overlay';
		$j.elementVars.defaultSearchRadius = 100;
		$j.elementVars.SearchMaxMatches = 50;
		$j.elementVars.SearchType = 'Geographic'; // valid options are 'Geographic' and 'Postal Code Lookup'
		$j.elementVars.ExpandFailedZipOnlySearch = 'No';
		$j.elementVars.enableGPSbasedStartPosition = 'Yes';
		$j.elementVars.hideLocationsUntilUserSearch = 'Yes';
		$j.elementVars.useNumberedMarkers = 'Yes';
		$j.elementVars.enableStreetView = 'Yes';
		// this will redirect if there is only one location
		$j.elementVars.enableSingleResultRedirect = 'Yes';
		
		// default start position; for center of US, use lat:38 lng:-97 zoom:3)
		$j.elementVars.defaultLat = '38';
		$j.elementVars.defaultLng = '-97';
		$j.elementVars.defaultZoom = 3;

		// Properties for Markers
		$j.elementVars.MarkerIconsBasePath = '/features/StoreLocator/images/custom_icons/';
		$j.elementVars.customStartMarker = '/features/StoreLocator/images/custom_icons/man.png';
		$j.elementVars.defaultStartLabel = 'You are Here';
		$j.elementVars.defaultStartMarkerInfo = '<div class="map-marker-info">You Are Here</div>';
		$j.elementVars.startMarkerZindex = 1;
		$j.elementVars.locationMarkerZindex = 2;

		// messages and strings
		$j.elementVars.geolocateFailedMessage = "<div class=\"message-select-location\">Search Failed. Please try again.<div>";
		$j.elementVars.emptyLocationsMessage = "<div class=\"message-locations\">No Locations Found<div>";
		$j.elementVars.emptySelectedLocationMessage = "<div class=\"message-select-location\">Nothing Found.<div>";
		$j.elementVars.waiting_user_input_message = '<p style="margin:20px;text-align:center;"><span style="border:1px solid #000000;padding:4px;color:red;background-color:#FFFFFF;">Waiting for User Input</span></p>';
		$j.elementVars.zipSearchFallingBackToGeoSearchMessage = '<div class=\"message-locations\">No match found for that Postal Code. Here are the nearest locations.<div>';
				
		// OVERRIDE DEFAULT PREFERENCES
		if (typeof($j.prefVars) != "undefined") {
			if (typeof($j.prefVars.LayoutType) != "undefined" && $j.prefVars.LayoutType.length >0) {
				$j.elementVars.LayoutType = $j.prefVars.LayoutType;
			}
			if (typeof($j.prefVars.StartupMode) != "undefined") {
				if ($j.prefVars.StartupMode == 'Blank Map' || $j.prefVars.StartupMode == 'Search Overlay') {
					$j.elementVars.StartupMode = $j.prefVars.StartupMode;
				}
			}
			if (typeof($j.prefVars.SearchMaxRadius)!="undefined") {
				if ($j.prefVars.SearchMaxRadius.length < 6 && parseInt($j.prefVars.SearchMaxRadius) > 0) {
					$j.elementVars.defaultSearchRadius = $j.prefVars.SearchMaxRadius;
				}
			}
			if (typeof($j.prefVars.SearchMaxMatches)!="undefined") {
				if ($j.prefVars.SearchMaxMatches.length < 6  && parseInt($j.prefVars.SearchMaxMatches) > 0) {
					$j.elementVars.SearchMaxMatches = $j.prefVars.SearchMaxMatches;
				}
			}
			if (typeof($j.prefVars.SearchType) != "undefined") {
				if ($j.prefVars.SearchType == 'Geographic' || $j.prefVars.SearchType == 'Postal Code Lookup') {
					$j.elementVars.SearchType = $j.prefVars.SearchType;
				}
			}
			if (typeof($j.prefVars.ExpandFailedZipOnlySearch)!="undefined") $j.elementVars.ExpandFailedZipOnlySearch = $j.prefVars.ExpandFailedZipOnlySearch;
			if (typeof($j.prefVars.enableGPSbasedStartPosition)!="undefined") $j.elementVars.enableGPSbasedStartPosition = $j.prefVars.enableGPSbasedStartPosition;

			// temp override of gps preference
			if ($j.elementVars.LayoutType =="full") $j.elementVars.enableGPSbasedStartPosition = 'No';

			if (typeof($j.prefVars.hideLocationsUntilUserSearch)!="undefined") $j.elementVars.hideLocationsUntilUserSearch = $j.prefVars.hideLocationsUntilUserSearch;
			if (typeof($j.prefVars.useNumberedMarkers)!="undefined") $j.elementVars.useNumberedMarkers = $j.prefVars.useNumberedMarkers;
			if (typeof($j.prefVars.enableStreetView)!="undefined") $j.elementVars.enableStreetView = $j.prefVars.enableStreetView;
			if (typeof($j.prefVars.MapDefaultCenterLat)!="undefined") {
				if ($j.prefVars.MapDefaultCenterLat.length < 64 && $j.prefVars.MapDefaultCenterLat.length >0) $j.elementVars.defaultLat = $j.prefVars.MapDefaultCenterLat;
			}
			if (typeof($j.prefVars.MapDefaultCenterLng)!="undefined") {
				if ($j.prefVars.MapDefaultCenterLng.length < 64 && $j.prefVars.MapDefaultCenterLng.length >0) $j.elementVars.defaultLng = $j.prefVars.MapDefaultCenterLng;
			}
			if (typeof($j.prefVars.MapDefaultZoom)!="undefined") {
				if ($j.prefVars.MapDefaultZoom.length < 4 && $j.prefVars.MapDefaultZoom.length > 0) $j.elementVars.defaultZoom = parseInt($j.prefVars.MapDefaultZoom);
			}
			// messages and strings
			if (typeof($j.prefVars.geolocateFailedMessage)!="undefined") {
				if ($j.prefVars.geolocateFailedMessage.length > 0) {
					$j.elementVars.geolocateFailedMessage = "<div class=\"message-select-location\">"+$j.prefVars.geolocateFailedMessage+"<div>";
				}
			}
			if (typeof($j.prefVars.emptyLocationsMessage)!="undefined") {
				if ($j.prefVars.emptyLocationsMessage.length > 0) {
					$j.elementVars.emptyLocationsMessage = "<div class=\"message-locations\">"+$j.prefVars.emptyLocationsMessage+"<div>";
				}
			}
			if (typeof($j.prefVars.emptySelectedLocationMessage)!="undefined") {
				if ($j.prefVars.emptySelectedLocationMessage.length > 0) {
					$j.elementVars.emptySelectedLocationMessage = "<div class=\"message-select-location\">"+$j.prefVars.emptySelectedLocationMessage+"<div>";
				}
			}
			if (typeof($j.prefVars.zipSearchFallingBackToGeoSearchMessage)!="undefined") {
				if ($j.prefVars.zipSearchFallingBackToGeoSearchMessage.length > 0) {
					$j.elementVars.zipSearchFallingBackToGeoSearchMessage = "<div class=\"message-locations\">"+$j.prefVars.zipSearchFallingBackToGeoSearchMessage+"<div>";
				}
			}
			if (typeof($j.prefVars.MarkerIconsBasePath)!="undefined") {
				if ($j.prefVars.MarkerIconsBasePath.length < 255 && $j.prefVars.MarkerIconsBasePath.length > 4) {
					$j.elementVars.MarkerIconsBasePath = $j.prefVars.MarkerIconsBasePath;
				}
			}
			if (typeof($j.prefVars.enableSingleResultRedirect)!="undefined") {
				
				$j.elementVars.enableSingleResultRedirect = $j.prefVars.enableSingleResultRedirect;

			}
			
		}

		// SET PAGE-SPECIFIC VARS
		if (typeof($j.pageSpecificVars) != "undefined") {
			if (typeof($j.pageSpecificVars.redirectToFullLocator) != "undefined" && $j.pageSpecificVars.redirectToFullLocator.length >0) {
				$j.elementVars.redirectToFullLocator = $j.pageSpecificVars.redirectToFullLocator;
			}
		}

        // Draw the map
        $j.elementVars.queryStringStartLocation = "";
        initializeMap($j.elementVars.defaultLat, $j.elementVars.defaultLng, $j.elementVars.defaultZoom);
        if (readQueryString("userStLoc") || $j.elementVars.hideLocationsUntilUserSearch == "No") {
            userSearch(false, null, $j.elementVars.queryStringStartLocation);
        } else if (geo_position_js.init() && $j.elementVars.enableGPSbasedStartPosition == 'Yes') {
            $j('div#map_canvas').html($j.elementVars.waiting_user_input_message);
            geo_position_js.getCurrentPosition(geocode_success_callback,geocode_failed_callback,{enableHighAccuracy:true});
        } else if ($j.elementVars.StartupMode == 'Search Overlay') {
            overlaySearchForm();
        }
    });

	function geocode_success_callback(position) {
		$j.elementVars.usersLat = position.coords.latitude;
		$j.elementVars.usersLng = position.coords.longitude;
		$j.elementVars.userLatLng = new google.maps.LatLng($j.elementVars.usersLat,$j.elementVars.usersLng);
		initializeMap($j.elementVars.usersLat,$j.elementVars.usersLng,$j.elementVars.defaultZoom);
		// Set query type (user-initiated searches need no resorting in PHP)
  	  	$j.elementVars.queryType = 'user_search';
		$j.elementVars.UserHasSearched = true;
		setStartPoint(true);
	}

	function geocode_failed_callback(position) {
		initializeMap($j.elementVars.defaultLat,$j.elementVars.defaultLng,$j.elementVars.defaultZoom);
		if ($j.elementVars.StartupMode == 'Search Overlay' && !$j.elementVars.UserHasSearched) {
			overlaySearchForm();
		}
	}		

	function initializeMap(Lat,Lng,ZoomNum) {
		$j.elementVars.mapHasBeenInitialized = true;
	    var latlng = new google.maps.LatLng(Lat, Lng);
	    var streetViewFlag = $j.elementVars.enableStreetView == 'Yes' ? true : false;
	    var mapOptions = {
	      zoom: ZoomNum,
	      center: latlng,
	      streetViewControl: streetViewFlag,
	      mapTypeId: google.maps.MapTypeId.ROADMAP
	    };
	    $j.elementVars.map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);

    	// Construct Single InfoWindow
	    $j.elementVars.infowindow = new google.maps.InfoWindow();

	    // Add listener for clicks on map and close InfoWindow
	    google.maps.event.addListener($j.elementVars.map, 'click', closeInfoWindow);
	    
	    // Add listener for changes to map
	    addChangeListener();
	}

	function overlaySupported()
	{
		return $j("#searchOverlay").size() > 0;
	}

	function overlaySearchForm() {
    	if(!$j.elementVars.UserHasSearched) {
        	return;
    	}
		if(!overlaySupported()) {
			return;
		}
		$j("#searchOverlay").overlay({
			// custom top position
			top: 140,
			// some mask tweaks
			mask: {
				color: '#ebecff',
				loadSpeed: 200,
				opacity: 0.8
			},
			closeOnClick: false,
			closeOnEsc: false,

			// load it immediately after the construction
			load: true
		});
		$j("#userStartLocationOverlay").focus();
	}

	function addChangeListener() {
	    // listen for changes to map
	    google.maps.event.addListener($j.elementVars.map, 'idle', function() {
    	    if(!_enableMapIdle) {
        	    return;
    	    }
		    if ($j.elementVars.hideLocationsUntilUserSearch == 'Yes' && !$j.elementVars.UserHasSearched) {
		    	return;
			} else if ($j.elementVars.SearchType == 'Postal Code Lookup' && $j.elementVars.queryType == 'map_change') {
				// ignore map changes in zip-only mode 
				return;
			}
			
	    	// get new center point and radius
	    	setCenterPointAndMapRadius();

	    	// search radius is either default for searches or based on visible map
			if ($j.elementVars.queryType == 'user_search') {
				if ($j.elementVars.defaultSearchRadius >$j.elementVars.mapRadius) {
					$j.elementVars.searchRadius = $j.elementVars.defaultSearchRadius;
				}else{
					$j.elementVars.searchRadius = $j.elementVars.mapRadius;
				}
		    }else{
		    	$j.elementVars.searchRadius = $j.elementVars.mapRadius;
		    }
	    	// update the search results
	    	updateSearchResults();
	    });
	}


	function updateSelectedLocation(locationID, type, distance, Lat, Lng, markerID) {
		// Prepare to get Json Data 
		var server_url = $j.elementVars.AJAXhandler+'?locationID='+locationID+'&type='+type+'&distance='+distance+'&latitude='+$j.elementVars.centerLat+'&longitude='+$j.elementVars.centerLng+'&radius='+$j.elementVars.searchRadius;
			// add time to url to prevent browser caching
			server_url += '&t=' +new Date().getTime();
		
			// other flags
			if ($j.elementVars.lastSearchResultsType != 'APPROXIMATE') server_url += '&lastresults_is_precise=true';
			server_url += '&markerID='+markerID;
			server_url += '&LayoutType='+$j.elementVars.LayoutType;
			
			// add ZIP to url if we're doing ZIP-only searches
			var validZip = isValidPostalCode($j.elementVars.userSpecifiedStartAddress, 'US') || isValidPostalCode($j.elementVars.userSpecifiedStartAddress, 'CA');
			if ($j.elementVars.SearchType =='Postal Code Lookup' && validZip) server_url += '&ziponlysearch='+$j.elementVars.userSpecifiedStartAddress+'&expandziponlysearch='+$j.elementVars.ExpandFailedZipOnlySearch+'&ziponlysearchlimit='+$j.elementVars.SearchMaxMatches;
			
		// Get Json Data
		$j.ajax({
			url: server_url,
			dataType: "json",
			error: function(data) {
				// when server returns error (no matches)
				$j('div#selected-location').html($j.elementVars.emptySelectedLocationMessage);
				$j('div#selected-location-container').show();
			},
			success: function(data) {
				$j('div#selected-location').html(null);
				$j('div#selected-location').html(data['locations']);
				$j('div#selected-location-container').show();
				if(typeof dcsMultiTrack == 'function') {
					 $j.each(data['locationNames'], function(i,LName){
						 dcsMultiTrack('DCS.dcssip', window.location.hostname, 'DCS.dcsuri', '/NearestSelected/'+LName, 'WT.ti', LName);
				
					 });
				}
			}
		});

		// Get driving directions for selected location
		if ($j.elementVars.lastSearchResultsType == 'APPROXIMATE') {
			 // hide directions for approx start location
			$j('#directions-container').hide();
			$j.elementVars.directionsRenderer.setMap(null);
			$j.elementVars.directionsRenderer.setPanel(null);
			$j.elementVars.directionsRendererModal.setPanel(null);
			return;
		}else{
			$j('#directions-container').show();
			var startLatLng = new google.maps.LatLng($j.elementVars.startLat, $j.elementVars.startLng);
			var destLatLng = new google.maps.LatLng(Lat, Lng);
			showDirections(startLatLng, destLatLng);
		}
	}
	
	function updateSearchResults() {
		// Get Json data from server and update list of locations and map
		processJsonData();
	}

	function clearMarkers()
	{
	  	// Clear location markers and the array of location markers
	  	if ($j.elementVars.locationMarkersArray) {
	  		clearOverlays($j.elementVars.locationMarkersArray);
	  		$j.elementVars.locationMarkersArray = [];
	  	}
	}

	function setCenterPointAndMapRadius() {
		// read center points of current map
		$j.elementVars.centerLat=$j.elementVars.map.getCenter().lat();
		$j.elementVars.centerLng=$j.elementVars.map.getCenter().lng();
		
    	// calculate approximate radius of current map (extraneous locations will be filtered later)
		// A better approx map radius would use: var radiusMeters = calcStraightLineDistance($j.elementVars.centerLat, $j.elementVars.centerLng, map.getBounds().getSouthWest().lat(), map.getBounds().getSouthWest().lng());
		// Just use diagonal distance for now (imprecise by nearly a factor of 2x):
		// var radiusMeters = calcStraightLineDistance($j.elementVars.map.getBounds().getNorthEast().lat(), $j.elementVars.map.getBounds().getNorthEast().lng(), $j.elementVars.map.getBounds().getSouthWest().lat(), $j.elementVars.map.getBounds().getSouthWest().lng());
		// Let's try half of diagonal distance:
		var diagMeters = calcStraightLineDistance($j.elementVars.map.getBounds().getNorthEast().lat(), $j.elementVars.map.getBounds().getNorthEast().lng(), $j.elementVars.map.getBounds().getSouthWest().lat(), $j.elementVars.map.getBounds().getSouthWest().lng());
		var radiusMeters = diagMeters/2;
		var radiusMiles = radiusMeters / 1609;
		$j.elementVars.mapRadius = radiusMiles;
	}

	function showDirections(startLatLng, destLatLng) {
		$j.elementVars.directionsRenderer.setMap($j.elementVars.map);
		$j.elementVars.directionsRenderer.setPanel(document.getElementById("directions-panel"));
		$j.elementVars.directionsRendererModal.setPanel(document.getElementById("directionsPopup"));

		// set stroke properties
		//var strokeOptions = {strokeColor:0xFF1111, strokeWeight:12};
		//var options:PolylineOptions =
		//       new PolylineOptions( { strokeStyle: { thickness: 3 }} );
		//   myPolyline.setOptions(options); 
		   
		//$j.elementVars.directionsRenderer.setOptions
		//	({
		//		polylineOptions: {strokeColor:0x000000, strokeWeight:12}
		//	});
		
		
		var request = {
	    	origin:startLatLng, 
	    	unitSystem: google.maps.DirectionsUnitSystem.IMPERIAL,
	    	destination:destLatLng,
	    	travelMode: google.maps.DirectionsTravelMode.DRIVING
	    };
	    $j.elementVars.directionsService.route(request, function(result, status) {
	    	if (status == google.maps.DirectionsStatus.OK) {
	    		$j.elementVars.directionsRenderer.setDirections(result);
	    		$j.elementVars.directionsRendererModal.setDirections(result);
	    	}
	  	});
	}

	function calcStraightLineDistance(lat1, lon1, lat2, lon2) {
		// api v3 currently doesn't support distanceFrom(), so, use Haversine formula to return distance in meters
		var R = 6371000; // meters
		var dLat = (lat2-lat1).toRad();
		var dLon = (lon2-lon1).toRad(); 
		var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
	        Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) * 
	        Math.sin(dLon/2) * Math.sin(dLon/2); 
		var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); 
		var d = R * c;
		return d;
	}

	/** Postal Code Validator */
	function isValidPostalCode(postalCode, countryCode) {
	    switch (countryCode) {
	        case "US":
	            postalCodeRegex = /^([0-9]{5})(?:[-\s]*([0-9]{4}))?$/;
	            break;
	        case "CA":
	            postalCodeRegex = /^([a-zA-Z][0-9][a-zA-Z])\s*([0-9][a-zA-Z][0-9])$/;
	            break;
	        default:
	            postalCodeRegex = /^(?:[A-Z0-9]+([- ]?[A-Z0-9]+)*)?$/;
	    }
	    return postalCodeRegex.test(postalCode);
	}

	/** Round Numbers */
	function roundNumber(number, decimals) {
		return parseFloat(number).toFixed(2);
	}

	/** Convert numeric degrees to radians */
	if (typeof(String.prototype.toRad) === "undefined") {
	  Number.prototype.toRad = function() {
	    return this * Math.PI / 180;
	  }
	}

	//** helper for clearing markers */
	function clearOverlays(overlaysArray) {
			for (var index in overlaysArray) {
		    	overlaysArray[index].setMap(null);
		    }
	}

	function openMarker(overlaysArrayName, key, setCenter, lat, lng){
		// recenter map, if necessary
		if (setCenter) {
			var newCenter = new google.maps.LatLng(parseFloat(lat), parseFloat(lng));
			$j.elementVars.map.setCenter(newCenter);
		}
		var markerArray = eval("$j.elementVars."+overlaysArrayName);
		google.maps.event.trigger(markerArray[key],'click');
	}

	function processJsonData() {
        // Prepare to get Json Data 
        var server_url = $j.elementVars.AJAXhandler+'?query_type='+$j.elementVars.queryType+'&start_lat='+$j.elementVars.startLat+'&start_lng='+$j.elementVars.startLng+'&latitude='+$j.elementVars.centerLat+'&longitude='+$j.elementVars.centerLng+'&radius='+$j.elementVars.searchRadius+'&limit='+$j.elementVars.SearchMaxMatches;
        // add time to url to prevent browser caching
        server_url += '&t=' +new Date().getTime();
        // add ZIP to url if we're doing ZIP-only searches
        var validZip = isValidPostalCode($j.elementVars.userSpecifiedStartAddress, 'US') || isValidPostalCode($j.elementVars.userSpecifiedStartAddress, 'CA');
        if ($j.elementVars.SearchType =='Postal Code Lookup' && validZip) server_url += '&ziponlysearch='+$j.elementVars.userSpecifiedStartAddress+'&expandziponlysearch='+$j.elementVars.ExpandFailedZipOnlySearch+'&ziponlysearchlimit='+$j.elementVars.SearchMaxMatches;
        // other flags
        if ($j.elementVars.lastSearchResultsType != 'APPROXIMATE') server_url += '&lastresults_is_precise=true';
        server_url += '&LayoutType='+$j.elementVars.LayoutType;

		// Get Json Data
		$j.ajax({
			url: server_url,
			dataType: "json",
			error: function(data) {
				clearMarkers();
				// when server returns error (no matches)
				if($j.elementVars.redirectToFullLocator == 'yes')
				{
					window.location = '/Store-Locator/Home.html?userStLoc='+$j.elementVars.userSpecifiedStartAddress+'&x=0&y=0';
					return;
				}
				$j('div#locations').html($j.elementVars.emptyLocationsMessage);
				if ($j.elementVars.queryType == 'user_search') {
					//leave selected location on map change
					$j('div#selected-location').html($j.elementVars.emptySelectedLocationMessage);
					$j('div#selected-location-container').show();
				}
			},
			success: function(data) {
				clearMarkers();
				// init mapBounds
				if(data['locations'].length == 1 && !isMobileDevice() && $j.elementVars.enableSingleResultRedirect == 'Yes')
				{
					var singleLoc = data['locations'][0];
					window.location = 'http://'+singleLoc.Domain;
					return;
				}

				else if($j.elementVars.redirectToFullLocator == 'yes' && !isMobileDevice())
				{
					window.location = '/Store-Locator/Home.html?userStLoc='+$j.elementVars.userSpecifiedStartAddress+'&x=0&y=0';
					return;
				}

				$j.elementVars.mapBounds = $j.elementVars.map.getBounds();

				// Init HTML for Locations List
				//$j('div#locations').html(null);
				if (data['zipSearchWasExpanded']) {
					//add message if we're falling back to geoSearch from zipSearch
					$j('div#locations').append($j.elementVars.zipSearchFallingBackToGeoSearchMessage);
				}
				$j.elementVars.locationsHTML = '';

				// filter locations based on visible map
				if ($j.elementVars.queryType == 'map_change' && $j.elementVars.SearchType != 'Postal Code Lookup') {
					$j.elementVars.filtedLocations = [];
					// On map changes in GeoSearch mode, remove location not in the current map bounds (needed due to imprecision of map radius calculation)
					$j.elementVars.tcount=0;
					$j.each(data['locations'], function(i, location) {
						var aPoint = new google.maps.LatLng(parseFloat(location.Latitude), parseFloat(location.Longitude));
						if ($j.elementVars.mapBounds.contains(aPoint)) {
							$j.elementVars.filtedLocations[$j.elementVars.tcount] = location;
							$j.elementVars.tcount++;
						}
					});					
				}else{
					$j.elementVars.filtedLocations = data['locations'];
				}

				var count = 1;
				
				$j.each($j.elementVars.filtedLocations, function(i, location) {
					var newPoint = new google.maps.LatLng(parseFloat(location.Latitude), parseFloat(location.Longitude));

					var markerInfo = location.infobox_data;
					var markerIconFile = null;
					if ($j.elementVars.useNumberedMarkers == 'Yes') {
						markerIconFile = $j.elementVars.MarkerIconsBasePath+'marker'+count+'.png';
					}
					addMapMarker(location.Latitude,location.Longitude,location.LocationName,markerInfo,false,markerIconFile,$j.elementVars.locationMarkerZindex,'location', location.FranchiseSiteID);

					// if user_search, set map bounds to include nearest location, and update the selected location
					// always extend map bounds in ZIP-only mode
					var extend = false;
					if ($j.elementVars.queryType == 'user_search' && count == 1) {
    					extend = true;
					}
					if ($j.elementVars.SearchType == 'Postal Code Lookup') {
    					extend = true;
					}
					if (extend) {
						// extend only if point is not already in bounds (this avoids having incorrect map size on Approx search results)
						if (!$j.elementVars.mapBounds.contains(newPoint)) {
							$j.elementVars.mapBounds.extend(newPoint);
							$j.elementVars.map.fitBounds($j.elementVars.mapBounds);
						}
						// update the selected location
						if (count == 1) {
							updateSelectedLocation(location.FranchiseSiteID, 'nearest', location.distance, location.Latitude, location.Longitude, location.FranchiseSiteID);
						}
					}
					
				// Set Query Type (subsequent searches will be triggered by map changes, so resorting in PHP is done)
					$j.elementVars.queryType = 'map_change';

				// Build HTML for locations div
					$j.elementVars.locationsHTML += location.list_data.replace("LOCATIONNUMBER", count);
;
					count++;
				});

				// write the HTML to the locations div
				if($j.elementVars.locationsHTML.length > 0)
				{
					$j('div#locations').html(null);
					$j.elementVars.locationsHTML += "<div style=\"clear:both;height:6px;\"></div>";
					$j('div#locations').append($j.elementVars.locationsHTML);
				}
			}
			});
		
	}

	function addMapMarker(Lat,Lng,Title,Info,AutoOpenInfo,CustomIcon,zindex,type,locationID) {
		// Create marker
		var location = new google.maps.LatLng(Lat,Lng);
		var marker = new google.maps.Marker({
			position: location,
			title: Title,
			zIndex: zindex,
			map: $j.elementVars.map
		});

		// set custom icon, if provided
		if(CustomIcon) {
			var icon = new google.maps.MarkerImage(CustomIcon);
			marker.setIcon(icon)
		}

		// push location markers onto array to enable later cleanup
		if (type == 'location') $j.elementVars.locationMarkersArray[locationID] = marker;
		if (type == 'start') $j.elementVars.startMarkersArray.push(marker);

		// Register listener for marker infoWindow
		registerMarkerListener(marker,Info,AutoOpenInfo);
	}

	function registerMarkerListener(marker, Info, AutoOpen) {
	  	// enable open of InfoWindow on user click on marker
		  google.maps.event.addListener(marker, 'click', function() {
			    openInfoWindow(marker, Info);
		  });
		}

	function openInfoWindow(marker, Info) {
		  var markerLatLng = marker.getPosition();

		  $j.elementVars.infowindow.setContent(Info);

		  $j.elementVars.infowindow.setOptions({content:Info, disableAutoPan:true});
		  $j.elementVars.infowindow.open($j.elementVars.map, marker);
		}

	function closeInfoWindow() {
		$j.elementVars.infowindow.close();
	}

	function confirmSearch() {	
		// Set query type (user-initiated searches need no resorting in PHP)
	  	$j.elementVars.queryType = 'user_search';
	  	// Set flag
	  	$j.elementVars.UserHasSearched = true;
	  	// Set Start Point and Marker
	  	setStartPoint(false);
	}

	function translateToZip(results)
	{
		if (results) {
			var rlen = results.length;
			for(var i = 0; i < rlen; i++) {
				var aclen = results[i].address_components.length;
				for (var n = 0; n < aclen; n++) {
					if (results[i].address_components[n].types == 'postal_code') {
						var zip = results[i].address_components[n].long_name;
						if(isValidPostalCode(zip, 'CA') || isValidPostalCode(zip, 'US')) {
							return zip;
						}
					}
				}
			}
		}
		return false;
	}
	
	function processSearchString(searchString) {
		if (searchString.length < 3) {
			alert('Please enter a valid location.');
			return false;
		}
		if ($j.elementVars.SearchType == 'Postal Code Lookup') {
			if (!isValidPostalCode(searchString, 'CA') && !isValidPostalCode(searchString, 'US')) {
				geocoder = new google.maps.Geocoder();
				if (geocoder) {
					var geocodeParams = {address : searchString};
					geocoder.geocode(geocodeParams, function(results, status) {
					    if (status != google.maps.GeocoderStatus.OK) {
					    	return false;
					    }
						var resultZ = translateToZip(results);
						if (resultZ) {
							$j.elementVars.userSpecifiedStartAddress = resultZ;
							confirmSearch();
						} else {
							if($j.elementVars.ExpandFailedZipOnlySearch == 'Yes') {
								$j.elementVars.userSpecifiedStartAddress = searchString;
								confirmSearch();
								return true;
							}
							alert('Unable to determine your Postal Code. Please enter a Postal Code or An Address.');
							return false;
						}
				    });
				} else {
					return false;
				}
			} else {
				$j.elementVars.userSpecifiedStartAddress = searchString;
				confirmSearch();
				return true;
			}
		} else{
			$j.elementVars.userSpecifiedStartAddress = searchString;
			confirmSearch();
			return true;
		}

		// Set query type (user-initiated searches need no resorting in PHP)
  	  	$j.elementVars.queryType = 'user_search';

  		// Set flag
		$j.elementVars.UserHasSearched = true;

	  	// Set Start Point and Marker
		setStartPoint(false);

		return true;
	}

	function userSearch(isOverlay, overlayID, queryStringStartPosition) {
		//hide some elements
		closeInfoWindow();
		$j('div#directions-container').hide();
		
		// Get user query fields
		if (isOverlay) {
			if (overlayID == "searchOverlay"){
				var searchStr = $j.trim($j('#userStartLocationOverlay').val());
				// validate search string
				if (!processSearchString(searchStr)) return;
				// saiena - 13 jul 2010 // $j.elementVars.userSpecifiedStartAddress = $j('#userStartLocationOverlay').val();
				// set value of embeded search field
				$j('#userStartLocation').val(searchStr);
				// close overlay
				$j("#searchOverlay").overlay().close();
			}else if (overlayID == "noDirectionsAlert"){
				var searchStr = $j.trim($j('#userStartLocationDirectionsAlert').val());
				// validate search string
				if (!processSearchString(searchStr)) return;
				// saiena - 13 jul 2010 // $j.elementVars.userSpecifiedStartAddress = $j('#userStartLocationDirectionsAlert').val();
				// set value of embeded search field
				$j('#userStartLocation').val(searchStr);
				// close overlay
				$j("#noDirectionsAlert").overlay().close();
			}
		} else {
			if (queryStringStartPosition) {
				var startLoc = $j.trim(unescape(queryStringStartPosition.replace(/\+/g,' ')));
			} else {
				var searchStr = $j.trim($j('#userStartLocation').val());
				var startLoc = searchStr;
			}
			// validate search string
			if (!processSearchString(startLoc)) {
    			return;
			}
		}
	}

	function setStartPoint(useUserLocation) {
        if(!useUserLocation && ($j.elementVars.userSpecifiedStartAddress == null || $j.elementVars.userSpecifiedStartAddress.length == 0)) {
            return;
        }
        $j.elementVars.geocoder = new google.maps.Geocoder();
        if ($j.elementVars.geocoder) {
            if (useUserLocation) {
                var geocodeParams = {location : $j.elementVars.userLatLng};
            } else {
                var geocodeParams = {address : $j.elementVars.userSpecifiedStartAddress};
            }
            _enableMapIdle = false;
			$j.elementVars.geocoder.geocode(geocodeParams, function(results, status) {
    			_enableMapIdle = true;
	    			if (status == google.maps.GeocoderStatus.OK) {
		    			if(results[0].partial_match) {
			    			return;
		    			}
                        if (useUserLocation) {
                            for (n=0; n < results[0].address_components.length; n++) {
                                if (results[0].address_components[n].types=='street_number') {
                                    $j.elementVars.lastGeoLocateAddress = results[0].address_components[n].long_name;
                                } else if (results[0].address_components[n].types=='route') {
                                    $j.elementVars.lastGeoLocateAddress += ' '+results[0].address_components[n].long_name;
                                } else if (results[0].address_components[n].types=='postal_code') {
                                    $j.elementVars.lastGeoLocateAddress += ', '+results[0].address_components[n].long_name;
                                }
                            }
                            $j('#userStartLocation').attr({value:$j.elementVars.lastGeoLocateAddress});
                        }

					// set map viewport to google's recommended viewport
					$j.elementVars.map.fitBounds(results[0].geometry.viewport);
					// set map center       	  
					$j.elementVars.map.setCenter(results[0].geometry.location);

					// set startLocation
					$j.elementVars.startLat = results[0].geometry.location.lat();
					$j.elementVars.startLng = results[0].geometry.location.lng();

					// set center position for query
					$j.elementVars.centerLat = results[0].geometry.location.lat();
					$j.elementVars.centerLng = results[0].geometry.location.lng();
					
					// Clear existing start position marker and array
					if ($j.elementVars.startMarkersArray) {
						clearOverlays($j.elementVars.startMarkersArray);
						$j.elementVars.startMarkersArray = [];
					}

					if ($j.elementVars.lastSearchResultsType != 'APPROXIMATE') {
						addMapMarker(results[0].geometry.location.lat(),results[0].geometry.location.lng(),$j.elementVars.defaultStartLabel,$j.elementVars.defaultStartMarkerInfo,false,$j.elementVars.customStartMarker,$j.elementVars.startMarkerZindex,'start');
					}
				} else {
					// Geolocate Failed
					$j('div#directions-container').hide();
					$j('div#selected-location').html($j.elementVars.geolocateFailedMessage);
					$j('div#selected-location-container').show();
					$j('div#locations').html($j.elementVars.geolocateFailedMessage);
					$j('div#locations-container').show();
			        }
	        	});
		}
	}

	function toggleTrafficLayer() {
			if ($j.elementVars.trafficLayer.getMap()) {
				$j.elementVars.trafficLayer.setMap(null);
				$j('#toggle_traffic_button').attr({value:'Show Traffic'});
			} else {
				$j.elementVars.trafficLayer.setMap($j.elementVars.map);
				$j('#toggle_traffic_button').attr({value:'Hide Traffic'});
			}
	}

	function readQueryString(ji) {
	    var hu = $j(location).attr('href');
	    var st = hu.split("?");
	    if (typeof(st[1]) == "undefined") return false;
	    var gy = st[1].split("&");
	    for (i=0;i<gy.length;i++) {
	        var ft = gy[i].split("=");
	        if (ft[0] == ji) 
	        {
	        	$j.elementVars.queryStringStartLocation =  $j.trim(ft[1]);
	            return true;
	        }
	    }
	    return false;
	}

	function miscFormSetup() {
		// handle Enter Key press in userStartLocation field
		$j('#userStartLocation').keydown(function(event) {
		  if (event.keyCode == '13') {
		     event.preventDefault();
		     $j('#new-search').focus();
		     userSearch(false);
		   }
		});

		// handle Enter Key press in userStartLocationOverlay field
		$j('#userStartLocationOverlay').keydown(function(event) {
		  if (event.keyCode == '13') {
		     event.preventDefault();
		     $j('#new-search').focus();
		     userSearch(true, 'searchOverlay');
		   }
		});

		// handle Enter Key press in userStartLocationDirectionsAlert field
		$j('#userStartLocationDirectionsAlert').keydown(function(event) {
			  if (event.keyCode == '13') {
			     event.preventDefault();
			     $j('#new-search').focus();
			     userSearch(true, 'noDirectionsAlert');
			   }
			});

		// bind overlay triggers
		$j(function() {
		    $j(".modalInput").live("click", function(e) {
		        e.preventDefault();
		        var divtofind = $j(this).attr("rel");
		        $j(divtofind).overlay({
					// some mask tweaks
					mask: {
						color: '#ebecff',
						loadSpeed: 200,
						opacity: 0.9
					},
					closeOnClick: false
		        });
		        var api = $j(divtofind).overlay();
		        api.load();
		        if (divtofind == '#noDirectionsAlert') $j("#userStartLocationDirectionsAlert").focus();
		        return false;
		    });
		});
		
	

	}
	


