// JavaScript Document

function Facilities__criteria() {
	
	//AA Star rating & type
	var starRatingSelect = $('aaStarRating');
	var starRatingMatch = starRatingSelect.value.match(/^([a-z]+)([0-9]+)$/);
	if(starRatingMatch != null) {
		this.starRatingType = starRatingMatch[1];
		this.starRating = new Number(starRatingMatch[2]);
	}
	else {
		this.starRatingType = 'white';
		this.starRating = 0;
	}
	
	//Food award rating
	var foodAwardSelect = $('restarauntAward');
	var foodAwardMatch = foodAwardSelect.value.match(/^([0-9]+)$/);
	if(foodAwardMatch != null) this.foodRating = new Number(foodAwardMatch[1]);
	else this.foodRating = 0;
	
	//Features
	var featureInputs = $$('#criteriaContent ul li input');
	this.features = new Object();
	for(var i = 0; i < featureInputs.length; i++) {
		var featureID = featureInputs[i].id.substr(7);
		this.features[featureID] = featureInputs[i].checked;
	}
	
	/**
	 * Tells us if a given hotel meets this criteria instance.
	 */
	this.hotelMeets = function (hotel) {
		try {
			for (featureID in this.features) {
				if(!this.features[featureID]) continue; //Feature isn't relevant
				if(hotel.select('div#'+hotel.id+'Feature'+featureID+' img').length == 0) {
					//console.log(hotel.id+' doesn\'t have an iconn for feature '+featureID);
					return false;
				}
				if(hotel.select('div#'+hotel.id+'Feature'+featureID+' img')[0].src.match(/facilities-cross\.png$/) != null) {
					//console.log(hotel.id+" doesn't have required feature "+featureID);
					return false;
				}
			}
			
			var starRatingCont = hotel.select('.hotelAward')[0];
			var foodRatingCont = hotel.select('.hotelAward')[1];
			
			var hotelFoodRating = foodRatingCont.select('img').length;
			if(hotelFoodRating < this.foodRating) {
				//console.log(hotel.id+" doesn't meet food rating");
				return false;
			}
			
			var hotelStarRating = starRatingCont.select('img').length;
			var hotelStarRatingType = hotelStarRating > 0 ? (starRatingCont.select('img')[0].src.match(/aa-star_sm\.png$/) != null ? 'white' : 'red')  : 'white';
			if(hotelStarRating == this.starRating) {
				//Tie-break on white OR red
				if(this.starRatingType == 'red' && hotelStarRatingType == 'white') {
					//console.log(hotel.id+" has equivalent AA star count, but not red");
					return false;
				}
			}
			else if(hotelStarRating < this.starRating) {
				//console.log(hotel.id+" doesn't meet star rating"); 
				return false;
			}
			
			//console.log(hotel.id+" meets the criteria");
			return true;
		}
		catch(e) {
			console.log(e);
			console.log(hotel);
		}
	}
	
	/**
	 * Tells us how many of the criteria that this hotel meets.
	 * Used when hotels don't meet the criteria, to determine which
	 * most closely matches
	 */
	this.scoreHotel = function(hotel) {
		var score = 0;
		for (featureID in this.features) {
			if(!this.features[featureID]) continue; //Feature isn't relevant
			if(hotel.select('div#'+hotel.id+'Feature'+featureID+' img').length > 0) {
				if(hotel.select('div#'+hotel.id+'Feature'+featureID+' img')[0].src.match(/facilities-cross\.png$/) == null) {
					score++;
				}
			}
		}
		
		var starRatingCont = hotel.select('.hotelAward')[0];
		var foodRatingCont = hotel.select('.hotelAward')[1];
		
		var hotelFoodRating = foodRatingCont.select('img').length;
		if(hotelFoodRating >= this.foodRating) {
			score++;
		}
		
		var hotelStarRating = starRatingCont.select('img').length;
		var hotelStarRatingType = hotelStarRating > 0 ? (starRatingCont.select('img')[0].src.match(/aa-star_sm\.png$/) != null ? 'white' : 'red')  : 'white';
		if(hotelStarRating == this.starRating) {
			//Tie-break on white OR red
			if((this.starRatingType == 'red' && hotelStarRatingType == 'red')|| this.starRatingType == 'white') {
				score++;
			}
		}
		else if(hotelStarRating > this.starRating) {
			score++;
		}
		
		return score;
	}
}

/**
* Used to score hotels as a tie-breaker
* when multiple hotels meet criteria.
* All features and stars/awards are worth one point.
* Having red AA stars is worth an additional half a point
* to nudge ahead of a hotel with identical features 
* but white stars, but stay behind a hotel with
* more features / stars.
*/
function Facilities__scoreHotel(hotel) {
	var score = 0;
	var features = hotel.select('div.hotelFacility img');
	for(var i = 0; i < features.length; i++) {
		if(features[i].src.match(/facilities-tick\.png$/) != null) score++;	
	}
	
	var starRatingCont = hotel.select('.hotelAward')[0];
	var foodRatingCont = hotel.select('.hotelAward')[1];
	var foodRating = foodRatingCont.select('img').length;
	var starRating = starRatingCont.select('img').length;
	var starRatingType = starRating > 0 ? (starRatingCont.select('img')[0].src.match(/aa-star_sm\.png$/) != null ? 'white' : 'red')  : 'white';
	
	score += foodRating;
	score += starRating;
	if(starRatingType == 'red') score += 0.5;
	return score;
}

var Facilities__morphTime = 0.6;
var Facilities__hotelsMorphing = 0;
var Facilities__hotelsCollapsing = 0;
var Facilities__sortedHotelArray = null;
var Facilities__queuedMorphs = new Array();
function Facilities__criteriaChanged(evnt) {
	var criteria = new Facilities__criteria();
	Facilities__criteriaChangedWorker(criteria);
}
//Event.observe(document, 'dom:loaded', Facilities__criteriaChanged);

function Facilities__collapseExpandedHotels(collapseFunc) {
	var hotelArray = $$('ul#facilitiesHotelList li');
	var hotelsExpanded = new Array();
	for(var i = 0; i < hotelArray.length; i++) {
		var moreContainer = hotelArray[i].select('div.hotelMore')[0];
		if(moreContainer.style.display != "none") {
			//We need a further check that this hotel isn't 
			//in the process of collapsing.
			//The easyest way of implimenting this seems to
			//be a check on the booking widget, as this
			//is removed instantly when a hotel collapses
			//(thanks to IE6).
			var bookingTeaserCont = moreContainer.select('div.bookingTeaserCont')[0];
			var bookingTeaserLoading = bookingTeaserCont.style.background.indexOf("/images/ajax-loader-big.gif") != -1;
			if((bookingTeaserCont.select('div.bookingPhoneCont').length == 0 
					&& bookingTeaserCont.select('div.booking').length == 0)
			   && !bookingTeaserLoading) continue;
			hotelsExpanded.push(hotelArray[i]);
		}
	}	
	
	if(hotelsExpanded.length > 0) {
		Facilities__hotelsCollapsing = hotelsExpanded.length;
		for(var i = 0; i < hotelsExpanded.length; i++) {
			var moreContainer = hotelsExpanded[i].select('div.hotelMore')[0];
			Effect.BlindUp(moreContainer, {afterFinish:collapseFunc});
			var bookingDiv = moreContainer.select('.hotelMoreRight .bookingTeaserCont')[0];
			bookingDiv.innerHTML = '&nbsp;';
		}
	}
	
	return hotelsExpanded.length;
}

function Facilities__criteriaChangedWorker(criteria) {	
	if(Facilities__hotelsMorphing > 0 || Facilities__hotelsCollapsing > 0) {
		//Queue the animation
		Facilities__queuedMorphs.push(criteria);
		return;
	}
	
	//Are any hotels expanded?	
	var collapseFunc = Facilities__collapseFinished.bind(criteria);
	if(Facilities__collapseExpandedHotels(collapseFunc) > 0) {
		//The callback will re-trigger the worker once
		//hotels are collapsed
		return;	
	}
		
	
	var compFunc = Facilities__hotelComparator.bind(criteria);
	var hotelArray = $$('ul#facilitiesHotelList li');
	var sortedHotelArray = hotelArray.sort(compFunc);
	//console.log(sortedHotelArray);
	//sortedHotelArray.each(Facilities__hotelMorph);
	
	//Set height on containing ul
	$('facilitiesHotelList').style.height = $('facilitiesHotelList').getHeight()+"px";
	$('facilitiesHotelList').style.position = "relative";
	
	//Make all the LI position: absolute
	//Need to scan for positions before making things position: absolute
	var hotelTopPositions = new Array();
	for(var i = 0; i < sortedHotelArray.length; i++) {
		hotelTopPositions[i] = sortedHotelArray[i].positionedOffset()[1]+"px";
	}
	
	
	Facilities__hotelsMorphing = sortedHotelArray.length
	Facilities__sortedHotelArray = sortedHotelArray;
	
	var totalHeight = 0;
	for(var i = 0; i < sortedHotelArray.length; i++) {
		//Absolutise position
		sortedHotelArray[i].style.position = "absolute";
		sortedHotelArray[i].style.top = hotelTopPositions[i];
		
		//Morph position
		new Effect.Morph(sortedHotelArray[i], {
			style:{
				top:(totalHeight)+ 'px'
			}, 
			duration:Facilities__morphTime,
			afterFinish:Facilities__morphFinished
		});
		
		//Morph mask
		var mask = sortedHotelArray[i].select('div.hotelMask')[0];
		if(criteria.hotelMeets(sortedHotelArray[i])) {
			mask.style.display = "block";
			
			new Effect.Morph(mask, {
				style:{
					opacity:"0.0"
				}, 
				duration:Facilities__morphTime,
				afterFinish:Facilities__hideMask.bind(mask)
			});
			//setTimeout('$$("#'+sortedHotelArray[i].id+' div.hotelMask")[0].style.display = "none";', (Facilities__morphTime*1000.0));
		}
		else {
			mask.style.display = "block";
			new Effect.Morph(mask, {
				style:{
					opacity:"0.745"
				}, 
				duration:Facilities__morphTime
			});
		}
		
		totalHeight += sortedHotelArray[i].getHeight();
	}
}

function Facilities__hideMask() {
	this.style.display = "none";
}

function Facilities__collapseFinished() {
	if(--Facilities__hotelsCollapsing > 0) return;
	//Collapse at astart of animation finished,
	//trigger the worker
	Facilities__criteriaChangedWorker(this);
}

function Facilities__morphFinished() {
	if(--Facilities__hotelsMorphing > 0) return;
	//Animation is over, let's re-flow the hotels
	var hotelUL = $('facilitiesHotelList');
	for(var i = 0; i < Facilities__sortedHotelArray.length; i++) {
		Facilities__sortedHotelArray[i].style.position = "relative";
		Facilities__sortedHotelArray[i].style.top = "";
		hotelUL.removeChild(Facilities__sortedHotelArray[i]);
		hotelUL.appendChild(Facilities__sortedHotelArray[i]);
	}
	
	//Remove height on containing ul
	hotelUL.style.height = "auto";
	hotelUL.style.position = "static";
	
	if(Facilities__queuedMorphs.length > 0) {
		Facilities__criteriaChangedWorker(Facilities__queuedMorphs.shift());
	}
}

/**
 * First priority is meeting the selected criteria.
 * Second priority is numbers of features.
 */
function Facilities__hotelComparator(hotelOne, hotelTwo) {
	var hotelOneMeetsCriteria = this.hotelMeets(hotelOne);
	var hotelTwoMeetsCriteria = this.hotelMeets(hotelTwo);
	if(hotelOneMeetsCriteria == hotelTwoMeetsCriteria) {
		//Either both meet or fail to meet criteria.
		//console.log(hotelOne.id + " & " +hotelTwo.id+(hotelOneMeetsCriteria? ' meet' : ' do not meet')+" the criteria");
		if(hotelOneMeetsCriteria) {
			//Tie break on number of features	
			var hotelOneScore = Facilities__scoreHotel(hotelOne);
			var hotelTwoScore = Facilities__scoreHotel(hotelTwo);
			if(hotelOneScore > hotelTwoScore) return -1;
			else if (hotelOneScore < hotelTwoScore) return +1;
			return 0;
		}
		else {
			//Tie break on which matches most features
			var hotelOneScore = this.scoreHotel(hotelOne);
			var hotelTwoScore = this.scoreHotel(hotelTwo);
			if(hotelOneScore > hotelTwoScore) return -1;
			else if (hotelOneScore < hotelTwoScore) return +1;
			else {
				hotelOneScore = Facilities__scoreHotel(hotelOne);
				hotelTwoScore = Facilities__scoreHotel(hotelTwo);
				if(hotelOneScore > hotelTwoScore) return -1;
				else if (hotelOneScore < hotelTwoScore) return +1;
				else return 0;
			}
		}
	}
	else if(hotelOneMeetsCriteria) {
		return -1;	
	}
	else if(hotelTwoMeetsCriteria) {
		return +1;
	}
}

function Facilities__toggleCriteria(evnt) {
	this.stopObserving('click');
	if($('criteriaContent').parentNode.style.display == "none") Effect.BlindDown($('criteriaContent').parentNode, {afterFinish:Facilities__reEnableCriteriaToggle.bind(this)});
	else Effect.BlindUp($('criteriaContent').parentNode, {afterFinish:Facilities__reEnableCriteriaToggle.bind(this)});
}	

function Facilities__reEnableCriteriaToggle() {
	this.observe('click', Facilities__toggleCriteria);
}

function Facilities__toggleHotelMore(evnt) {
	
	var moreContainer = this.select('div.hotelMore')[0];
	if(moreContainer.style.display == "none") {		
		//Can only have one booking widget on the page at a time!
		var collapseFunc = function() {
			Facilities__hotelsCollapsing--;
		};
		Facilities__collapseExpandedHotels(collapseFunc);  //Collapse hotels, but we don't care about a callback.
		//We SHOULD disable other hotel clickers so they can't be oped simultaneously
		//and result in either two booking widgets at once,
		//or the first to be clicked collapsing and expanding 
		//at the same time, which looks odd.
		var moreImages = $$('ul#facilitiesHotelList li img.hotelMore');
		for(var i = 0; i < moreImages.length; i++) {
			moreImages[i].stopObserving('click');
		}
		var loadBookingFunc = function() {
			//Re-enable the more buttons
			var moreImages = $$('ul#facilitiesHotelList li img.hotelMore');
			for(var i = 0; i < moreImages.length; i++) {
				Facilities__reEnableToggleHotelMore.bind(moreImages[i].parentNode)();
			}
			new Ajax.Request('/facilities/ajax_booking_teaser/'+this.id.substr(5)+'.htm', {
				method:"get",
				onSuccess:Facilities__loadBookingTeaserCB
			});
		}.bind(this);
		Effect.BlindDown(moreContainer, {afterFinish:loadBookingFunc});
		moreContainer.select('div.bookingTeaserCont')[0].style.background = "url('/images/ajax-loader-big.gif') no-repeat center";
	}
	else {
		this.select('img.hotelMore')[0].stopObserving('click');
		Effect.BlindUp(moreContainer, {afterFinish:Facilities__reEnableToggleHotelMore.bind(this)});
		var bookingDiv = this.select('div.hotelMore .hotelMoreRight .bookingTeaserCont')[0];
		bookingDiv.innerHTML = '&nbsp;';
	}
}

function Facilities__reEnableToggleHotelMore() {
	this.select('img.hotelMore')[0].observe('click', Facilities__toggleHotelMore.bind(this));	
}

function Facilities__loadBookingTeaserCB(transport) {
	var xml = transport.responseXML;
	var hotelID = xml.getElementsByTagName("hotel_id")[0].firstChild.data;
	var bookingHTML = xml.getElementsByTagName("html")[0].firstChild.data;
	var bookingDiv = $$('#hotel'+hotelID+' div.hotelMore .hotelMoreRight .bookingTeaserCont')[0];
	bookingDiv.innerHTML = bookingHTML;
	bookingDiv.style.background = "none";
	var scriptTags = bookingDiv.select("script");
	for(var  i = 0; i < scriptTags.length; i++) {
		try {
			var js = scriptTags[i].innerHTML;
			eval(js);
		}
		catch(e) {
			console.log(e);
		}
	}
}
