function DateSelection(fieldSet, addIcons) {
	this.fieldSet = $(fieldSet);

	var selects = $A(fieldSet.getElementsByTagName('select'));
	this.daySelect = selects.find(function(el)   { return Element.hasClassName(el, 'day'); });
	this.monthSelect = selects.find(function(el) { return Element.hasClassName(el, 'month'); });

	if(addIcons)
	{
	    this.icon = document.createElement('img');
	    this.icon.src = '/graphics/search/calendar_icon.gif';
	    this.icon.alt = 'calendar';
	    this.icon.height = 19;
	    this.icon.width = 31;

	    var iconA = document.createElement('a');
	    iconA.href = '#';
	    iconA.className = 'calendar_ico';
	    iconA.title = "open calendar";
	    iconA.appendChild(this.icon);

	    Event.observe(iconA, 'click', this.openCalendar.bind(this));

	    var pCal = $A(fieldSet.getElementsByClassName('calendar'));
	    if (pCal.length > 0) {
		    // thin search
		    pCal.first().insertBefore(iconA, pCal.first().firstChild);
	    } else {
		    // wide search
		    this.monthSelect.parentNode.insertBefore(iconA, this.monthSelect.previousSibling);
	    }
	}

	this.yearFirst = this.monthSelect.options[0].value.substr(0,2) > 12;
	this.zeroBasedMonth = false;
	
	$A(this.monthSelect.options).pluck('value').each(function(val) {
		var month = this.yearFirst ? val.substr(4) : val.substr(0,2);

		if (month == '00') {
			this.zeroBasedMonth = true;
		}
	}.bind(this));
}

// static method
DateSelection.init = function() { 
	if (!PageUpdates.enabled) 
		return;

	var lastFrom;

	$A(document.getElementsByClassName('dateSelect')).each(function (el) {
		if (Element.hasClassName(el, 'from_row')) {
			lastFrom = new DateSelection(el, true);
		} else if (Element.hasClassName(el, 'to_row')) {
			var toRow = new DateSelection(el, true);

			new DateLinker(lastFrom, toRow);
		} else {
			new DateSelection(el, true);
		}
	});
}
//static method to be called after updating from calendar to update num nights as required 
DateSelection.update = function() { 
	if (!PageUpdates.enabled) 
		return;

	var lastFrom;

	$A(document.getElementsByClassName('dateSelect')).each(function (el) {
		if (Element.hasClassName(el, 'from_row')) {
			lastFrom = new DateSelection(el, false);
		} else if (Element.hasClassName(el, 'to_row')) {
			var toRow = new DateSelection(el, false);

			new DateLinker(lastFrom, toRow);
		} else {
			new DateSelection(el, false);
		}
	});
}

DateSelection.activeCalendar = false;

DateSelection.prototype = {
	openCalendar: function(event) {
		if (event) Event.stop(event);

		if (DateSelection.activeCalendar) {
			DateSelection.activeCalendar.hide();

			if (DateSelection.activeCalendar == this.cal) {
				DateSelection.activeCalendar = false;
				return;
			}
		}
		if (typeof this.cal == 'undefined') {
			var minDate = new Date();
			var maxDate = new Date(minDate.getTime() + (4 * 365 * 24 * 60 * 60 * 1000)); // 2 years

			this.cal = new TPCalendar(this.getDate(), this.selectHandler.bind(this), this.closeHandler.bind(this));
			this.cal.setRange(minDate, maxDate);
			this.cal.create();

			$A(this.fieldSet.getElementsByTagName('select')).each(function(el) {
				Event.observe(el, 'change', function() { this.cal.setDate(this.getDate())}.bind(this));
			}.bind(this));
		} else {
			this.cal.setDate(this.getDate());
		}
		DateSelection.activeCalendar = this.cal;
		
		this.cal.hideDropDowns();
		this.cal.showAt(this.icon);
	},
	dropdownDate: function(monthValue, dayValue) { 
		
		var result = new Date();

        result.setMonth(monthValue.substr(4) - (this.zeroBasedMonth ? 0 : 1));  
		result.setUTCHours(0);
		result.setUTCMinutes(0);
		result.setUTCSeconds(0);
		result.setUTCDate(dayValue);

		if (this.yearFirst) {
			result.setUTCFullYear(monthValue.substr(0,4));
			result.setUTCMonth(monthValue.substr(4) - (this.zeroBasedMonth ? 0 : 1));
		} else {
			result.setUTCFullYear(monthValue.substr(2,4));
			result.setUTCMonth(monthValue.substr(0,2) - (this.zeroBasedMonth ? 0 : 1));
		}

		return result;
	},
	getForm: function() {
		return this.daySelect.form;
	},
	getDate: function() {
		return this.dropdownDate(this.monthSelect.value, this.daySelect.value);
	},
	setDate: function(date) {
		var monthValue = '';

		if (this.yearFirst) monthValue += date.getUTCFullYear();
		monthValue += (date.getUTCMonth() < 9 ? '0' : '') + (date.getUTCMonth() + (this.zeroBasedMonth ? 0 : 1)); 
		if (!this.yearFirst) monthValue += date.getUTCFullYear();

		if (!$A(this.monthSelect.options).pluck('value').include(monthValue)) {
			this.monthSelect.appendChild(document.createElement('option'));
			this.monthSelect.lastChild.appendChild(document.createTextNode(Date.monthNames[date.getUTCMonth()].substr(0,3) + " " + date.getUTCFullYear().toString().substr(2)));
			this.monthSelect.lastChild.value = monthValue;
		}

		this.monthSelect.value = monthValue;
		this.daySelect.value = date.getUTCDate();

		if (this.linker)
			this.linker.updateSecond();
	},
	selectHandler: function(date) { this.setDate(date); this.cal.hide(); DateSelection.activeCalendar = false; },
	closeHandler:	function() { this.cal.hide(); DateSelection.activeCalendar = false; },
	isValidDate: function() {
		var date = this.getDate();
		return (date.getUTCDate() == this.daySelect.value);
	}
};

function DateLinker(first, second) {
	this.firstSelector = first;
	this.secondSelector = second;
	this.nightSelector = this.getNightSelector(first.getForm());
	this.guestSelector = this.getGuestSelector(first.getForm());

    this.nightSelector.setNights();
    
	first.linker = this;
	
	//if UpdateNumNights function is defined in search page, use it to update required number of nights
	if (window.UpdateNumNights)
	{
	    this.reqNights = window.UpdateNumNights();
	}
	
	//if UpdateNumGuests function is defined in search page, use it to update required number of guests
	if (window.UpdateNumGuests)
	{
	    this.reqGuests = window.UpdateNumGuests();
	}
	
	//if UpdateStartDateRange function is defined in search page, use it to update required start date range
	if (window.UpdateStartDateRange)
	{
	    this.reqStartDateRange = window.UpdateStartDateRange();
	    
	    var dayValue = this.reqStartDateRange.substr(0,2);
	    var monthValue = this.reqStartDateRange.substr(3,2);
	    var yearValue = this.reqStartDateRange.substr(6,4);
	    
	    var start = new Date();

		start.setUTCHours(0);
		start.setUTCMinutes(0);
		start.setUTCSeconds(0);
		start.setUTCDate(dayValue);
        start.setUTCFullYear(yearValue);
		start.setUTCMonth(monthValue - 1); 
		
		this.reqStartDateRange = start;
	}
	
	//if UpdateEndDateRange function is defined in search page, use it to update required end date range
	if (window.UpdateEndDateRange)
	{
	    this.reqEndDateRange = window.UpdateEndDateRange();
	    
	    var dayValue = this.reqEndDateRange.substr(0,2);
	    
	    var monthValue = this.reqEndDateRange.substr(3,2);
	    var yearValue = this.reqEndDateRange.substr(6,4);
	    
	    var end = new Date();

		end.setUTCHours(22);
		end.setUTCMinutes(0);
		end.setUTCSeconds(0);
		end.setUTCDate(dayValue);
        end.setUTCFullYear(yearValue);
		end.setUTCMonth(monthValue - 1); 
		
		this.reqEndDateRange = end;
	}

	$A(first.fieldSet.getElementsByTagName('select')).each(function(el) {
	    Event.observe(el, 'change', this.updateNumNightsAndSecond.bind(this));		    
	}.bind(this));
	
	$A(second.fieldSet.getElementsByTagName('select')).each(function(el) {
		Event.observe(el, 'change', this.updateNumNights.bind(this));    
	}.bind(this));

	Event.observe(first.getForm(), 'submit', this.checkBounds.bind(this));
}

DateLinker.prototype = {
    reqNights: 1,
    reqGuests: 1,   
    getGuestSelector: function(form){
        var guestSelectors = form.getElementsByClassName('guestSelector');
        if (guestSelectors != null)
        {
            return guestSelectors[0];
        }
        else
        {
            return null;
        }
    },
    getNightSelector: function(form){
        var nightSelectors = form.getElementsByClassName('nightSelector');
        if (nightSelectors != null)
        {
            return new NightSelector(nightSelectors[0], this.firstSelector, this.secondSelector);
        }
        else
        {
            return null;
        }
    },
	updateSecond: function() {
		var firstDate = this.firstSelector.getDate();
		var secondDate;
		
		secondDate = new Date(firstDate.getTime() + (1000 * 60 * 60 * 24 * this.reqNights));

		this.secondSelector.setDate(secondDate);
	},
	updateNumNights: function() {
		this.nightSelector.setNights();
	},
	updateNumNightsAndSecond: function(){
	    this.updateSecond();
	    this.updateNumNights();
	},
	checkBounds: function(evt) {
		var firstDate = this.firstSelector.getDate();
		var secondDate = this.secondSelector.getDate();
		var today = new Date();
		today.setUTCHours(0);
		today.setUTCMinutes(0);
		today.setUTCSeconds(0);

		if (!this.firstSelector.isValidDate()) {
			this.displayError("The check-in date is not valid");
			return Event.stop(evt);
		}

		if (!this.secondSelector.isValidDate()) {
			this.displayError("The check-out date is not valid");
			return Event.stop(evt);
		}

		if (firstDate < today) {
			this.displayError("The check-in date cannot be in the past");
			return Event.stop(evt);
		}

		if (firstDate >= secondDate) {
			this.displayError("The check-out date must be later than the check-in date");
			return Event.stop(evt);
		}
		
		var numNights = (secondDate - firstDate) / (1000 * 60 * 60 * 24);
		
		if (numNights > 30) {
			this.displayError("The check-out date must be no more than 30 days after the check-in date");
			return Event.stop(evt);
		}
		
		if (this.reqStartDateRange)
		{            
            if (firstDate < this.reqStartDateRange)
            {	        
                //UTC date comparison hovers around 0.99 to 1.01 if different day, so if difference is above
                //0.5 then it is safe to assume that the date is out of bounds
                if(((this.reqStartDateRange - firstDate) / (1000 * 60 * 60 * 24)) > 0.5)
                {
                    this.displayError("The check-in date is outside of the selected promotional period. Please amend your stay dates.");
			        return Event.stop(evt);
			    }
            }
		}
		
		if (this.reqEndDateRange)
		{           
            if (secondDate > this.reqEndDateRange)
            {
                this.displayError("The check-out date is outside of the selected promotional period. Please amend your stay dates.");
		        return Event.stop(evt);
            }
		}
		
		if (this.reqNights > 1)
		{
		    if (numNights < this.reqNights){
		        this.displayError("A minimum length of stay of " + this.reqNights + " nights is required for this promotion. Please amend your dates. ");
			    return Event.stop(evt);
		    }
		}
	    
		if (this.reqGuests > 1 && this.guestSelector != null)
		{
		    var numGuests = this.guestSelector.value;
		    
		    if (numGuests < this.reqGuests){
		        this.displayError(this.reqGuests + " guests are required for this promotion. Please amend the number of guests in the room.");
			    return Event.stop(evt);
		    }
		}
		
		var d = new Date();
		var numNightsFromToday = (secondDate - d.getTime()) / (1000 * 60 * 60 * 24);
		
		if (numNightsFromToday > 350) {
			this.displayError("The check-out date must be no more than 350 days from today's date");
			return Event.stop(evt);
		}
		
		//if no errors, remove error boxes before submitting form
		var form = this.firstSelector.getForm();
        var errors = $A(form.getElementsByClassName('error_box'));
        errors.each(function(error){
            error.remove();
        });
	},
	errorBox: false,
	displayError: function(msg) {
		if (!this.errorBox) {							
			this.errorBox = document.createElement('div');
			this.errorBox.className = "error_box";

			this.errorBox.appendChild(document.createElement('h2'));
			this.errorBox.lastChild.className = "error_message";
			this.errorBox.lastChild.appendChild(document.createTextNode("There is a problem with your search"));

			this.errorBox.appendChild(document.createElement('p'));
			this.errorBox.lastChild.className = "error_message";
			this.errorBox.lastChild.appendChild(document.createTextNode(msg));
		} else {
			this.errorBox.lastChild.replaceChild(document.createTextNode(msg), this.errorBox.lastChild.firstChild);
		}

		var form = this.firstSelector.getForm();
		var legend = $A(form.getElementsByTagName('legend')).first();
		
		legend.parentNode.insertBefore(this.errorBox, legend.nextSibling);
	}
};

function NightSelector(obj, first, second){
    this.nightSelector = obj;
    this.checkInSelector = first;
    this.checkOutSelector = second;
    
    Event.observe(obj, 'change', function() { this.checkOutSelector.setDate(this.getDate())}.bind(this));
}

NightSelector.prototype = {
    setNights: function(){

        var checkIn = this.checkInSelector.getDate();
        var checkOut = this.checkOutSelector.getDate();
        var numNights = (checkOut - checkIn) / (1000 * 60 * 60 * 24);
        
        var options = $A(this.nightSelector.options).each(function(opt) {
            if (opt.value == numNights)
            {
                opt.selected=true;
            }
        });
    },
    getNights: function(){
        var nights = 0;
        
        var options = $A(this.nightSelector.options).each(function(opt) {
            if (opt.selected)
            {
                nights = opt.value;
            }
        });

        return nights;
    },
    getDate: function(){
        var checkIn = this.checkInSelector.getDate();
		var checkOut;
		
		checkOut = new Date(checkIn.getTime() + (1000 * 60 * 60 * 24 * this.getNights()));
        
        return checkOut;
    }
};

Event.observe(window, 'load', DateSelection.init);

