(function ($) {	
	var SL = {
		filePath: '',
		lastPostcode: '',
		cachedStoreData: {},
		currentStoreData: {},
		appointmentOpen: false,
		fieldValues: {},

		trackEvent: function () {
			try {
//console.log(arguments);
				pageTracker._trackEvent.apply(pageTracker, arguments);
			} catch (e) {
//console.log(e);
			}
		},

		trackFieldData: function (name, value) {
			if (value === '' || name in SL.fieldValues && SL.fieldValues[name] === value) {
				return;
			}
			SL.fieldValues[name] = value;
			SL.trackEvent('Contact Form Field Data', name, value);
		},

		init: function (filePath) {
			this.filePath = filePath;
			// Workaround for IE6 not rendering flash in hidden elements (needed for sIFR)
			$(window).load(function () {
				if (!SL.appointmentOpen) {
					$('.hidden').hide();
				}
			});
			
			$('#submit_postcode').click(function(e){
				e.preventDefault();
				SL.searchPostcode();
				return false; 
			});
			$('#submitAnyway').click(function(e){
				e.preventDefault();
				SL.searchPostcode();
				return false; 
			});
			// not required any more
//			$('#swap_inputs').click(function(e){
//				e.preventDefault();
//				// hide any 'old' jquery validation errors
//				$('#select_input span.error').hide();
//				SL.swapInputs();
//				return false; 
//			});
			
			$('#form_store_locator').change(function () {
				var $this = $(this),
				selected = $this.find('option:selected');
				selected.trigger('showStoreInMap');
			});

			$('#form_postcode').keyup(this.searchPostcode);
			$('#stateSearch').click(this.searchState);
			$('#form_store_locator').change(this.showAddress);
			$('#form_store_locator').change(this.showAppointmentDays);
			$('#form_store_locator').change(this.showAppointmentTimes);
			$('#form_appointment_day').change(this.showAppointmentTimes);
			/**
			 * Enable keypress entering of postcode form
			 */
			$("#postcode_form").keypress(function(e){
				if (e.which == 13) {
					if (!$('#postcode_input').is(':hidden')) {
						SL.searchPostcode();
						return false;
					}
				}
			});

			// Handle default values
			if ($('#form_postcode').val()) {
				$('#form_postcode').keyup();
			}
			if ($('#user_postcode').val()) {
				SL.searchPostcode();
			} else {
				$('#user_postcode').val('Please enter your postcode');
			}
			$('#user_postcode').focus(function(){
				if($('#user_postcode').val() == 'Please enter your postcode'){
					$('#user_postcode').select();
					$('#user_postcode').val('');
				}
			})
			$('#user_postcode').blur(function(){
				if($('#user_postcode').val() == ''){
					$('#user_postcode').val('Please enter your postcode');
				}
			})
			$('.appointmentYesNo:checked').click();
			
			// Add event tracking
			$('input:text, input:radio, input:checkbox, textarea').blur(function () {
				var $this = $(this),
					name = $this.attr('name'),
					value = $this.val();
				SL.trackFieldData(name, value);
			});
			$('select').change(function () {
				var $this = $(this),
					name = $this.attr('name'),
					value = $this.find('option:selected').text();
				SL.trackFieldData(name, value);
			});
		},

		searchPostcode: function () {
			if($('#user_postcode').val()){
				var postcode_val = $('#user_postcode').val();				
			} else {
				var postcode_val = $('#form_postcode').val();
			}
			if (!/^\d{4}$/.test(postcode_val)) {
				return;
			}
			// test for NT 0800 postcodes - which do not have any Optus Business stores
			if ($('#user_postcode').val()) {
				if (/^08\d{2}$/.test(postcode_val)) {
					if ($('#no_stores_in_state_block').is(':hidden')) {
						$('#no_stores_in_state_block').show();
						return;
					}
				}
			}
			// hide the 'no stores' prompt
			if (!$('#no_stores_in_state_block').is(':hidden')) {
				$('#no_stores_in_state_block').hide();
			}

			if($('#selected_store').val()){
				var store_id_val = $('#selected_store').val();
			}
			SL.lastPostcode = postcode_val;
			$.getJSON(SL.filePath + '/contactus/findStoresNearPostcode.json', {postcode:postcode_val,store_id:store_id_val}, SL.populateStores);
		},

		searchState: function (e) {
			e.preventDefault();
			SL.trackEvent('Contact Form', 'Field Data', 'View all stores in state', $('#form_postcode').val());
			if (!SL.lastPostcode) {
				alert('Please enter a postcode.');
				return;
			}
			var pcode = $('#form_postcode').val().substr(0, 1),
				states = {
					1: 'NSW|ACT',
					2: 'NSW|ACT',
					3: 'VIC',
					4: 'QLD',
					5: 'SA',
					6: 'WA'
				},
				data = {};
			if (states.hasOwnProperty(pcode)) {
				data.state = states[pcode];
				$.getJSON(SL.filePath + '/contactus/findStore.json', data, SL.populateStores);
			} else {
				alert('Sorry, there are no business specialist stores available in your state.')
			}
		},

		populateStores: function (data) {
			if (!data || !data.stores) {
				var msg = data.error || 'There was an error locating your nearest store. There may not be any business specialist stores in your area.';
				alert(msg);
				return;
			}
			if (data.stores == SL.cachedStoreData) {
				return;
			}
			SL.cachedStoreData = data.stores;
			SL.currentStoreData = {};
			var list = $('#form_store_locator').empty();
			if (data.stores.length !== 1) {
				$('<option/>').val('').text('Please select a store').attr('selected', 'selected').appendTo(list);
			}
			var selected_store;
			if(data.store_id > 0){
				var selected_store = data.store_id;
			}

			if (data.stores.length !== 1) {
	  		// sort stores by exactly matching user postcode query at top, then store.name A-Z
				data.stores.sort(SL.sortStoreObjects);
			}
			var group = false;
			var nearby = false;
			var last_store_index = data.stores.length - 1;
			
			$.each(data.stores, function (i, store) {
				if (data.stores.length !== 1) {
					// if first item in list has a postcode matching the users query
					// and that postcode does not match the postcode of the last store in the list
					// then we are going to group stores into two lists
					// 1. those that exactly match the postcode
					// 2. those 'nearby'
					// Otherwise we just use a flat list without grouping
					if(i == 0)
					{
						if(store.postcode == SL.lastPostcode && data.stores[last_store_index].postcode != SL.lastPostcode)
						{
							// create 'exact match' group
							group = $('<optgroup/>').attr('label', SL.lastPostcode + " postcode stores").appendTo(list);
						}
						else
						{
							// create 'nearby' group
							group = $('<optgroup/>').attr('label', "Nearby stores").appendTo(list);
							nearby = true;
						}
						
						if(store.id == selected_store){
							var option = $('<option/>').val(store.id).attr('selected', 'selected').html(store.name);
							(group) ? option.appendTo(group) : option.appendTo(list);
						} else {
							var option = $('<option/>').val(store.id).html(store.name);
							(group) ? option.appendTo(group) : option.appendTo(list);
						}
					}
					else
					{
						if(group)
						{
							if( nearby || ( !nearby && store.postcode == data.stores[0].postcode ) )
							{
								// join onto the 'nearby' or 'exact match' group... depending on what the first store created
								if(store.id == selected_store){
									$('<option/>').val(store.id).attr('selected', 'selected').html(store.name).appendTo(group);
								} else {
									$('<option/>').val(store.id).html(store.name).appendTo(group);
								}
							}
							else
							{
								if(!nearby)
								{
									// create 'nearby' group
									group = $('<optgroup/>').attr('label', "Nearby stores").appendTo(list);
									nearby = true;
								}
								
								// join onto the 'nearby' group
								if(store.id == selected_store){
									$('<option/>').val(store.id).attr('selected', 'selected').html(store.name).appendTo(group);
								} else {
									$('<option/>').val(store.id).html(store.name).appendTo(group);
								}
							}
						}
						else
						{
							// join onto list that does not contain groups
							if(store.id == selected_store){
								$('<option/>').val(store.id).attr('selected', 'selected').html(store.name).appendTo(list);
							} else {
								$('<option/>').val(store.id).html(store.name).appendTo(list);
							}
						}
					}

				} else {
					$('<option/>').val(store.id).attr('selected', 'selected').html(store.name).appendTo(list);
				}
				SL.currentStoreData[store.id] = store;
			});
			if ($('#form_appointment_yes').attr('checked')) {
				$('#form_appointment_yes').click();
			}
			list.triggerHandler('change');
			
			if($('#user_postcode').val()){
				SL.swapInputs();
				SL.loadMap(data);
			}
			if($('#form_store_locator').val()){
				SL.showAppointmentDays();
			}
		},
		
		sortStoreObjects: function( a, b ){
			// all stores are sorted A-Z
			// stores that match the postcode exactly will be listed first A-Z
			if(a.postcode == SL.lastPostcode && b.postcode != SL.lastPostcode)
			{
				return -1;
			}
			else if ( a.postcode != SL.lastPostcode && b.postcode == SL.lastPostcode)
			{
				return 1;
			}
			else // either both stores DO or DON't match the postcode... sort A-Z
			{
				if(a.name == b.name)
				{
					return 0;
				}
				return (a.name < b.name ) ? -1 : 1;
			}
		},
		
		swapInputs: function(){
			if($('#select_input_heading').hasClass('fauxHiddenSifr'))
			{
				// sifr won't convert a hidden element, so need to hide it off the screen until the first swap, then we can toggle it normally.
				$('#select_input_heading').css('display', 'none').removeClass('fauxHiddenSifr');
			}
			$('#postcode_input').toggle();
			$('#postcode_input_heading').toggle();
			$('#select_input').toggle();
			$('#select_input_heading').toggle();
		},
		
		swapMapPromo: function(){
			$('#map').show();
			$('#promo').hide();
			$('#map-rightcol').show();
			$('#promo-rightcol').hide();
			if($('#form_store_locator').val()){
				// load in the first popup
				selected = $('#form_store_locator').find('option:selected');
				selected.trigger('showStoreInMap');
			}
		},
		
		zoomInOutControlsSetButtonStyle: function(button)
		{
		  button.style.textDecoration = "none";
		  button.style.color = "#FFD100";
		  button.style.backgroundColor = "#000000";
		  button.style.font = "small Arial";
		  button.style.border = "1px solid #FFFFFF";
		  button.style.padding = "5px";
		  button.style.marginBottom = "3px";
		  button.style.textAlign = "center";
		  button.style.width = "6em";
		  button.style.cursor = "pointer";
		},
			
		/**
		 * The zoomInOutControls adds controls to the map that simply
		 * allow the user to zoom in or out. This constructor takes
		 * the control DIV as an argument.
		 */
		zoomInOutControls: function (controlDiv, map) {
		  // Set CSS styles for the DIV containing the control
		  // Setting padding to 5 px will offset the control
		  // from the edge of the map
		  controlDiv.style.padding = '5px';
		
		  var zoomInDiv = document.createElement("div");
		  SL.zoomInOutControlsSetButtonStyle(zoomInDiv);
		  controlDiv.appendChild(zoomInDiv);
		  zoomInDiv.appendChild(document.createTextNode("Zoom In"));
			google.maps.event.addDomListener(zoomInDiv, 'click', function() {
		    var zoomLevel = map.getZoom();
		    if (zoomLevel >= 22) {
		      map.setZoom(14);
		    }
				else
				{
					map.setZoom(zoomLevel + 1);
				}
		  });			
		
		  var zoomOutDiv = document.createElement("div");
		  SL.zoomInOutControlsSetButtonStyle(zoomOutDiv);
		  controlDiv.appendChild(zoomOutDiv);
		  zoomOutDiv.appendChild(document.createTextNode("Zoom Out"));
			google.maps.event.addDomListener(zoomOutDiv, 'click', function() {
		    var zoomLevel = map.getZoom();
		    if (zoomLevel <= 0) {
		      map.setZoom(14);
		    }
				else
				{
					map.setZoom(zoomLevel - 1);
				}
		  });		
		},
		
		loadMap: function(data){
			initialize(data);
			var infoWindow;
			
			function initialize(data){
				var myOptions = {
					zoom: 14,
					/**
					* centered on Sydney by default
					* 
					* once each marker is inserted, the latlang bounds of the map is then extended, 
					* therefore the map will zoom in or out depending on the amount of markers inserted
					*/
					center: new google.maps.LatLng(-33.894072, 151.210155),
					navigationControl: false, // disables the default zoom in/out, move and center controls
					mapTypeId: google.maps.MapTypeId.ROADMAP
				}
				
				var map = new google.maps.Map(document.getElementById("map"), myOptions);

			  // Create the DIV to hold the control and
			  // call the zoomInOutControls() constructor passing
			  // in this DIV.
			  var zoomControlDiv = document.createElement('DIV');
			  var zoomControl = new SL.zoomInOutControls(zoomControlDiv, map);
			  zoomControlDiv.index = 1;
			  map.controls[google.maps.ControlPosition.TOP_LEFT].push(zoomControlDiv);			
				
				infoWindow = new google.maps.InfoWindow();
				markers = [];
				setMarkers(map, data);
				SL.swapMapPromo();
			}
			
			function clearLocations(){
				infoWindow.close();
				for (var i = 0; i < markers.length; i++) {
					markers[i].setMap(null);
				}
				markers.length = 0;
			}
			
            function setMarkers(map, data){
				clearLocations();
				var bounds = new google.maps.LatLngBounds();
                for (var i = 0; i < data.stores.length; i++) {
                    var shop = data.stores[i];
					var user_postcode = data.user_postcode;
                    var latLng = new google.maps.LatLng(shop.lat, shop.lon);
					createMarker(latLng, shop, map, user_postcode);
					bounds.extend(latLng);
                }
				map.fitBounds(bounds);
            }
			
			function createMarker(latlng, data, map, user_postcode) {
				var shopName = data.name;
				var shopAddress = data.address + ', ' + data.state;
				var shopId = data.id; 
				var shopPhone = data.number;
				var html = "<div id=\"business_details\" class=\"row\"><p><b>" + shopName + "</b><br/>" + shopAddress + "<br/>" + shopPhone + "</p><p style=\"margin:0;\"><a href="+SL.filePath+"/contactus/appointment?postcode="+user_postcode+"&store_id="+shopId+"><img src="+SL.filePath+"/_images/contactus/btn_make_appt_infowindow.png"+" alt=\"Make an appointment\" width=\"132\" height=\"16\" /></a></p></div>";
				
                var image = new google.maps.MarkerImage(SL.filePath+'/_images/contactus/icon-maps-optus.png',
					// The Optus marker is width: 47px & height: 31px.
	                new google.maps.Size(47, 31),
	                new google.maps.Point(0, 0),
	                new google.maps.Point(0, 31));
	            var shape = {
	                    coord: [1, 1, 1, 47, 31, 47, 31, 1],
	                    type: 'poly'
                };
				var marker = new google.maps.Marker({
					position: latlng,
                    map: map,
                    icon: image,
                    shape: shape,
					title: shopName
				});
				google.maps.event.addListener(marker, 'click', function() {
					infoWindow.setContent(html);
					infoWindow.open(map, marker);
					SL.showStoreInDropdown(shopId);
				});

				$('#form_store_locator option[value="'+ shopId +'"]').bind('showStoreInMap', function(e) {
					infoWindow.setContent(html);
					infoWindow.open(map, marker);
				});
				
				markers.push(marker);
			}
		},
		
		showStoreInDropdown: function( shopId ) {
			$('#form_store_locator').val(shopId);
		},

		showAddress: function () {
			var val = $('#form_store_locator').val(),
				store, address;
			if (!val) {
				$('#form_store_address').empty();
				$('#form_li_store_address').hide();
				$('#form_store_email').val('');
				return;
			}
			store = SL.currentStoreData[val];
			address = store.address + '<br />' +
				(store.address2 ? store.address2 + '<br />' : '') +
				store.suburb + ' ' + store.postcode + ' ' + store.state + '<br /><br />' +
				'Ph: ' + store.number;
			$('#form_store_address').html(address);
			$('#form_li_store_address').show();
			$('#form_store_email').val(store.email);
		},

		hideAppointments: function () {
			SL.appointmentOpen = false;
			$('#form_li_appointment_day, #form_li_appointment_time').hide().find('select').empty();
		},

		showAppointmentDays: function () {
			SL.appointmentOpen = true;
			var list = $('#form_appointment_day').empty(),
				store = SL.currentStoreData[$('#form_store_locator').val()];
			if (!store || store == 'Please select a store') {
				$('<option/>').text('Please select a store above').appendTo(list);
				return;
			} else {
				$('<option value="">Please select a day</option>').appendTo(list);
			}
			if (store.hoursMonWed) {
				$('<option value="Monday" hours="MonWed">Monday</option>').appendTo(list);
				$('<option value="Tuesday" hours="MonWed">Tuesday</option>').appendTo(list);
				$('<option value="Wednesday" hours="MonWed">Wednesday</option>').appendTo(list);
			}
			if (store.hoursThurs) {
				$('<option value="Thursday" hours="Thurs">Thursday</option>').appendTo(list);
			}
			if (store.hoursFri) {
				$('<option value="Friday" hours="Fri">Friday</option>').appendTo(list);
			}
			if (store.hoursSat) {
				$('<option value="Saturday" hours="Sat">Saturday</option>').appendTo(list);
			}
			if (store.hoursSun) {
				$('<option value="Sunday" hours="Sun">Sunday</option>').appendTo(list);
			}
			list.change();
		},

		showAppointmentTimes: function () {
			var list = $('#form_appointment_time').empty(),
				day = $('#form_appointment_day option:selected'),
				hours = 'hours' + day.attr('hours'),
				store = SL.currentStoreData[$('#form_store_locator').val()];
			if (!store || !store[hours]) {
				$('<option/>').text('Please select a store and day above').appendTo(list);
				return;
			} else {
				$('<option value="">Please select a time</option>').appendTo(list);
			}
			$.each(store[hours], function (i, time) {
				$('<option/>').val(time).text(time).appendTo(list);
			});
		}
	};
	window.storeLocator = SL;
})(jQuery);
