addLoadHandler(function() { new CalendarInput('dates flightDate','/img/button_calendar.gif'); return true; });

//	creates calendar widgets for forms
//	takes a fieldset and appends the calendar, then finds
//	fields for day, month and year by looking for corresponding classes

function CalendarInput(cssClass,imagePath) {
var dateFields,dateInputs,optionElements,num,i,curr,maxYear,minYear;
if (	document.getElementsByTagName &&
		document.createElement &&
		document.createTextNode &&
		(dateFields = document.getElementsByTagName('fieldset')) &&
		dateFields.length > 0 &&
		dateFields[0].appendChild &&
		dateFields[0].firstChild &&
		dateFields[0].removeChild
		) {
//	get fieldset
	this.name = cssClass.replace(/ /,'_') + 'Calendar';
	window[this.name] = this;

	num = dateFields.length;
	for (i = 0; i < num; i ++) {
		if (dateFields[i].className.indexOf(cssClass) != -1) this.dateField = dateFields[i];
	}
	if (typeof this.dateField == 'undefined') return this;
	// in order to get today's date reliably, I need to get it from the server, and not rely on the client. todayDate is set in the page the calendar is implemented on, and is used from there.
	this.today = todayDate;
//	get day, month and year fields
	dateInputs = this.dateField.getElementsByTagName('select');
	num = dateInputs.length;
	this.selected = {};
	for (i = 0; i < num; i++) {
		if (dateInputs[i].className.toLowerCase().indexOf('day') != -1) this.selected.day = dateInputs[i];
		else if (dateInputs[i].className.toLowerCase().indexOf('month') != -1) {
				this.selected.month = dateInputs[i];
				addHandler(dateInputs[i],'onchange',new Function('return ' + this.name + '.createCalendar();'));
		} else if (dateInputs[i].className.toLowerCase().indexOf('year') != -1) {
			this.selected.year = dateInputs[i];
			addHandler(dateInputs[i],'onchange',new Function('return ' + this.name + '.createCalendar();'));
		}
	}
	if (typeof this.selected.day == 'undefined' || typeof this.selected.month == 'undefined' || typeof this.selected.year == 'undefined') return this;
//	get maximum and minimum dates
	optionElements = this.selected.year.getElementsByTagName('option');
	num = optionElements.length;
	// maxDate is a year from today
	this.maxDate = new Date(this.today);
	this.maxDate.setYear(this.maxDate.getFullYear() + 1);	
//	min date for this application is just today
	 this.minDate = new Date(this.today.getFullYear(),this.today.getMonth(),this.today.getDate());
//	create and append calendar button
	this.button = this.dateField.appendChild(this.createButton(imagePath));
//	append the nested DIVs to hold the calendar
	this.calendar = document.getElementsByTagName('body')[0].appendChild(DIV({'class':'calendarControl'}));
//	clean up circular references
	addUnloadHandler(new Function(this.name + '.cleanUp();'));

} return this;}
CalendarInput.prototype.createButton = function (imagePath) {
//	create new image object and set it's path
//	use the DomBuilder to create the anchor + image child
	return A({ 'href':'#','title':'click to view calendar','onclick':'return ' + this.name + '.showCalendar();'},IMG({'src':imagePath}))
}
CalendarInput.prototype.showCalendar = function (calMonth,calYear) {
//	create and append the calendar itself; if there's a year and/or month already selected use those; if not, use the values for today
	this.button.onclick = new Function('return ' + this.name + '.hideCalendar();');
	this.createCalendar(calMonth,calYear);
	this.calendar.style.top = getTop(this.button.firstChild) + (this.button.firstChild.offsetHeight - 2) + 'px';
	this.calendar.style.left = getLeft(this.button.firstChild) + 'px';
	this.calendar.style.display = 'block';
	return false;
}
CalendarInput.prototype.hideCalendar = function ()	{
	this.button.onclick = new Function('return ' + this.name + '.showCalendar();');
	this.calendar.style.display = 'none';
	this.clearCalendar();
	return false;
};
CalendarInput.prototype.createCalendar = function (calMonth,calYear) {
	var cal,calTable,selectedDate,currRow,i, inputMonth;
	this.clearCalendar();
	// the Date object is zero-based, the values in the select are one-based. This is fixed here.
	calMonth = (typeof calMonth != 'undefined')?calMonth:(this.selected.month.value)?this.selected.month.value - 1:this.today.getMonth(); 
	calYear = (typeof calYear != 'undefined')?calYear:(this.selected.year.value)?this.selected.year.value:this.today.getFullYear();
	cal = DIV();
//	create TABLE & cache reference
	calTable = cal.appendChild(TABLE());
//	instantiate a date object
	selectedDate = new Date(calYear,calMonth,1,0,0,0,0);
//	create CAPTION & append month + year as a text node, then append CAPTION to TABLE
	calTable.appendChild(CAPTION(selectedDate.getMonthName() + ' ' + selectedDate.getFullYear()));
//	acreate a THEAD with a TR child and append it to the TABLE
	currRow = calTable.appendChild(THEAD(TR())).firstChild;
//	run an unrolled loop through the days of the week, adding one TH per
//	use the number equivalent of the day of week + an arbitrary slug to create an ID, populate with the
//	first letter of the day name
	currRow.appendChild(TH({'scope':'col','id':'calendarControl' + (i=1)},selectedDate.getDayName(i).substring(0,1)));
	currRow.appendChild(TH({'scope':'col','id':'calendarControl' + (++i)},selectedDate.getDayName(i).substring(0,1)));
	currRow.appendChild(TH({'scope':'col','id':'calendarControl' + (++i)},selectedDate.getDayName(i).substring(0,1)));
	currRow.appendChild(TH({'scope':'col','id':'calendarControl' + (++i)},selectedDate.getDayName(i).substring(0,1)));
	currRow.appendChild(TH({'scope':'col','id':'calendarControl' + (++i)},selectedDate.getDayName(i).substring(0,1)));
	currRow.appendChild(TH({'scope':'col','id':'calendarControl' + (++i)},selectedDate.getDayName(i).substring(0,1)));
	currRow.appendChild(TH({'scope':'col','id':'calendarControl' + (i = 0)},selectedDate.getDayName(i).substring(0,1)));
//	append a TBODY to the TABLE
	calTable.appendChild(TBODY());
//	cache the current month
	currMonth = selectedDate.getMonth();
	var tempTime = new Date(selectedDate.getTime())
//	create TRs while the month of the date is still equal to the current month
	i = 0;
	var numRows = 0;
	while (tempTime.getMonth() == currMonth) {
		currRow = calTable.lastChild.appendChild(TR());
//		use another unrolled loop to add the TDs by calling a utility function & increment the date object
//		used to track the month we're creating; for each child node, we increment i (++ before the variable returns the incremented
//		value; after returns the unincremented value) and then test to see if there's a child node; if so, it means we've not got
//		an empty cell, which in turn means that we've completed one date for this month and need to increment the date of our date
//		tracking object
		if (currRow.appendChild(this.createCell(++i,currMonth,tempTime)).childNodes.length != 0) tempTime.setDate(tempTime.getDate() + 1);
		if (currRow.appendChild(this.createCell(++i,currMonth,tempTime)).childNodes.length != 0) tempTime.setDate(tempTime.getDate() + 1);
		if (currRow.appendChild(this.createCell(++i,currMonth,tempTime)).childNodes.length != 0) tempTime.setDate(tempTime.getDate() + 1);
		if (currRow.appendChild(this.createCell(++i,currMonth,tempTime)).childNodes.length != 0) tempTime.setDate(tempTime.getDate() + 1);
		if (currRow.appendChild(this.createCell(++i,currMonth,tempTime)).childNodes.length != 0) tempTime.setDate(tempTime.getDate() + 1);
		if (currRow.appendChild(this.createCell(++i,currMonth,tempTime)).childNodes.length != 0) tempTime.setDate(tempTime.getDate() + 1);
		if (currRow.appendChild(this.createCell(i = 0,currMonth,tempTime)).childNodes.length != 0) tempTime.setDate(tempTime.getDate() + 1);
		numRows++
	}
//	pad the bottom of the table if there are less than 6 rows so the prev/next links stay in one spot
	if (numRows < 6) {
		currRow = calTable.lastChild.appendChild(TR(TD(' '),TD(' '),TD(' '),TD(' '),TD(' '),TD(' '),TD(' ')));
	}
//	reset the selected date, then decrement the month by 2 to get the previous month for the 'previous' link (due to advancing the
//	selectedDate for the date cells, it will be 1 month ahead of the month the calendar shows)
	tempTime.setTime(selectedDate.getTime());
	tempTime.setMonth(tempTime.getMonth() - 1);
//	if the previous month isn't before the minimum valid date, add a 'previous' link
	if (tempTime.getMonth() >= this.minDate.getMonth() || tempTime.getFullYear() > this.minDate.getFullYear()) cal.appendChild(A({'href':'#','class':'previous','onclick':'return ' + this.name + '.setMonth(' + tempTime.getMonth() + ',' + tempTime.getFullYear() + ');'},'« '+tempTime.getMonthName()));
//	increment the month by 2 to get the next month after that shown
	tempTime.setMonth(tempTime.getMonth() + 2);
//	if that month isn't after the maximum selectable date, add a 'next' link
	if (tempTime.getTime() <= this.maxDate.getTime()) cal.appendChild(A({'href':'#','class':'next','onclick':'return ' + this.name + '.setMonth(' + tempTime.getMonth() + ',' + tempTime.getFullYear() + ');'},tempTime.getMonthName()+' »'));
//	add a junk markup clearing DIV -- IE goes blooey if you give the wrapper DIV layout and we need to clear the floated
//	'previous' link when the 'next' link isn't present
	cal.appendChild(DIV({'class':'fixFloat'},BR({'clear':'all'})));
	cal = this.calendar.appendChild(cal);
	//	return the calendar
	return cal;
}
//	returns a TD for a supplied day; requires a numeric day of week & month and a date object corresponding to the 
//	month for which we're generating a calendar
CalendarInput.prototype.createCell = function (day,month,calDate) {
//	create the TD and wire it up to the corresponding day TH
	var td = TD({'headers':'calendarControl' + (day)});
//	if our date is within the month for the calendar we're creating, and the day of the
//	week for the date corresponds to the day of week for the cell, add the date to the
//	cell as a text node
	if (calDate.getDay() == day && calDate.getMonth() == month) {
//		if the current date is on or after the earliest valid date make the date a link to set the calendar
		if (calDate.getTime() >= this.minDate.getTime()) td.appendChild(A({'href':'#','onclick':'return ' + this.name + '.setDate(' + calDate.getDate() + ')'}, calDate.getDate().toString()));
//		otherwise, make the date just plain text
		else td.appendChild(document.createTextNode(calDate.getDate().toString()));
	}
	return td;
}
CalendarInput.prototype.clearCalendar = function () { if (this.calendar.firstChild) {
	var anchors = this.calendar.getElementsByTagName('A'), numAnchors = anchors.length,i;
	for (i = 0; i < numAnchors; i++) anchors[i].onclick = null;
	return this.calendar.removeChild(this.calendar.firstChild);
} return false; }
CalendarInput.prototype.setMonth = function(month,year) {
	this.setSelect(this.selected.year,year);
	// because months in Date object are zero-based and in selects one-based, we need this correction.
	this.setSelect(this.selected.month,month + 1);
	this.createCalendar(month,year);
	return false;
}
CalendarInput.prototype.setDate = function(day) {
	this.hideCalendar();
	this.setSelect(this.selected.day,day);
	return false;
}
CalendarInput.prototype.setSelect = function (selectElement, which) {
	var optionElements = selectElement.getElementsByTagName('option'), numOpts = optionElements.length,i,selected,option;
	for (i = 0; i < numOpts; i++) {
		option = optionElements[i];
		if (typeof option.value != 'undefined' && option.value == which) {
			selected = option;
			option.selected = true;
		} else if (typeof option.selected != 'undefined') option.selected = false;
	}
	if (typeof selectElement.onchange == 'function') selectElement.onchange();
	return selected;
}
//	function to clean up our own mess onunload to prevent memory leaks in IE/Win
CalendarInput.prototype.cleanUp = function() {
	this.button.onclick = null;
	document.getElementsByTagName('BODY')[0].removeChild(this.calendar);
	this.dateField.removeChild(this.button);
	this.calendar = null;
	this.button = null;
	this.selected.year = null;
	this.selected.day = null;
	this.selected.month = null;
	this.dateField = null;
	window[this.name] = null;
}

