/**
	SUMMARY
	Departure and Return Date selection using menus.
	
	FEATURES
	Simplifies date selection for the user.
	Provides cleaner date handling as the user cannot enter invalidly formatted dates.
	Displays the day of the week in gray text to the left of the menus.
	
	NOTES
	The range of future years to display can be configured by setting the yearInterval variable.
	The default number of days between departure and return dates can be configured by setting
	the dateInterval variable.
**/


// Constant array of days of the week, in short 3 character form.
var daysOfWeek = new Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
// The year interval (i.e. how far in the future we wish to display).
var yearInterval = 3;
// The date interval between departure and rturn dates - default value is 7 days (in milliseconds).
var dateInterval = 1000 * 60 * 60 * 24 * 7;

/**
	Helper function to calculate the number of days in the month.
**/
function daysInMonth(month, year)
{
	var actual_month = (month != 11) ? month + 1 : 0;
	var actual_year = (month != 11) ? year : year + 1;
	
	var new_date = new Date(actual_year, actual_month, 0);
	return new_date.getDate();
}

/**
	Helper function to get the date components from a hidden date field.
**/
function getHiddenDateComponents(selection)
{	
	// crappy hacky fixy thing - because the popup calendar stores the
	// year as 2 digits we need to fix it to be 4 digits and we do tha
	// here as I don't fancy wading through all of the calendar.js code
	// to check what side-effects I might cause if I 'fix' it there ;-)
	// it will only for the 21st century but I figure we can live with that ;-)
	var date_array = $(selection + '_date_hidden').value.split("/");
	// check whether the hidden date field had a date value
	if (date_array.length == 3)
	{
		date_array[2] = (date_array[2].length == 2) ? (date_array[2] = '20' + date_array[2]): date_array[2];
		return date_array;
	}
	else
	{
		return false;
	}
}

/**
	Helper function to set the date in a hidden date field.
**/
function setHiddenDate(selection, day, month, year)
{	
	// update the date stored in the hidden field
	$(selection + '_date_hidden').value = day + "/" + month + "/" + year;
	
	// as we're maintaining the old hidden date fields too update the matching one also
	// they've been retained as-is to avoid breaking other code which relies on then, i.e.
	// the Flight_Search and Cosnet_ProductSearchRQ classes
	//year = year + "";
	if (selection == 'dep')
	{
		$('date').value = day + "/" + month + "/" + year.toString().substr(2, 2);
	}
	else if (selection == 'ret')
	{
		$('rtn_date').value = day + "/" + month + "/" + year.toString().substr(2, 2);
	}
}

/**
	Helper function to make a date from array elements.
**/
function makeDateFromArray(date_array)
{	
	if (date_array.length == 3)
	{
		// NB month (date_array[1]) must be in the range 0-11!
		return new Date(date_array[2], date_array[1] - 1, date_array[0]);
	}
	else
	{
		return false;
	}
}

/**
	Initialise the flight search dates.
	This should be run on body load.
**/
function initFlightSearchDates()
{
	if (($('dep_date_hidden') != null) && ($('ret_date_hidden') != null))
	{
		// create date objects
		var initial_departure_date = makeDateFromArray(getHiddenDateComponents('dep'));
		var initial_return_date = makeDateFromArray(getHiddenDateComponents('ret'));
		
		// if the hidden date fields didn't have a date value then use the current date
		if (! initial_departure_date)
		{
			initial_departure_date = new Date();
		}
		
		if (! initial_return_date)
		{
			initial_return_date = new Date(initial_departure_date.getTime() + dateInterval);
		}
	
		// initialise departure and return date menus
		initDateMenus('dep', initial_departure_date);
		initDateMenus('ret', initial_return_date);
	}
}

/**
	Initialise a set of date menus (either departure or return).
**/
function initDateMenus(selection, new_date)
{
	var today = new Date();
	var actual_date = new Date();
	var date_parts = [];
	
	// zero the days menu
	$(selection + '_day').options.length = 0;
	
	// use the date passed into the function otherwise
	// use the one stored in the hidden date field
	if (new_date instanceof Date)
	{
		actual_date = new_date;
	}
	else
	{
		actual_date = makeDateFromArray(getHiddenDateComponents(selection));
	}
	
	var day = actual_date.getDate();
	var month = actual_date.getMonth();
	var year = actual_date.getFullYear();	
		
	// get the number of days in the month
	// NB month must be in the range 0-11!
	var numOfDays = daysInMonth(month, year);
	
	// re-create the days
	for (i = 1; i <= numOfDays; i++)
	{
		$(selection + '_day').options[i - 1] = new Option(i, i);
	}

	// re-create the year menu
	if ($(selection + '_year').options.length > 0)
	{	
		// drop all current year menu options
		$(selection + '_year').options.length = 0;
		// create year menu options with incrementing year number
		for (var i = 0; i < yearInterval; i++)
		{
			// create a new option
			$(selection + '_year').options[i] = new Option(today.getFullYear() + i, today.getFullYear() + i);
		}	
	}
	
	$(selection + '_day').options[actual_date.getDate() - 1].selected = true;
	$(selection + '_month').options[actual_date.getMonth()].selected = true;
	$(selection + '_year').options[actual_date.getFullYear() - today.getFullYear()].selected = true;
		
	// update the weekday text
	$(selection + '_dayofweek').firstChild.nodeValue = daysOfWeek[actual_date.getDay()];
	// update the hidden date field
	setHiddenDate(selection, day, month + 1, year);
	
	return true;
}

/**
	Update the date information, based on year and month.
**/
function updateDate(selection, is_calendar_update)
{
	var today = new Date();
			
	// get the date components from the hidden field
	if (is_calendar_update)
	{
		date_array = getHiddenDateComponents(selection);
		var day = date_array[0];
		var month = date_array[1];
		var year = date_array[2];
	}
	// get the date components from the menus
	else
	{
		var day = $(selection + '_day').options[$(selection + '_day').selectedIndex].value;
		var month = $(selection + '_month').options[$(selection + '_month').selectedIndex].value;
		var year = $(selection + '_year').options[$(selection + '_year').selectedIndex].value;
	}
	
	// update the hidden date field
	setHiddenDate(selection, day, month, year);
	
	// get the number of days in the month
	// NB month must be in the range 0-11!
	var numOfDays = daysInMonth(month - 1, year);
	// zero the days menu
	$(selection + '_day').options.length = 0;
	
	// re-create the days
	for (i = 1; i <= numOfDays; i++)
	{
		$(selection + '_day').options[i - 1] = new Option(i, i);
	}
	
	// set the correct date menu selections
	// NB need to check that the day is valid for this month,
	// e.g. if previous month's selected day was 31 and this month there are
	// only 30 days, in which case use the beginning of the month as default
	var actual_day_index = (day <= numOfDays) ? day - 1 : numOfDays-1;
	$(selection + '_day').options[actual_day_index].selected = true;
	$(selection + '_month').options[month - 1].selected = true;
	
	// create a new date object, and set the weekday
	// NB month must be in the range 0-11!
	var new_date = new Date(year, month - 1, (day <= numOfDays) ? day : numOfDays);
	// update the day of week text
	$(selection + '_dayofweek').firstChild.nodeValue = daysOfWeek[new_date.getDay()];
	
	// if the departure date has been updated then auto-update the return date
	if (selection == 'dep')
	{
		// determine the new return date
		var return_date = new Date(new_date.getTime() + dateInterval);
		// update the month and year return date menus
		// NB getMonth() function return is in the range 0-11!
		$('ret_month').selectedIndex = return_date.getMonth();
		
		// handle situation where year has exceeded the display range, in
		// which case set the date to the maximum date displayable
		if (return_date.getFullYear() > (today.getFullYear() + $('ret_year').length - 1))
		{
			// set the date to the maximum allowable by the menus, i.e. 31 Dec of the highest year
			$('ret_day').selectedIndex = $('ret_day').length - 1;
			$('ret_month').selectedIndex = $('ret_month').length - 1;
			$('ret_year').selectedIndex = $('ret_year').length - 1;
			// determine the revised return date
			var final_day = $('ret_day').options[$('ret_day').selectedIndex].value;
			var final_month = $('ret_month').options[$('ret_month').selectedIndex].value;
			var final_year = $('ret_year').options[$('ret_year').selectedIndex].value;
			// NB month must be in the range 0-11!
			var return_date = new Date(final_year, final_month - 1, final_day);
			// force the return date to our revised date
			initDateMenus('ret', return_date);
		}
		var return_day = return_date.getDate();
		var return_month = return_date.getMonth();
		var return_year = return_date.getFullYear();
		// update the hidden return date field
		setHiddenDate('ret', return_day, return_month + 1, return_year);
		initDateMenus('ret', return_date);
		
		$('date').value = $('dep_day').value + "/" + month + "/" + year.toString().substr(2, 2);
	}
	
	return true;
}

// run this after the page loads
addLoadEvent(initFlightSearchDates);
