/*
 * De Vere Booking Panel Javascript.
 * 
 * Copyright Vexed Ltd. 2011
 * 
 * Throughout this file, the jQuery() construct SHOULD be used instead of the 
 * shorter $ form. 
 * 
 *  DEPENDENCIES:
 *  lib/jquery-1.6.2.min.js
 *  plugins/jquery-ui-1.8.7.custom.min.js
 *  lib/date-en-GB-1.0-Alpha-1.js
 *  plugins/jquery-validation-1.8.1/jquery.validate.min.js
 *  plugins/jquery.selectboxes-2.2.4.js
 *  devere/LocationService.js
 *  devere/PropertyAutocomplete.js
 * 
 * 25 Jul 2011
 * A couple of additional settings have been added which can be used to override standard functionality:
 *
 *  DATEPICKER_OPTIONS - used to extend or override the standard jQuery UI datepicker options
 *  DEPARTURE_DATE_FORMAT - used to override the format for the departure date text
 *
 * Examples:
 *
 *  DEPARTURE_DATE_FORMAT = "ddd, d MMM yyyy";
 *  DATEPICKER_OPTIONS = {
 *    showOn: 'both',
 *    buttonImageOnly: true
 *  }
 */

// Function run when page loads; this is fired at document.ready 
jQuery(function()
{
	
	// position booking panel popup
	jQuery(window).bind('resize scroll', function() {
		positionBookingPanelPopup();
	});
	
	function positionBookingPanelPopup() {
		jQuery("#booking-panel-popup, #booking-panel-iframe").css({
			'top': function() { 
				var winHeight = jQuery(window).height(),
					panelHeight = jQuery("#booking-panel-popup").outerHeight(),
					hdrOffset = jQuery('#hotelHeader').outerHeight() + 15,
					vCentrePoint = winHeight/2 - panelHeight/2;
				
				if ( vCentrePoint > hdrOffset ) return vCentrePoint;
				
				return hdrOffset; 
			}, 
			'left': function() { 
				
				var hCentrePoint = jQuery(window).width()/2 - jQuery("#booking-panel-popup").outerWidth()/2; 
				return hCentrePoint;
			}
		});
	}
	
	// show booking panel popup
	jQuery("#booking-panel-trigger, a.booking-panel-trigger").bind('click', function(e) {
		e.preventDefault();
		positionBookingPanelPopup();
		jQuery("#booking-panel-popup").show(300);
	});
	
	// hide booking panel popup
	jQuery("#booking-panel-popup A.close").bind('click', function() {
		jQuery("#booking-panel-popup").hide(300);
	});
	
	// initialise autocompleter functionality
	jQuery(".booking-panel .js-hotel-autocomplete").each(function()
	{
		new PropertyAutocomplete({ 
			element: this,
			field: jQuery("#propertycode"),
			searchType: PropertyAutocomplete.SEARCHTYPE_BEDROOM
		});
	});
	
	// initialise calendar popup functionality
	jQuery(".booking-panel .js-date").each(function()
	{	
		var element = jQuery(this),
		
			today = new Date(),
			month = parseInt( today.getMonth() + 1 ),
			month = month < 10 ? '0' + month : month,
			todayFormatted = today.getDate() + '/' + month + '/' + today.getFullYear();
		
		element.val( todayFormatted ); // set default to today
		
		DATEPICKER_OPTIONS_DEFAULT = {
			buttonImage: calendarIcon, // needs to be defined outside and before this js file
			minDate: new Date(),
			maxDate: "+9M",
			dateFormat : "dd/mm/yy",
			onSelect : function() {
				// set hidden arrival date to be sent to BBE
				jQuery("#arrivaldate").val( formatDateStr( element.val() ) );
				
				// set flex/fixed arrival dates to be the same value
				jQuery("#fixedarrivaldate, #approxarrivaldate").val( element.val() );
				
				updateDepartureDate();
			}
		};
		
		if(typeof(DATEPICKER_OPTIONS) != "undefined") jQuery.extend(DATEPICKER_OPTIONS_DEFAULT, DATEPICKER_OPTIONS);

		element.datepicker(DATEPICKER_OPTIONS_DEFAULT);
		
		element.nextAll("IMG").click(function()
		{
			element.focus();
		}).css("cursor", "pointer");
		
		element.attr("autocomplete", "off");
	});
	
	// initially refresh booking panel display from cached values
	refreshBookingPanel();
	
	// refresh booking panel display when number of rooms, number of nights and date changes
	jQuery(".booking-panel .room-count").change(updateRoomConfiguration);
	jQuery("SELECT.no-nights, .js-date").change(updateDepartureDate);
	
	// refresh booking panel when search preference or fixed/flex changes
	jQuery(".booking-panel .search-selection INPUT:radio").bind("click blur change", updateSearchPreference);
	jQuery(".booking-panel .type-selection INPUT:radio").bind("click blur change", updateFixedFlexDisplay);
	
	// update all locations dropdowns across forms to be display the same property attribute (property name) if exists
	jQuery("SELECT.locationdd").change( function() {
		jQuery("SELECT.locationdd option[property='" + jQuery(this).find(":selected").attr("property") + "']").attr("selected","selected");
	});
	
	// empty input search field on click
	jQuery("#locationsearch").click( function() { jQuery(this).val(""); } );
	
	// trigger change event on autocompleter input when switching to it, to repopulate the #promocode hidden field potentially set by the drop down list
	jQuery('INPUT.location-search:radio').click( function() {
		$('#locationsearch').trigger('change');
	});

	// display meeting times message in accordance to selection
	jQuery("FORM#meetingSearch .meeting-time INPUT:radio").bind("click", updateMeetingTime);
	function updateMeetingTime() {
       switch ( jQuery("FORM#meetingSearch .meeting-time INPUT:radio:checked").val() ) {
            case "AM":
                jQuery("#meetingMsgAvailability").text("Meeting room available between 8:30am & 12:30pm");
                break;
            case "PM":
                jQuery("#meetingMsgAvailability").text("Meeting room available between 13:30pm & 5:30pm");
                break;
            default:
                jQuery("#meetingMsgAvailability").text("Meeting room available between 8:30am & 5:30pm");
       }
     }
	
	// VALIDATION
	
	// Show/Hide error message
	function refreshErrorMessage() {
		jQuery(".error-ctr").each(function()
		{
			var element = jQuery(this),
				hasErrors = element.find("LI.err").length > 0;
			
			if (!hasErrors)
			{
				element.hide();
			}
		});
	}
	refreshErrorMessage();
	
	jQuery.validator.prototype.addErrorHeader = function() {
		if (jQuery("DIV.error-ctr H2").size() < 1)
    	{
    		
    		jQuery("DIV.error-ctr").prepend(jQuery("<h2>There's a problem.</h2>"));
    	}
	}
	
	/* 
	// Have moved these defaults to be options of the validate() function
	// otherwise it's near impossible to use the validation plugin elsewhere
	
	jQuery.validator.setDefaults({
		errorElement : "LI",
		errorClass : "err",
		errorContainer : "DIV.error-ctr",
		errorLabelContainer : "DIV.error-ctr UL",
		debug: false,
		success : function(element){
			jQuery(element).remove();
		},
	    errorPlacement : function(){},
		invalidHandler: function(form, validator)
		{
			validator.showErrors();
			validator.addErrorHeader();
		},
		highlight : function(element, errorClass, validClass)
        {
			this.addErrorHeader();
			element = jQuery(element);
            element.closest("LABEL, .label").addClass(errorClass);
        },
        unhighlight : function(element, errorClass, validClass)
        {
        	element = jQuery(element);
            element.closest("LABEL, .label").removeClass(errorClass);
            refreshErrorMessage();
        }
	});
	*/
	
	// Assign custom error messages
	bedroomBookingErrors = {
		locationsearch : { required : "You haven't given us your preferred location." },
		locationlist : { required : "You haven't given us your preferred location." },
		fixedarrivaldate : { required : "You haven't given us an arrival date.", daterange:"You have given a date that is invalid or out of range." },
		approxarrivaldate : { required : "You haven't given us an approximate arrival date.", daterange:"You have given a date that is invalid or out of range." }
	};
	meetingBookingErrors = {
		meetinglocationlist : { required: "You haven't indicated your preferred venue." },
		meetingdate : { required : "You haven't given us a meeting date.", daterange:"You have given a date that is invalid or out of range." }
		//numAttendees : { required : "You haven't indicated the number of attendees.", range: "Please enter between 2 and 25 attendees." }
	};
	lodgeBookingErrors = {
		lodgelist : { required : "You haven't given us your preferred lodge." },
		lodgedate : { required : "You haven't given us an arrival date.", simpledaterange:"You have given a date that is invalid or out of range." }
	};
	
	// Custom validation method: Check if a given date is between now and 9 months in the future
	jQuery.validator.addMethod("simpledaterange", function(date, element) 
	{   
		var result = true;
		if (jQuery(element).is(":visible")) {
			var d1 = Date.parse(date);
			if (d1 === null) {
				//not a valid date
				result = false;
			} else {
				if (d1.isBefore(Date.today()) === true) {
					//date out of range
					result = false;
				}
			}
		}
		
		return result;
	}, "Date invalid or out of range.");

	// Custom validation method: Check if a given date is between now and 9 months in the future
	jQuery.validator.addMethod("daterange", function(date, element) 
	{   
		var result = true;
		if (jQuery(element).is(":visible")) {
			var d1 = Date.parse(date);
			if (d1 === null) {
				//not a valid date
				result = false;
			} else {
				if (d1.isBefore(Date.today()) === true || d1.isAfter(new Date().addMonths(9)) === true) {
					//date out of range
					result = false;
				}
			}
		}
		
		return result;
	}, "Date invalid or out of range.");
	
	// Custom validation method: Check if there are more than 4 people selected per room
	jQuery.validator.addMethod("peoplePerRoom", function(val,element) 
	{   
		var result = true;
		//check for all rooms
		jQuery('.selection-group').each(function(){
			var people = 0;
			//go through all drop-downs for the specific room 
			//and get the number off people selected
			jQuery(this).find('.peoplePerRoom').each(function(){
				people += parseInt(jQuery(this).val());
			});
			if(people > 4){
				result = false;
				return result;
			}
		});	
		return result;
	}, "You have indicated more than 4 occupants per room. Could you lessen this please? (4 occupants max per room)");
	
	// Define validation class rules
	jQuery.validator.addClassRules({ 
		required :
		{
			required : {
				depends : function(element) {
					return jQuery(element).is(":visible");
				}
			}
		},
		limit10 : 
		{
			maxlength : 10
		},
		daterange : 
		{
			daterange : true
		},
		peoplePerRoom : 
		{
			peoplePerRoom: true
		},
		range2to25req :
		{
			required: true,
			range : [2, 25]
		}
	});
	
	// Setup validator for bedroom booking form
	jQuery("FORM#bedroomSearch").validate({
		errorElement : "LI",
		errorClass : "err",
		debug: false,
		success : function(element){
			jQuery(element).remove();
		},
	    errorPlacement : function(){},
		invalidHandler: function(form, validator)
		{
			validator.showErrors();
			validator.addErrorHeader();
		},
		errorContainer : "FORM#bedroomSearch DIV.error-ctr", // require unique errorContainer per form
		errorLabelContainer : "FORM#bedroomSearch DIV.error-ctr UL", // require unique errorContainer per form
		messages : translateErrorMessages(jQuery("FORM#bedroomSearch"), bedroomBookingErrors),
		groups:{
			//peoplePerRoomGroup: "select_3 select_4 select_5 select_6 select_7 select_8 select_9 select_10 select_11 select_12 select_13 select_14 select_15 select_16 select_17"
			peoplePerRoomGroup: "Adults1 Children1 Infants1 Adults2 Children2 Infants2 Adults3 Children3 Infants3 Adults4 Children4 Infants4 Adults5 Children5 Infants5"
		},
		highlight : function(element, errorClass, validClass)
	    {
	    	this.addErrorHeader();
	    },
	    unhighlight : function(element, errorClass, validClass)
	    {
	    	refreshErrorMessage();
	    },
	    submitHandler: function(form) {
	    	// Set locations search type value
	    	if ( jQuery(".booking-panel .search-selection INPUT.location-search").is(":not(:checked)") ) {
	    		jQuery("#propertycode").val( jQuery("#locationlist").val() );
	    	}
	    	
	    	// Set fixed/flex hidden values
	    	if ( jQuery(".booking-panel .type-selection INPUT.fixed-date").is(":checked") || jQuery(".booking-panel INPUT[name='fixed-date']").is("[value='true']") ) {
				//console.log(jQuery(".booking-panel INPUT.fixed-date").is("[value='true']"));
	    		jQuery("#step").val("RESULTS"); // User will be shown the results page on BBE
	    		jQuery("#arrivaldate").val( formatDateStr( jQuery("#fixedarrivaldate").val() ) );
	    	} else {
	    		jQuery("#step").val("GRID"); // User will be shown the grid page on BBE
	    		jQuery("#arrivaldate").val( formatDateStr( jQuery("#approxarrivaldate").val() ) );
	    	}
	    	
	    	// Room guest configuration
	    	var numRooms = parseInt(jQuery("#rooms").val(), 10);
	    	
	    	var globalAdults = "";
			var globalChildren = "";
			var globalInfants = "";
			for (var i = 1; i <= numRooms; i++) {
				var adults = jQuery("#adults" + i).val();
				globalAdults += adults + ",";
				
				var children = jQuery("#children" + i).val();
				globalChildren += children + ",";
				
				var infants = jQuery("#infants" + i).val();
				globalInfants += infants + ",";						
			}
			globalAdults = globalAdults.substring(0, globalAdults.length-1);
			jQuery("#adults").val(globalAdults);
			
			globalChildren = globalChildren.substring(0, globalChildren.length-1);
			jQuery("#children").val(globalChildren);
			
			globalInfants = globalInfants.substring(0, globalInfants.length-1);
			jQuery("#infants").val(globalInfants);
			
			// Submit form
			form.submit();
	    }
	});
	
	
	// Setup validator for meeting booking form
	jQuery("FORM#meetingSearch").validate({ 
		errorContainer : "FORM#meetingSearch DIV.error-ctr", // require unique errorContainer per form
		errorLabelContainer : "FORM#meetingSearch DIV.error-ctr UL", // require unique errorContainer per form
		messages : translateErrorMessages(jQuery("FORM#meetingSearch"), meetingBookingErrors),
		highlight : function(element, errorClass, validClass)
	    {
	    	this.addErrorHeader();
	    },
	    unhighlight : function(element, errorClass, validClass)
	    {
	    	refreshErrorMessage();
	    },
	    submitHandler: function(form) {
			
			// Submit form
			form.submit();
	    }
	});
	
	// Setup validator for lodges booking form
	jQuery("FORM#lodgeSearch").validate({ 
		errorContainer : "FORM#lodgeSearch DIV.error-ctr", // require unique errorContainer per form
		errorLabelContainer : "FORM#lodgeSearch DIV.error-ctr UL", // require unique errorContainer per form
		messages : translateErrorMessages(jQuery("FORM#lodgeSearch"), lodgeBookingErrors),
		highlight : function(element, errorClass, validClass)
	    {
	    	this.addErrorHeader();
	    },
	    unhighlight : function(element, errorClass, validClass)
	    {
	    	refreshErrorMessage();
	    },
	    submitHandler: function(form) {
			
	    	// All OK, so change "start_date" string from DD/MM/YYYY format to DD-MM-YYYY before submitting form
	    	// (DD-MM-YYYY = date string format accepted by 3rd party Lodges booking system) 
	    	jQuery("INPUT#lodgedate").val( jQuery("INPUT#lodgedate").val().replace(/\//g,'-') );
	    	
			form.submit();
	    }
	});
});

// Update the guests per room table according to the number of rooms selected
function updateRoomConfiguration() {
	
	jQuery(".booking-panel .room-count").each(function()
	{
		var element = jQuery(this),
			count = element.val(),
			selectionGroups = jQuery(element.closest("FORM").find(".selection-group")),
			idx = 0;

		for (idx = 0; idx < selectionGroups.length; idx++)
		{
			var group = jQuery(selectionGroups.get(idx));
			
			if (idx < count)
			{
				group.show();
			}
			else
			{
				group.hide();
			}
		}
	});
	
}

// Show the preferred search selection, free text field or dropdown dependent on radio option selected
function updateSearchPreference()
{
	
	jQuery(".booking-panel .search-selection INPUT.location-search").each(function()
	{
		var element = jQuery(this),
			form = jQuery(element.closest("FORM")),
			searchCtrl = form.find("#locationsearch"),
			listCtrl = form.find("#locationlist"),
			label = form.find('.location-label');
		
		if (element.is(":checked"))
		{
			searchCtrl.show();
			listCtrl.hide();
			label.text('Show properties near:');
		}
		else
		{
			searchCtrl.hide();
			listCtrl.show();
			listCtrl.find("UL").hide();
			label.text('Select a property from the list:');
		}
	});
	
}

// Show/Hide the fields relevant to fixed or flexible dates, and set hidden values accordingly
function updateFixedFlexDisplay() {
	
	jQuery(".booking-panel .type-selection INPUT.fixed-date").each(function()
	{
		var element = jQuery(this),
			form = jQuery(element.closest("FORM")),
			fixedSection = form.find(".fixed-date-section"),
			flexibleSection = form.find(".flexible-date-section");
			
		if (element.is(":checked"))
		{
			fixedSection.show();
			flexibleSection.hide();
		}
		else 
		{
			flexibleSection.show();
			fixedSection.hide();
		}
	});
	
}

if (typeof(DEPARTURE_DATE_FORMAT) == "undefined") DEPARTURE_DATE_FORMAT = "dddd, d MMM yyyy";

// Update the departure date display according to the arrival date selected
function updateDepartureDate() {
	
	jQuery(".booking-panel .departure-date").each(function()
	{
		var element = jQuery(this),
			form = jQuery(element.closest("FORM")),
			arrivalDate = Date.parse(form.find(".arrival-date").val()),
			numberOfNights = form.find("SELECT.no-nights").selectedValues()[0],
			departureElement = element.find(".date"),
			displayDate = null;

		if (arrivalDate != null)
		{	
			displayDate = arrivalDate.add(~~(numberOfNights)).days().toString(DEPARTURE_DATE_FORMAT);
			departureElement.html(displayDate);
			element.show();
		}
		else
		{
			element.hide();
		}
		
	});
	
}

// format date string for use by BBE dd/mm/yyyy to yyyymmdd
function formatDateStr(dateStr) {
	
	var dateArray = dateStr.split('/'),
		formattedDate = { dd : dateArray[0], mm : dateArray[1], yyyy : dateArray[2] };
	
	return formattedDate.yyyy + formattedDate.mm + formattedDate.dd;
	
}

// Refresh booking panel display for cached or prepopulated values
function refreshBookingPanel()
{
	updateRoomConfiguration();
	
	updateSearchPreference();
	
	updateFixedFlexDisplay();
	
	updateDepartureDate();
}

// Translate error message to relevant element by id
function translateErrorMessages(element, messages)
{
	element = jQuery(element);
	
	var result = {};
	
	for (key in messages)
	{
		var messageObject = messages[key],
			messageElement = element.find("#" + key);
			
		result[messageElement.attr("name")] = messageObject;
	}
	return result;
}

