if(typeof Prototype == 'undefined' || !Prototype.Version.match("1.6"))
	throw("Core library requires Prototype library >= 1.6.0");

function trim(stringToTrim) {
	if(stringToTrim == null) return null;
	return stringToTrim.replace(/^\s+|\s+$/g,"");
}
function sticky_dropdown(search_type){
	if (search_type == "store_search") {
		$('store_finder').addClassName('fs_active');
		if ($('book_app'))
		$('book_app').addClassName('no_dropdown');
		$('close_sf').show();
	}
	else if (search_type == "book_appointment") {
		$('book_app').addClassName('ba_active');
		$('store_finder').addClassName('no_dropdown');
		$('close_ba').show();
	}
}
function close_sticky(search_type){
	if (search_type == "store_search") {
		$('store_finder').removeClassName('fs_active');
		if ($('book_app'))
		$('book_app').removeClassName('no_dropdown');
		$('close_sf').hide();
	}
	else if (search_type == "book_appointment") {
		$('book_app').removeClassName('ba_active');
		$('store_finder').removeClassName('no_dropdown');
		$('close_ba').hide();
}
}
var gAlertBoxWidth = 585;
var gAlertBoxHeight = 310;
var gStoreTypeOptician = 1;
var gStoreTypeHearingCentre = 2;
var gMultipleStoresHtmlFormat = "<li><a class=\"search_list_item\" href=\"{p}?search_criteria={0}&latitude={1}&longitude={2}&store_type={3}&default_search_criteria_head=Enter+postcode%2Ftown\">{0} ></a></li>";;

var GoogleStoreFinderService = Class.create({
	initialize: function(locale) {
		this.locale = locale;
	},
	searchResultsToJSON: function(searchResults) {
		var json = "";
		
		if (searchResults.length == 0)
		{
		    json = "{geo_locations:{geo_location:[]}}";
		}
		else if (searchResults.length == 1)
		{
		    json = "{geo_locations:{geo_location:[";
		    json += "{name: '" + searchResults[0].name.replace("'","") + "', lat: '" + searchResults[0].lat + "', lng: '" + searchResults[0].lng + "'}";
		    json += "]}}";
		}
		else if (searchResults.length > 1)
		{
            json = "{suggestions:{suggestion:[";
            
            searchResults.each(function(item) {
                json += "{name: '" + item.name.replace("'","") + "', lat: '" + item.lat + "', lng: '" + item.lng + "'},";
            });

            // Remove the final comma as this causes problems with IE.
            json = json.substring(0, json.length - 1);

            json += "]}}";
		}

		return json;
	},
	searchStores: function(observerElementId, storeType, searchCriteria) {
        
        var geocoder = new google.maps.Geocoder();

        var ADDRESS_COMPONENT_TYPE = "COUNTRY";
 
        var countryCode = this.locale.getCountryCode();

        var searchCriteriaWithWildcard = searchCriteria;
        var searchCriteriaWithCountryCode = searchCriteriaWithWildcard + ", " + this.locale.getAdditionalSearchTerms();
        var searchResults = new Array();
        var self = this;
        var json = "";

        geocoder.geocode({ 'address': searchCriteriaWithCountryCode }, function(results, status) {

            if (status != google.maps.GeocoderStatus.OK && status != google.maps.GeocoderStatus.ZERO_RESULTS) {
            	$(observerElementId).fire("store_finder:searched_stores_failed", { responseText: gStoreFinderMockServiceResponseText, storeType: storeType, searchCriteria: searchCriteria });
            } else {

            	var lastName = '';
                for (var i = 0; i < results.length; i++)
                {
                    // Loop through the address components for each geocode result and check the country component to stop results from other countries being returned.
                    results[i].address_components.each(function(addressComponent) { 
                        addressComponent.types.each(function(addressComponentType) {
                            if (addressComponentType.toUpperCase() == ADDRESS_COMPONENT_TYPE && addressComponent.short_name.toUpperCase() == countryCode)
                            {
                            	//	don't return the same text twice in a row
                            	var thisName = results[i].formatted_address.substr(0, results[i].formatted_address.lastIndexOf(","));
                            	if(thisName != lastName) {
                            		
                            		var searchResult = {name: thisName, lat: results[i].geometry.location.lat(), lng: results[i].geometry.location.lng() };
                            		searchResults.push( searchResult );
                            	}
                            	lastName = thisName;


                            }
                        });
                    });
                }
            }

            json = self.searchResultsToJSON(searchResults);

            $(observerElementId).fire("store_finder:searched_stores", { responseText: json, storeType: storeType, searchCriteria: searchCriteria });
        });
      }
	
});

var gStoreFinderMockServiceResponseText = "";
var gStoreFinderMockServiceSimulateServerFailure = false;

var StoreFinderMockService = Class.create({
	initialize: function() {
	},
	searchStores: function(observerElementId, storeType, searchCriteria) {
		if(gStoreFinderMockServiceSimulateServerFailure) {
			$(observerElementId).fire("store_finder:searched_stores_failed", { responseText: gStoreFinderMockServiceResponseText, storeType: storeType, searchCriteria: searchCriteria });
		} else {
			$(observerElementId).fire("store_finder:searched_stores", { responseText: gStoreFinderMockServiceResponseText, storeType: storeType, searchCriteria: searchCriteria });
		}
	}
});

/*
StoreFinderService

Class to issue a request to the store finder proxy via AJAX and fire a success/fail event

* can have two radio buttons (opticians and hearing centres) and a submit button
* can have two submit buttons(opticians and hearing centres)
* is designed by CSS
* uses Lightbox to show alerts

Assumptions:
* Prototype is included 
* Lightbox is included
* Global gSearchFormElementId is set to an existing form element

Form Example 1 (radio buttons):
> ...
> <form action="http://testing/results.html.php" method="get" name="store_search" id="store_search">
>	<input type="radio" class="optician_button" name="store_type" value="1" checked />
>	<input type="radio" class="hearing_centre_button" name="store_type" value="2" />
>	<input value="Near postcode or suburb/town" type="text" name="search_criteria" class="search_criteria"  />
>	<input type='hidden' value='Near postcode or suburb/town' name='default_search_criteria' id='default_search_criteria' class="default_search_criteria">
>	<a href="#" class="submit_button" id="store_submit">SUBMIT</a>
> </form>	
> ...

Form Example 2 (action buttons):
> ...
> <form action="http://testing/results.html.php" method="get" name="store_search" id="store_search">
>	<input type='hidden' value='1' name='store_type'>
>	<input name="search_criteria" value="Near postcode or suburb/town" type="text" class="search_criteria"  />
>	<div id="search_btn1" class="optician_button"><a href="#">OPT</a></div>
>	<div id="search_btn2" class="hearing_centre_button"><a href="#">HEAR</a></div>
>	<input type='hidden' value='Near postcode or suburb/town' name='default_search_criteria' id='default_search_criteria' class="default_search_criteria">
> </form>
> ...

Lightbox Alert Examples:
> ...
> <div id="alert_no_search_criteria" style="display:none">nothing entered</div>
> <div id="alert_no_results" style="display:none">no results</div>
> <div id="alert_many_results" style="display:none">
> 	<div id="results_container"></div>
> </div>
> <div id="alert_ajax_error" style="display:none">ajax error</div>
> ...
*/
var gStoreFinderServiceUrl = "/stores/lookup.php";

if (window.location.protocol == 'https:') {
	gStoreFinderServiceUrl = "/stores/lookup_secure.php";
} 

var StoreFinderService = Class.create({
	initialize: function() {
	},
	searchStores: function(observerElementId, storeType, searchCriteria) {

		// Issue AJAX request to lookup service
		new Ajax.Request(gStoreFinderServiceUrl, {
			method: 'get',
			parameters: $(observerElementId).serialize(true),
			onSuccess: function(transport) {
				$(observerElementId).fire("store_finder:searched_stores", { responseText: transport.responseText, storeType: storeType, searchCriteria: searchCriteria });
			},
			onFailure: function(transport) { 
				$(observerElementId).fire("store_finder:searched_stores_failed", { responseText: transport.responseText, storeType: storeType, searchCriteria: searchCriteria });
			}
		});
	}
});

var StoreFinderNotificationServiceDropdown = Class.create({
	initialize: function(
		searchFormElementId,
		storeFinderInstructionsElementId, 
		storeFinderInstructionsNotFoundElementId,
		storeFinderInstructionsMultipleElementId,
		storeFinderInstructionsErrorElementId,
		storeFinderInstructionsStartedSearchElementId
	) {
		this.searchFormElementId = searchFormElementId;
		this.storeFinderInstructionsElementId = storeFinderInstructionsElementId;
		this.storeFinderInstructionsNotFoundElementId = storeFinderInstructionsNotFoundElementId;
		this.storeFinderInstructionsMultipleElementId = storeFinderInstructionsMultipleElementId;
		this.storeFinderInstructionsErrorElementId = storeFinderInstructionsErrorElementId;
		this.storeFinderInstructionsStartedSearchElementId = storeFinderInstructionsStartedSearchElementId;
		this.searchPath = $(this.searchFormElementId).getAttribute("action");
		
		this.showDefaultView();
	},
	showAlert: function(elementId, searchCriteria) {
		[this.storeFinderInstructionsElementId, 
		 this.storeFinderInstructionsNotFoundElementId,
		 this.storeFinderInstructionsMultipleElementId,
		 this.storeFinderInstructionsErrorElementId,
		 this.storeFinderInstructionsStartedSearchElementId].each(function(instructionsElementId) {
			 $(instructionsElementId).hide();
		 });
		
		var searchCriteriaElements = $(elementId).getElementsByClassName('search_criteria');
		if(searchCriteriaElements)
			$A(searchCriteriaElements).each(function(searchCriteriaElement) {
				 $(searchCriteriaElement).update(searchCriteria);
			});
		
		$(elementId).show();
	},
	showDefaultView: function() {
		// Show the instructions by default
		this.showAlert(this.storeFinderInstructionsElementId, null);
		// Remove the large dropdown class, if assigned
		$(this.searchFormElementId).up().up().removeClassName('dropdown_large');
		if($("store_finder_standard"))
			$("store_finder_standard").removeClassName('dropdown_large');
		// Show the search form
		$(this.searchFormElementId).show();
	},
	alertStartedSearch: function(searchCriteria) {
		this.showAlert(this.storeFinderInstructionsStartedSearchElementId, searchCriteria);
		//$(this.searchFormElementId).hide();
	},
	alertNoSearchCriteria: function(searchCriteria) {
	},
	alertNoResults: function(storeType, searchCriteria) {
		this.showAlert(this.storeFinderInstructionsNotFoundElementId, searchCriteria);
	},
	alertDuplicateResults: function(target, storeType, searchCriteria, suggestions) {

		// Set up the 'try another search' elements to return the user back to the default view
		var tryAnotherSearchElements = $(this.storeFinderInstructionsMultipleElementId).getElementsByClassName('try_another_search');
		if(tryAnotherSearchElements) {
			$A(tryAnotherSearchElements).each(function(tryAnotherSearchElement) {
				$(tryAnotherSearchElement).observe("click", function(event) {
					self.showDefaultView();
				});
			});
		}

		this.html = "";
		var multipleStoresHtmlFormat = "<li><a class=\"search_list_item\" href=\"{p}?search_criteria={0}&latitude={1}&longitude={2}&store_type={3}&default_search_criteria_head=Enter+postcode%2Ftown\">{0} ></a></li>";
		var self = this;
		suggestions.each(function(suggestion) {
			var temp = gMultipleStoresHtmlFormat;
			temp = temp.replace("{p}", self.searchPath);
			temp = temp.replace(/\{0\}/g, suggestion.name);
			temp = temp.replace('{1}', suggestion.lat);
			temp = temp.replace('{2}', suggestion.lng);
			temp = temp.replace('{3}', storeType);
			self.html += temp;
		});
			
		var multipleResultsContainerElement = $(this.storeFinderInstructionsMultipleElementId).getElementsByClassName('multiple_results_container')[0];
		$(multipleResultsContainerElement).update("<ul class='multiple_results'>" + this.html + "</ul>");
		
		// Hide the form
		$(this.searchFormElementId).hide();
		
		// Add a class to the dropdown window to make it large
		$(this.searchFormElementId).up().up().addClassName('dropdown_large');
		if($("store_finder_standard"))
			$("store_finder_standard").addClassName('dropdown_large');
		
		this.showAlert(this.storeFinderInstructionsMultipleElementId, searchCriteria);
	},
	alertTransportError: function(storeType, searchCriteria) {
        this.showAlert(this.storeFinderInstructionsErrorElementId, searchCriteria);
	}
});

var StoreFinderNotificationServiceLightbox = Class.create({
	initialize: function(
		alertNoSearchCriteriaElementId,
		alertNoResultsElementId,
		alertDuplicateResultsElementId,
		alertDuplicateResultsContainerElementId,
		alertTransportErrorElementId) {
	
		this.alertNoSearchCriteriaElementId = "alert_no_search_criteria";
		if(alertNoSearchCriteriaElementId != null)
			this.alertNoSearchCriteriaElementId = alertNoSearchCriteriaElementId;
		
		this.alertNoResultsElementId = "alert_no_results";
		if(alertNoResultsElementId != null)
			this.alertNoResultsElementId = alertNoResultsElementId;
	
		this.alertDuplicateResultsElementId = "alert_many_results";
		if(alertDuplicateResultsElementId != null)
			this.alertDuplicateResultsElementId = alertDuplicateResultsElementId;
		
		this.alertDuplicateResultsContainerElementId = "results_container";
		if(alertDuplicateResultsContainerElementId != null)
			this.alertDuplicateResultsContainerElementId = alertDuplicateResultsContainerElementId;
		
		this.alertTransportErrorElementId = "results_container";
		if(alertTransportErrorElementId != null)
			this.alertTransportErrorElementId = alertTransportErrorElementId;
	
		Event.observe(window, 'load', function(event) {
			Lightbox.init();
			
			$$(".close_lightbox").each(function(closeLightboxElement) {
				closeLightboxElement.observe("click", function() {Lightbox.hideBox()});
			});
		});
	},
	alertStartedSearch: function(searchCriteria) {
	},
	alertNoSearchCriteria: function(searchCriteria) {
		this.showAlert(this.alertNoSearchCriteriaElementId, searchCriteria);
	},
	alertNoResults: function(storeType, searchCriteria) {
		this.showAlert(this.alertNoResultsElementId, searchCriteria);
	},
	alertDuplicateResults: function(target, storeType, searchCriteria, suggestions) {
		this.html = "";
		var self = this;
		suggestions.each(function(suggestion) {
			var temp = gMultipleStoresHtmlFormat;
			temp = temp.replace("{p}", self.searchPath);
			temp = temp.replace(/\{0\}/g, suggestion.name);
			temp = temp.replace('{1}', suggestion.lat);
			temp = temp.replace('{2}', suggestion.lng);
			temp = temp.replace('{3}', storeType);
			self.html += temp;
		});
		$(this.alertDuplicateResultsElementId).getElementsBySelector("#" + this.alertDuplicateResultsContainerElementId)[0].update(this.html);
		this.showAlert(this.alertDuplicateResultsElementId, searchCriteria);		
	},
	alertTransportError: function(storeType, searchCriteria) {
		this.showAlert(this.alertTransportErrorElementId, searchCriteria);
	},
	showAlert: function(elementId, searchCriteria) {
		var self = this;
		$$(".searched_criteria").each(function(searchedCriteriaElement) {searchedCriteriaElement.update(searchCriteria)});
		Lightbox.showBoxByID(elementId, gAlertBoxWidth, gAlertBoxHeight);
	},
	hideAlert: function() {
		Lightbox.hideBox();
	}
});

/*
	StoreFinder
	
	Main class to handle a store locator in a page. A store locator:
	* can have two radio buttons (opticians and hearing centres) and a submit button
	* can have two submit buttons(opticians and hearing centres)
	* is designed by CSS
	* uses Lightbox to show alerts

	Assumptions:
	* Basic html/id/classname framework below is adhered to
	* Lightbox is included

	Form Example 1 (radio buttons):
	> ...
	> <form action="http://testing/results.html.php" method="get" name="store_search" id="store_search">
	>	<input type="radio" class="optician_button" name="store_type" value="1" checked />
	>	<input type="radio" class="hearing_centre_button" name="store_type" value="2" />
	>	<input value="Near postcode or suburb/town" type="text" name="search_criteria" class="search_criteria"  />
	>	<input type='hidden' value='Near postcode or suburb/town' name='default_search_criteria' id='default_search_criteria' class="default_search_criteria">
	>	<a href="#" class="submit_button" id="store_submit">SUBMIT</a>
	> </form>	
	> ...
	
	Form Example 2 (action buttons):
	> ...
	> <form action="http://testing/results.html.php" method="get" name="store_search" id="store_search">
	>	<input type='hidden' value='1' name='store_type'>
	>	<input name="search_criteria" value="Near postcode or suburb/town" type="text" class="search_criteria"  />
	>	<div id="search_btn1" class="optician_button"><a href="#">OPT</a></div>
	>	<div id="search_btn2" class="hearing_centre_button"><a href="#">HEAR</a></div>
	>	<input type='hidden' value='Near postcode or suburb/town' name='default_search_criteria' id='default_search_criteria' class="default_search_criteria">
	> </form>
	> ...
	
	Lightbox Alert Examples:
	> ...
	> <div id="alert_no_search_criteria" style="display:none">nothing entered</div>
	> <div id="alert_no_results" style="display:none">no results</div>
	> <div id="alert_many_results" style="display:none">
	> 	<div id="results_container"></div>
	> </div>
	> <div id="alert_ajax_error" style="display:none">ajax error</div>
	> ...
*/
var StoreFinderV6 = Class.create({
	initialize: function(
		storeType,
		storeFinderService, 
		searchFormElementId,
		notificationService) {
	
		this.storeType = storeType;
		this.notificationService = notificationService;

		// Get all form elements
		this.storeFinderService = storeFinderService;
		this.searchFormElementId = "store_search";
		if(searchFormElementId != null)
			this.searchFormElementId = searchFormElementId;
		
		this.submitButtonElement = $(this.searchFormElementId).getElementsByClassName("find")[0];
		this.searchCriteriaElement = $(this.searchFormElementId).getElementsByClassName("search_criteria")[0];
		this.latElement = $(this.searchFormElementId).getElementsByClassName("lat")[0];
		if(this.latElement == null)
			this.latElement = $("lat");
		this.lngElement = $(this.searchFormElementId).getElementsByClassName("lng")[0];
		if(this.lngElement == null)
			this.lngElement = $("lng");
		this.defaultSearchCriteria = $(this.searchFormElementId).getElementsByClassName("default_search_criteria")[0].value;

		// Set up click observer(s) based on whether radio buttons are used or not
		$(this.submitButtonElement).observe('click', this.onSubmitSearch.bind(this));
		
		// Observer focus and keyboard events for the text box
		var self = this;
		this.searchCriteriaElement.observe('focus', function(event) {
			// Clear the textbox on focus if nothing has been entered yet
			if(self.defaultSearchCriteria == event.element().value)
				event.element().value = "";
		});
		this.searchCriteriaElement.observe('keydown', function(event) {
			// Auto submit when return is hit
			if(event.keyCode == Event.KEY_RETURN) {
				self.onSubmitSearch(event);
			}
		});
		
		var self = this;
		
		document.observe("store_finder:searched_stores", function(event) {
			if(event.element().identify() != self.searchFormElementId)
				return;
			try {
				var responseData = event.memo.responseText.evalJSON();
				
				if(responseData.suggestions)
					self.notificationService.alertDuplicateResults(self, event.memo.storeType, event.memo.searchCriteria, $A(responseData.suggestions.suggestion));
				else if(responseData.stores) {

					switch($A(responseData.stores.store).length) {
						case 0:		self.notificationService.alertNoResults(event.memo.storeType, event.memo.searchCriteria);	break;
						default:	self.submitForm(self, event.memo.storeType, event.memo.searchCriteria);	break;
					}
				}
				else if(responseData.geo_locations) {
					switch($A(responseData.geo_locations.geo_location).length) {
						case 0:		self.notificationService.alertNoResults(event.memo.storeType, event.memo.searchCriteria);	break;
						default:	
							self.latElement.value = responseData.geo_locations.geo_location[0].lat.substring(0, 19);
							self.lngElement.value = responseData.geo_locations.geo_location[0].lng.substring(0, 19);
							self.submitForm(self, event.memo.storeType, event.memo.searchCriteria);	
							break;
					}
				}
			} catch(e) {
				self.notificationService.alertTransportError(event.memo.storeType, event.memo.searchCriteria);
			}
		});
		
		document.observe("store_finder:searched_stores_failed", function(event) {
			self.alertTransportError(event.memo.storeType, event.memo.searchCriteria);
		});
	},
	onSubmitSearch: function(event) {
		$(this.searchFormElementId).show();
		event.stop();
		
		//	strip out the unique form field identifiers before we push the
		//	form elements to the store searching routine so that the correct
		//	field names are passed when the form is serialized. We uniquely
		//	identify forms by prefixing their fields with 'slba_X_' where X is
		//	any single character
		$$('input.slba_input_field').each(function(sfel) {
			if(sfel.name.substr(0,5)=='slba_' && sfel.name.substr(6,1)=='_')
				sfel.name = sfel.name.substr(7);
		});

		this.searchStores(this.searchCriteriaElement.value);
	},
	isSearchCriteriaSpecified: function(searchCriteria) {
		return (trim(searchCriteria) != "" && trim(searchCriteria) != this.defaultSearchCriteria);
	},
	searchStores: function(searchCriteria) {
		if(!this.isSearchCriteriaSpecified(searchCriteria))
			this.notificationService.alertNoSearchCriteria(searchCriteria);
		else {
			this.notificationService.alertStartedSearch(searchCriteria);
			this.storeFinderService.searchStores(this.searchFormElementId, this.storeType, searchCriteria);
		}
	},
	submitForm: function(target, storeType, searchCriteria) {
		
		$(this.searchFormElementId).submit();
	}
});

