LocationFinder = new function() {
// Private properties
	var self = this;
	var mapBufferPx = 25;
	var gmap;
	var gcoder;
	var idBase;
	var currentCenter;
	var useDialog = false;
	var showSearchOrigin = true;
	var locationTypes = new Object();
	var locations = new Array();

	// Public properties
	this.version = "1.0";
	this.startLat = -25.00;
	this.startLng = 133.00;
	this.startZoom = 3;
	this.forceDefaultCountry = false;
	this.defaultCountry = '';
	this.defaultCCTLD = '';

	//Private methods
	function init() {
	}

	function gcodeCallback(data) {
		if(!data) {
			self.showMessage('Sorry, the address/postcode entered could not be found.');
			setSubmitButtonActive();
		}
		// Use the following for full AJAX (not yet implemented)
		//currentCenter = data;
		//$.ajax({url : '/system/inc/custom/locationFinderAjaxHandler.php?lat=' + data.lat() + '&lng=' + data.lng(), type : 'GET', dataType : 'json', success : function(data){updateResults(data);}, error: handleError,  timeout : 10000});
		var latField = document.getElementById(idBase + ':lat');
		var lngField = document.getElementById(idBase + ':lng');
		if(latField && lngField) {
			latField.disabled = false;
			lngField.disabled = false;
			latField.value = data.lat();
			lngField.value = data.lng();
			latField.form.submit();
		}
		else {
			document.location.href = document.location.pathname + '?lat=' + data.lat() + '&lng=' + data.lng() + '#Map';
			setSubmitButtonActive();
		}
		return;
	}

	function updateResults(data) {
		setLocations(data);
		updateList();
		document.location.hash = '#' + idBase;
	}

	function updateList() {
		var i, loc, item;
		var list = document.getElementById(idBase + ':list');
		list.innerHTML = '';
		for(i=0; i < locations.length; i++) {
			loc = locations[i];

			item = document.createElement('DT');
			item.innerHTML = '' + String('ABCDEFGHIJKLMNOPQRSTUVWXYZ').charAt(i) + '.';
			list.appendChild(item);

			item = document.createElement('DD');
			item.innerHTML = '<span class="locationName">' + loc['name'] + '</span>' + '<table width="100%"><tr><td width="50%">' + loc['shop'] + ' ' + loc['street'] + '<br />' + loc['suburb'] + '<br />' + loc['state'] + ' ' + loc['postcode'] + '</td><td width="50%"><strong>Phone:</strong> ' + loc['phone'] + '<br /><strong>Fax:</strong> ' + loc['fax'] + '</td></tr></table>';
			list.appendChild(item);
		}
	}

	function updateMap(data) {
		var i, loc, point, marker, icon, baseIcon;
		var minLat, maxLat, minLng, maxLng;
		var minLatLng, maxLatLng, bounds, zoom;
		var minLatLngPx, maxLatLngPx

		gmap.clearOverlays();

		// Show search origin
		if(self.showSearchLocation) {
			icon = new GIcon();
			icon.image = 'http://maps.google.com/mapfiles/kml/pal4/icon47.png';
			icon.size = new GSize(16, 16);
			icon.iconAnchor = new GPoint(8,8);
			gmap.addOverlay(new GMarker(currentCenter, {'icon': icon, 'clickable' : false, 'title': 'Your location'}));
		}
		minLat = maxLat = currentCenter.lat();
		minLng = maxLng = currentCenter.lng();

		// Show locations found
		baseIcon = new GIcon();
		baseIcon.image = 'http://www.google.com/intl/en_ALL/mapfiles/marker.png';
		baseIcon.iconSize =  new GSize(20, 34);
		baseIcon.iconAnchor = new GPoint(10,34);
		baseIcon.shadow = 'http://www.google.com/intl/en_ALL/mapfiles/shadow50.png';

		for(i=0; i < data['locations'].length; i++) {
			loc = data['locations'][i];
			loc['detailsElement'] = getDetailsElementByIndex(i);
			point = new GLatLng(loc['latitude'], loc['longitude']);
			var locType = locationTypes[loc['locationTypeID']];
			if(locType && locType['iconURL']) {
				icon = new GIcon();
				icon.image = locType['iconURL'];
				icon.iconSize = new GSize(locType['iconWidth'], locType['iconHeight']);
				icon.iconAnchor = new GPoint(locType['iconAnchorX'], locType['iconAnchorY']);
				if(locType['iconShadowURL']) {
					icon.shadow = locType['iconShadowURL'];
				}
			}
			else {
				icon = new GIcon(baseIcon);
				icon.image = 'http://www.google.com/intl/en_ALL/mapfiles/marker' + String('ABCDEFGHIJKLMNOPQRSTUVWXYZ').charAt(i) + '.png';
			}
			marker = new GMarker(point, {'icon': icon, 'clickable' : true, 'title': loc['name']});
			loc['marker'] = marker;
			if(self.useDialog) {
				GEvent.addListener(marker, "click", function(x){return function(){
					showLocationDetails(x);
				}}(i));
			}

			if(locType && locType['iconURL'] && locType['iconHighlightURL']) {
				GEvent.addListener(marker, "mouseover", getEventHandler('mouseover', i));
				GEvent.addListener(marker, "mouseout", getEventHandler('mouseout', i));
				GEvent.addListener(marker, "click", getEventHandler('click', i));
			}

			gmap.addOverlay(marker);
			minLat = Math.min(minLat, point.lat());
			maxLat = Math.max(maxLat, point.lat());
			minLng = Math.min(minLng, point.lng());
			maxLng = Math.max(maxLng, point.lng());
		}

		if(data['locations'].length == 0) {
			minLatLng = new GLatLng(currentCenter.lat() - data['distance_degrees'], currentCenter.lng() - data['distance_degrees']);
			maxLatLng = new GLatLng(currentCenter.lat() + data['distance_degrees'], currentCenter.lng() + data['distance_degrees']);
			bounds = new GLatLngBounds(minLatLng, maxLatLng)
			zoom = gmap.getBoundsZoomLevel(bounds);
			gmap.setCenter(currentCenter, zoom);
			self.showMessage('Sorry, no locations were found matching your search. Please check your spelling, or try searching a neighbouring town or suburb.');
		}
		else {
			minLatLng = new GLatLng(minLat, minLng);
			maxLatLng = new GLatLng(maxLat, maxLng);
			bounds = new GLatLngBounds(minLatLng, maxLatLng)
			zoom = gmap.getBoundsZoomLevel(bounds);
			gmap.setCenter(bounds.getCenter(), zoom);
			minLatLngPx = gmap.fromLatLngToDivPixel(minLatLng);
			maxLatLngPx = gmap.fromLatLngToDivPixel(maxLatLng);
			if(maxLatLngPx.y < mapBufferPx) { gmap.setZoom(--zoom); }
		}
	}

	function handleError(xhr, e, o) {
		var errmsg = 'There was a technical error. Please try again.';
		if(xhr.responseText) errmsg += "\nError code: " + xhr.status;
		self.showMessage(errmsg);
	}

	function getEventHandler(type, idx) {
		var handler;
		switch(type) {
		case 'click':
			handler = function(){self.focusLocation(idx, true);};
			break;
		case 'mouseover':
			handler = function(){self.focusLocation(idx, false);};
			break;
		case 'mouseout':
			handler = function(){self.clearFocus(false);};
			break;
		}
		return handler;
	}

	function showLocationDetails(idx) {
		var info = document.createElement('DIV');
		info.innerHTML = document.getElementById(idBase+':list').getElementsByTagName('DD').item(idx).innerHTML;
		
		gmap.openInfoWindow(
			new GLatLng(locations[idx].latitude, locations[idx].longitude),
			info
		);
	}

	function getDetailsElementByIndex(idx) {
		var container = document.getElementById(idBase + ':list');
		if(!container) return null;
		var items = container.getElementsByTagName('DD');
		if(!items || items.length == 0 ) return null;
		var element = items.item(idx);
		return element;
	}

	function setSubmitButtonWaiting() {
		var submitButton = document.getElementById(idBase + ':submit');
		if(!submitButton) return;
		submitButton.oldValue = submitButton.value;
		submitButton.value = 'Searching...';
		submitButton.disbled = true;
		submitButton.style.cursor = 'wait';
	}

	function setSubmitButtonActive() {
		var submitButton = document.getElementById(idBase + ':submit');
		if(!submitButton) return;
		submitButton.value = submitButton.oldValue ? submitButton.oldValue : 'Search';
		submitButton.disbled = false;
		submitButton.style.cursor = 'auto';
	}

	//Public methods
	this.createMap = function(baseName, opts) {
		idBase = baseName;
		var gmapContainer = document.getElementById(idBase + ':map');
		gmap = new GMap2(gmapContainer);
		gmap.enableContinuousZoom();
		//gmap.setMapType(G_HYBRID_MAP);
		gmap.addControl(new GSmallMapControl());
		gmap.addControl(new GMapTypeControl());
		currentCenter = new GLatLng(self.startLat, self.startLng)
		gmap.setCenter(currentCenter, self.startZoom);

		// Handle options
		self.useDialog = (opts['useDialog'] && opts['useDialog']!='false');
		self.showSearchOrigin = (opts['showSearchOrigin'] && opts['showSearchOrigin']!='false');
	}

	this.setCenter = function(lat, lng) {
		currentCenter = new GLatLng(lat, lng);
		gmap.setCenter(currentCenter);
	}

	this.setLocations = function(data) {
		locations = data['locations'];
		updateMap(data);
	}

	this.setLocationTypes = function(data) {
		locationTypes = data;
	}

	this.go = function() {
		self.showMessage('');
		var addressField = document.getElementById(idBase + ':query');
		var address = (addressField) ? addressField.value.replace(/(^\s*)|(\s*$)/g,'') : '';
		if(!address) return false;
		if (self.forceDefaultCountry && (address.toLowerCase() != self.defaultCountry.toLowerCase())) {
			address += ' ' + self.defaultCountry;
		}
		gcoder = new GClientGeocoder();
		gcoder.getLatLng(address, gcodeCallback);
		setSubmitButtonWaiting();
		return true;
	};

	this.showMessage = function(message) {
		var messageBox = document.getElementById(idBase + ':jsMessage');
		if(!messageBox) return false;
		messageBox.style.display = message ? 'block' : 'none';
		messageBox.innerHTML = String(message);
		return true;
	};

	this.clearMessage = function() {
		return self.showMessage('');
	}

	this.focusLocation = function(idx, sticky) {
		for(i = 0; i < locations.length; i++) {
			var loc = locations[i];
			var locType = locationTypes[loc['locationTypeID']];
			if(i == idx && !(loc['current'] && sticky)) {
				if(sticky) {
					loc['current'] = true;
					//GoogleMap.bounceMarker(loc['marker'], 20, 0.4);
				}
			 	if(!/\bcurrent\b/.test(loc['detailsElement'].className)) {loc['detailsElement'].className += ' current';}
				if(locType && locType['iconHighlightURL']) {loc['marker'].setImage(locType['iconHighlightURL']);}
			}
			else {
				if(sticky) {loc['current'] = false;}
				if(!loc['current']) {
					loc['detailsElement'].className = loc['detailsElement'].className.replace(/\bcurrent\b/, '').replace(/(^\s*)|(\s*$)/g, '');
					if(locType && locType['iconURL']) {loc['marker'].setImage(locType['iconURL']);}
				}
			}
		}
	}

	this.clearFocus = function(clearSticky) {
		self.focusLocation(-1, clearSticky);
	}

	init();
	return this;
}();

