VenueChooser = function(form, venueConfigs, maxVenues){

	// venue chooser ranking constants
	// overal weighting adjsutments - mutiplies score prior to sorting (1 = neutral, < 1 decrease weight, > 1 increase weight)
	var CAPACITY_WEIGHT = 1;
	var DISTANCE_WEIGHT = 1.5;
	var FACILITIES_WEIGHT = 0.5;
	
	// distance score calculation adjustments
	var DISTANCE_UNDER_WEIGHT = 1;
	var DISTANCE_OVER_WEIGHT = 50; // make bigger for more difference between over / under
	var DISTANCE_SCORING_ADJ = 6000; // make bigger for higher scores overall	
	var self = this;
	self._venueConfigs = null;
	self._form = null;
	self._localSearch = null;
	self._recommendedVenues = null;
	self._oldUrl = null;
	self._maxVenues = null;
	self._previousFieldValues = null;
	self._requestedCapacityType = null;
	
	
	// constructor
	self.init = function(form, venueConfigs, maxVenues){
		
		self._venueConfigs = venueConfigs;
		self._form = form;
		self._form.addListener(self);
		self._localSearch = new GlocalSearch();
		self._recommendedVenues = [];
		self._requestedCapacityType = 'Meeting'
		self._oldUrl = $('#compareVenuesButton').attr('alt');
		if (maxVenues) {
			self._maxVenues = maxVenues;
		}
		else {
			self._maxVenues = 5;
		}
	}
	
	self.notifyChange = function(){
		var iNumberAttendees = '';
		var iNumberWeddingAttendees = '';
		var postcode = '';
		var iaFacilities = '';

		if (self._form.getInstance('iNumberAttendees')) {
	  		iNumberAttendees = self._form.getInstance('iNumberAttendees').getValue();
	  	}
		if (self._form.getInstance('iNumberWeddingAttendees')) {
	  		iNumberWeddingAttendees = self._form.getInstance('iNumberWeddingAttendees').getValue();
	  	}
	
		if (self._form.getInstance('sGeoProximity')) {
	  		postcode = self._form.getInstance('sGeoProximity').getValue();
	  	}
		if (postcode == '' && self._form.getInstance('iRegionPreference')) {
			postcode = self._form.getInstance('iRegionPreference').getValue();
		}		
		
		if (self._form.getInstance('iaFacilities')) {
	  		iaFacilities = self._form.getInstance('iaFacilities').getValue();
	  	}				
		
		// check that field values have actually changed		
		var currentFieldValues = '';
		currentFieldValues += iNumberAttendees;
		currentFieldValues += iNumberWeddingAttendees;
		currentFieldValues += postcode;
		if (iaFacilities) {
			currentFieldValues += iaFacilities.join();
	  	}
		if (currentFieldValues == '') {
			$('#venueChooserSidebar').hide();
			return;
		}

		if (self._previousFieldValues != currentFieldValues) {
			// initial sidebar is rendered with css class hidden to make it hidden by default
			$('#venueChooserSidebar').removeClass('hidden');
			$('#venueChooserSidebar').show();
			self._previousFieldValues = currentFieldValues;
			// clear current rec venues list
			self._recommendedVenues = [];
			
			// loop thru all venues in config, calcualte percent scores for various criteria
			$.each(self._venueConfigs, function(){
				var venueConfig = this;
				
				// calculate percent score for capacity
				var venuesFailingCapacity = Array();				
				var requestedCapacity = parseInt(iNumberAttendees);								
				if (!requestedCapacity){
					requestedCapacity = parseInt(iNumberWeddingAttendees);
					self._requestedCapacityType = 'Wedding';
				}

				if (requestedCapacity) {
					var eventCapacity = null;
					switch (self._requestedCapacityType){
						case 'Meeting':
							eventCapacity = venueConfig.eventCapacityMeeting;
							break;
						case 'Wedding':
							eventCapacity = venueConfig.eventCapacityWedding;
							break;							
					}
					var difference = eventCapacity - requestedCapacity;
					
					if (difference < 0) {
						var score = Math.abs(difference) * DISTANCE_OVER_WEIGHT;
					}
					else {
						var score = Math.abs(difference) * DISTANCE_UNDER_WEIGHT;
					}
					
					var percentage = 100 * Math.pow(10, -(score / DISTANCE_SCORING_ADJ));
					venueConfig.scoreCapacity = percentage;
				}
				
				// calculate percent score for facilities				
				var facilitiesRequested = iaFacilities;
				var facilitiesMatched = 0;
				
				if (facilitiesRequested && facilitiesRequested.length > 0) {
					$.each(facilitiesRequested, function(){
						if ($.inArray(this.toString(), venueConfig.facilities) > -1) {
							facilitiesMatched++;
						}
					});
					venueConfig.scoreFacilities = (facilitiesMatched / facilitiesRequested.length) * 100;
				}
				else {
					// nothing requested, so perfect score
					venueConfig.scoreFacilities = 100;
				}
				
				self._recommendedVenues.push(venueConfig);
			});
			
			// calculate distance score
			if (postcode) {
				self._localSearch.setSearchCompleteCallback(null, function(){
					if (self._localSearch.results[0] && self._localSearch.results[0].lat && self._localSearch.results[0].lng) {
						var resultLat = self._localSearch.results[0].lat;
						var resultLng = self._localSearch.results[0].lng;
						
						var point = new GLatLng(resultLat, resultLng);
						
						// Deal with returned data - point.lat() & point.lng()
						var query = {
							lat: point.lat(),
							lng: point.lng()
						} // pass onto function to cal distance...
						//pass geoCode'd postcode to distance calculator
						self._calculateDistanceScore(query, postcode);
					}
				});
//				self._localSearch.execute(postcode + ", EU");
				self._localSearch.execute(postcode + ", UK");
//				self._localSearch.execute(postcode);
			}
			else {
				// if not calcultaing distance, update rec venue sidebar now 
				// (otherwise sidebar is updated at end of distance callback function)
				self._updateRecommendedVenues();
			}
		}
	}
	
	// replace rec venues sidebar with current rec venues list
	self._updateRecommendedVenues = function(){
	
		// logic for ranking various scores. Currently just sum them and order descending
		self._recommendedVenues.sort(function(a, b){
			return ((b.scoreCapacity * CAPACITY_WEIGHT) + (b.scoreFacilities * FACILITIES_WEIGHT) + (b.scoreDistance * DISTANCE_WEIGHT)) - ((a.scoreCapacity * CAPACITY_WEIGHT) + (a.scoreFacilities * FACILITIES_WEIGHT) + (a.scoreDistance * DISTANCE_WEIGHT));
		});
		
		// truncate rec venues list to maxVenues size
		self._recommendedVenues.length = self._maxVenues;
		
		
		var listItems = '<ul id="venueChooser">';
//		console.log('******************************************************************************************************************************************************************************************');
		$(self._recommendedVenues).each(function(){
			
			var checked = '';
			if (this.selected) {
				checked = 'checked="checked"';
			}
			
			self.selectVenueToCompare(this.venueId, this.selected);
			if (this.venueId != 'grandCentralHotel'){
			listItems += '<li class="section">';
			listItems += '<a href="javascript:TB_special(\'/conferences-and-meetings/plan-and-request-a-proposal/venue-information?venueId=' + this.venueId + '&KeepThis=true&TB_iframe=true&height=auto&width=700\')" class="thickbox"><span title="Hotel Information Overview">?</span><img src="' + this.image + '"></a>';
			listItems += '<a href="javascript:TB_special(\'/conferences-and-meetings/plan-and-request-a-proposal/venue-information?venueId=' + this.venueId + '&KeepThis=true&TB_iframe=true&height=auto&width=700\')" class="thickbox action">' + this.title + ', ' + this.city + ' (' + this.region + ')</a>';
			listItems += '<a href="javascript:;" class="buttonBottomLeft" id="selectVenue_1_' + this.venueId + '">1st&nbsp;Choice</a>';
			listItems += '<a href="javascript:;" class="buttonBottomRight" id="selectVenue_2_' + this.venueId + '">2nd&nbsp;Choice</a>';
			listItems += '<label for="compareVenue_' + this.venueId + '"><input type="checkbox" id="compareVenue_' + this.venueId + '" name="compareVenues[]" value="' + this.venueId + '" ' + checked + ' />Select to compare</label>';
			listItems += '</li>';
			}
		});
		
		listItems += '</ul>';		
		
		// replace html list with current rec venue list		
		if ($('#venueChooserList').html() != listItems) {
			//			$('#venueChooserList').slideUp('Slow');
			$('#venueChooserList').html(listItems);
			$('#venueChooser').jScrollPane({scrollbarWidth:15, dragMinHeight:99, dragMaxHeight:99, wheelSpeed:36});
			//			$('#venueChooserList').slideDown('Slow');
		}
		
		// removes class on first li element for styling reasons
		$('#venueChooser').children(":first").removeClass("section");
					
		// bind onchange to all the checkboxes we just created
		$("#venueChooser [@id ^= 'compareVenue_']").each(function(){
			$(this).bind('change', function(){
				var selected = false;
				var venueId = $(this).attr('id').substring(13);
				if ($(this).attr('checked')) {
					selected = true;
				}
				self.selectVenueToCompare(venueId, selected);
			});
		});
		
		// bind onClick to all select venue buttons
		$("#venueChooser [@id ^= 'selectVenue_']").each(function(){				
			$(this).bind('click', function(){
				var choiceNumber = $(this).attr('id').substring(12, 13);
				var venueId = $(this).attr('id').substring(14);
				self.selectVenue(venueId, choiceNumber);
			});
		});		
	}
	
	// mark a venue as selected to compare
	self.selectVenueToCompare = function(venueId, selected){
//		var queryString = '&requestedCapacityType=eventCapacity' + self._requestedCapacityType + '&venueIds=';
		var queryString = '?requestedCapacityType=eventCapacity' + self._requestedCapacityType + '&venueIds=';
		// loop thru cenueConfigs and find the right one
		// rebuild veneuId querystring						
		$.each(self._recommendedVenues, function(){
			if (this.venueId == venueId) {
				this.selected = selected;
			}
			if (this.selected) {
				queryString += this.venueId + ',';
				$('#compareVenue_' + this.venueId).attr("checked", "checked");
			}
			else{
				$('#compareVenue_' + this.venueId).attr("checked", "");
			}
		});		
		
//		$('#compareVenuesButton').attr('alt', self._oldUrl + queryString);

		$('#compareVenuesButton').attr('alt', self._oldUrl + queryString + '&TB_iframe=true&height=500&width=700');
	}
	
	self._calculateDistanceScore = function(query, postcode){
		var maxDistance = 0;
		
		Number.prototype.toRad = function(){ // convert degrees to radians
			return this * Math.PI / 180;
		}
		
		// Haversine Forumla
		function getDistance(lat1, lon1, lat2, lon2){
			var R = 3959; // miles
			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;
		}
		
		// @todo rewrite loop to use jquery each function
		for (var i = 0; i < self._recommendedVenues.length; i++) {
			self._recommendedVenues[i].dist = Math.round(getDistance(query.lat, query.lng, self._recommendedVenues[i].lat, self._recommendedVenues[i].lng));
			if (self._recommendedVenues[i].dist > maxDistance) {
				maxDistance = self._recommendedVenues[i].dist
			}
		}
		
		$.each(self._recommendedVenues, function(){
			this.scoreDistance = 100 - ((this.dist / maxDistance) * 100);
		});
		
		self._updateRecommendedVenues();
	}
	
	// select a venue as choice 1 or 2
	self.selectVenue = function(venueId, choiceNumber){
		self._form.getInstance('bVenueUndecided').setValue(false);
		var venueTitle = self._venueConfigs[venueId].title;
		var venueCity = self._venueConfigs[venueId].city;
		switch (choiceNumber) {
			case '1':				
				self._form.getInstance('iVenueChoice1').setValue(venueTitle + ', ' + venueCity);
				alert (venueTitle + ' selected as 1st choice');
				break;
			case '2':
				self._form.getInstance('iVenueChoice2').setValue(venueTitle + ', ' + venueCity);
				alert (venueTitle + ' selected as 2nd choice');
				break;
		}		
	}
	
	self.init(form, venueConfigs, maxVenues);
}



