/*
	Holiday Extras JS calender control
	
	An OO Calander control used to output dates in an easy to use GUI
	WARNING THIS CALENDAR ONLY SUPPORTS DATES IN THE 1901-2099 RANGE
	THIS IS BECAUSE I DIDN'T WANT TO WRITE LOADS OF CODE TO HANDLE
	THE JULIAN CALENDAR AS WELL AS THE GREGORIAN CALENDAR AND I DIDN'T
	WANT TO HAVE TO DEAL WITH THE 100 AND 400 YEAR LEAP YEAR RULES!
*/

// Globals for a day change (currently 2 or 3 days on the drop down )
var gTd;
var gCal;

// Constructor for our calender object
function calendar( id, startDate, clickFunction, dateFormat, showMonth, showYear, aDates, aBlock, numDays ) {
	this.id = id;
	this.dateObject = startDate;
	this.clickFunction = clickFunction;
	this.dateFormat = dateFormat;
	this.showMonth = showMonth;
	this.showYear = showYear;
	this.aAvailDates = aDates;
	this.aBlockDates = aBlock;
	this.aSelected = new Array();
	this.write = writeCalendar;
	this.length = getLength( startDate );
	this.month = startDate.getMonth();
	this.date = startDate.getDate();
	this.day = startDate.getDay();
	this.year = startDate.getFullYear();
	this.getFormattedDate = getFormattedDate;
	this.getChauntryDate = getChauntryDate;
	this.getUnixDate = getUnixDate;
	this.numDaysToSelect = numDays;
	this.selectedUniqueCell = 0;
	// Get the first day of the passed in month's day
	startDate.setDate( 1 );
	this.firstDay = startDate.getDay();
	// Then reset the date object to the passed in date
	startDate.setDate( this.date );
}

// Global arrays for storing the days and month strings ( Change this for multi-lingual support )
var aDays = new Array( 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' );
var aMonths = new Array( 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' );

// Function that returns the date formated into a string
function getFormattedDate() {
	return aDays[this.day] + ', ' + aMonths[this.month] + ' ' + this.date + ', ' + this.year;
}

// Function that returns the date formated into a Chauntry format
function getChauntryDate() {
	var day = this.date + ""; // Add "" to convert to string
	if ( day.length == 1 ) {
		day = 0 + day;
	}
	var month = aMonths[this.month].toUpperCase();
	month = month.substr( 0, 3 );
	var year = this.year + ""; // Add "" to convert to string
	year = year.substr( 2, 3 );
	
	return day + month + year;
}

// Function that returns the date in a Unix TimeDate Stamp format
function getUnixDate() {
	var dateNoTime = new Date( Date.UTC( this.year, this.month, this.date, 0, 0, 0 ) );
	return dateNoTime.getTime() / 1000.0;
}

// Function that writes out the calender to a div
function writeCalendar() {
// Need a unique cell id for highlighting multiple days
	var uniquCellID = "";
	var calString = '<div id="calContainer_' + this.id + '">';
	// Write month and year at top of table
	calString += '<table id="cal' + this.id + '" cellspacing="0" style="border:1px black solid;">';
	// Write the navigation and month row
	calString += '<tr>';
	if ( this.showYear ) {
		calString += '<td class="nav" onClick="changeMonth(-12,\'' + this.id + '\')">&lt;&lt;</td>';
	} else {
		calString += '<td class="nav">&nbsp;</td>';
	}
	if ( this.showMonth ) {
		calString += '<td class="nav" onClick="changeMonth(-1,\'' + this.id + '\')">&lt;</td>';
	} else {
		calString += '<td class="nav">&nbsp;</td>';
	}
	calString += '<td class="month" colspan="3">' + aMonths[this.month] + ' ' + ( this.year + "" ).substring( 2, 4 ) + '</td>';
	if ( this.showMonth ) {
		calString += '<td class="nav" onClick="changeMonth(1,\'' + this.id + '\')">&gt;</td>';
	} else {
		calString += '<td class="nav">&nbsp;</td>';
	}
	if ( this.showYear ) {
		calString += '<td class="nav" onClick="changeMonth(12,\'' + this.id + '\')">&gt;&gt;</td>';
	} else {
		calString += '<td class="nav">&nbsp;</td>';
	}
	calString += '</tr>';
	// Write a row containing days of the week
	calString += '<tr>';
	// Write the days of the week headings
	for ( dow = 0; dow < aDays.length; dow++ ) {
		calString += '<th class="dayHeader">' + aDays[dow].substring( 0, 3 ) + '</th>';
	}	
	// Write the body of the calendar
	calString += '<tr>';
	// Create 6 rows so that the calendar doesn't resize
	for ( displayDay = 0; displayDay < 42; displayDay++ ) {
		var displayNum = ( displayDay - this.firstDay + 1 );
		if ( displayDay < this.firstDay ) {
			// Write the leading empty cells
			calString += '<td class="empty">&nbsp;</td>';
		} else if ( displayNum == this.date ) {
			if ( this.showMonth || this.showYear ) {
				// Unique cell identifier
				uniqueCellID = this.id + "_" + displayNum;
				// Write the selected date out with special style
				calString += '<td id="' + uniqueCellID + '" class="date">' + displayNum + '</td>';
			} else {
				// Unique cell identifier
				uniqueCellID = this.id + "_" + displayNum;
				// Show the selected date as a regular day
				calString += '<td id="' + uniqueCellID + '" class="days" onClick="javascript:changeDate(this,\'' + this.id + '\')">' + displayNum + '</td>';
			}
		} else if ( displayNum > this.length ) {
			// Write the trailing empty cells
			calString += '<td class="empty">&nbsp;</td>';
		} else {
			// Write the rest of the numbered cells
			if ( this.aAvailDates == null ) {
				// Unique cell identifier
				uniqueCellID = this.id + "_" + displayNum;
				calString += '<td id="' + uniqueCellID + '" class="days" onClick="javascript:changeDate(this,\'' + this.id + '\')">' + displayNum + '</td>';
			} else {
				uniqueCellID = this.id + "_" + displayNum;
				testDate = displayNum + "";
				if ( testDate.length == 1 ) {
					testDate = "0" + displayNum + "";
				}
				testMonth = ( this.dateObject.getMonth() + 1 ) + "";
				if ( testMonth.length == 1 ) {
					testMonth = "0" + ( this.dateObject.getMonth() + 1 ) + "";
				}
				testDate = testDate + testMonth + this.year;
				// If we passed an array of dates in, check against it.
				if ( this.aAvailDates.inArray( testDate ) ) {
					calString += '<td id="' + uniqueCellID + '" class="days" onClick="javascript:changeDate(this,\'' + this.id + '\')">' + displayNum + '</td>';
				} else {
					if ( 	this.aBlockDates == null ) {
						calString += '<td id="' + uniqueCellID + '" class="offDays">' + displayNum + '</td>';
					} else {
						// Deal with non avilable days
						if ( displayNum > this.aBlockDates[0] && displayNum < this.aBlockDates[1] ) {
							calString += '<td id="" class="blockDays">' + displayNum + '</td>';
						} else {
							calString += '<td id="" class="offDays">' + displayNum + '</td>';
						}
					}
				}	
			}
		}
		if ( displayDay % 7 == 6 ) {
			calString += '</tr><tr>';
		}
	}
	// Close the last number row
	calString += '</tr>';
	calString += '</table>';
	calString += '</div>';
	return calString;
}

// Fuction thats get the length of a month
function getLength( dateObj ) {
	// Calculate the 30 and 31 one day months, plus calculate if February has 28 or 29 days in the current year
	var daysCount;
	switch( dateObj.getMonth() ) {
		case 1:
			if ( ( dateObj.getFullYear() % 4 == 0 && dateObj.getFullYear() % 100 != 0 ) || dateObj.getFullYear() % 400 == 0 ) {
				daysCount = 29; // leap year
			} else {
				daysCount = 28;
			}
			break;
		case 3:
			daysCount = 30;
			break;
		case 5:
			daysCount = 30;
			break;
		case 8:
			daysCount = 30;
			break;
		case 10:
			daysCount = 30;
			break;
		default:
			daysCount = 31;
	}
	return daysCount;
}

// Function to unselect previously selected days.
function unselectDays() {
	// Loop round the number of calenders on display
	for ( calCount = 0; calCount < 2; calCount++ ) {
		cal = eval( aCalendarNames[currentCalendar + calCount] );
		// Un hilite old days on the first calender
		if ( cal.aSelected.length > 0) {
			for ( cellNo = 0; cellNo < cal.aSelected.length; cellNo++ ) {
				cellUnselect = cal.id + '_' + cal.aSelected[cellNo];
				document.getElementById( cellUnselect ).className = "days";
			}
			cal.aSelected = new Array();
		}
	}
}

/* function getNextDay() {} */
// Function that changes the date
function changeDate( td, cal) {
	// Store td and cal in global vars for the days change
	gTd = td;
	gCal = cal;
	// Change the cal argument to the existing calendar object
	// This is why the first argument in the constructor must match the variable name
	// The cal reference also allows for multiple calendars on a page
	cal = eval( cal );
	// Un hilite old days before selecting new ones
	unselectDays();
	
	// Now get our selected dates
	aCellNameSplit = td.id.split('_');
	cal.selectedUniqueCell = td.id;
	document.getElementById( td.id ).className = "daySelected";
	// Add day to the selected array
	cal.aSelected[cal.aSelected.length] = aCellNameSplit[1];
	
	// Var to track whether park will be closed during some of selected period
	var noPark = false;
	
	// Repeate for each additional day
	for ( cellCount = 1; cellCount < cal.numDaysToSelect; cellCount++ ) {
		// Get our new day number
		otherCellNo = aCellNameSplit[1] - 0;
		otherCellNo = otherCellNo + cellCount;
		otherCellName = aCellNameSplit[0] + '_' + otherCellNo;
		// Generate a string version of our second day
		if ( ( otherCellNo + "" ).length == 1 ) {
			searchDate = "0" + otherCellNo;
		} else {
			searchDate = "" + otherCellNo;
		}
		if ( cal.month < 9 ) {
			searchDate = searchDate + "0" + ( cal.month + 1) + cal.year;
		} else {
			searchDate = searchDate + ( cal.month + 1) + cal.year;
		}
		// Check if our other day is in our available dates array
		if ( findValueInArray( searchDate, cal.aAvailDates ) != -1 ) {
			// Hilite the other day
			document.getElementById( otherCellName ).className = "daySelected";
			// Add day to the selected array
			cal.aSelected[cal.aSelected.length] = otherCellNo;
		} else {
			// Days are outside the bounds of the list, we need to check if they are valid days or if they are next month
			var testDate = new Date()
			testDate.setFullYear( searchDate.substr( 4, 4 ), ( searchDate.substr( 2, 2 ) - 1 ), aCellNameSplit[1] - 0 );
			realDate = new Date( testDate.getTime() + ( cellCount * 86400000 /*one day*/) );
			// Compare the month on the testDate with the realDate
			if ( testDate.getMonth() != realDate.getMonth() ) {
				if ( cal.id == aCalendarNames[currentCalendar] ) {
					// We are the left hand calender so we can select additional days
					cal = eval( aCalendarNames[currentCalendar + 1] );
					otherCellName = aCalendarNames[currentCalendar + 1] + "_" + realDate.getDate();
					// Hilite the other day
					document.getElementById( otherCellName ).className = "daySelected";
					// Add day to the selected array
					cal.aSelected[cal.aSelected.length] = realDate.getDate();
					// RESET CAL as we may have changed it
					cal = eval( aCalendarNames[currentCalendar] );
				} else {
					// We are the right hand calender so we need to move the calenders first
					if ( ( currentCalendar + 2 ) < aCalendarNames.length ) {
						// Move the calanders to display the correct months
						scrollCalendars( 1 );
						checkLinks();
						// Now we need to hilite the days again
						changeDate( gTd ,gCal );
					}
				}
			} else {
				noPark = true;
			}
		}
	}
	
	if( noPark) {
		alert("Please be advised that LEGOLAND Windsor will be closed on one or more of the days you have selected. You may still book your tickets, but will be unable to take full advantage of the free day offer.");
	}
	
	// Set the calendar object to the new date ( we reset the calender obj to do a redraw )
	cal.dateObject.setDate( td.firstChild.nodeValue );
	cal = new calendar( cal.id, cal.dateObject, cal.clickFunction, cal.dateFormat, cal.aAvailDates );  
	// Here is where we react to a date change - We call the function that was passed in.
	if ( cal.dateFormat == "unix" ) {
		var functionCallStr = cal.clickFunction + "( '" + cal.getUnixDate() + "' )";
	} else if ( cal.dateFormat == "chauntry" ) {
		var functionCallStr = cal.clickFunction + "( '" + cal.getChauntryDate() + "' )";
	} else {
		var functionCallStr = cal.clickFunction + "( '" + cal.getFormattedDate() + "' )";
	}
	
	eval( functionCallStr );
}

// Function that goes forward or back a month
function changeMonth( month, cal ) {
	// The Date object is smart enough to know that it should roll over in December and January ( except on safari !!! )
	cal = eval( cal );
	// Set the calendar object to the new month ( we reset the calender obj to do a redraw )
	cal.dateObject.setMonth( cal.dateObject.getMonth() + month );
	cal = new calendar( cal.id, cal.dateObject, cal.clickFunction, cal.dateFormat, cal.showMonth, cal.showYear, cal.aAvailDates );
	//cal.formattedDate = cal.getFormattedDate();
	// Commented code out as I don't think it is required any more.
	document.getElementById( 'calContainer_' + cal.id ).innerHTML = cal.write();
}

function onDateChange( selectedDate ) {
	
	document.searchForm.ParkDate.value = selectedDate;
	hotelArrivalDate();
	dateSpecificEvents( frm.ParkDate.value);
}

function convertDate(dt) {
	var temp = new Date(2006,1,1,0,0,0);
	
	d = dt.substr(0,2);
	m = dt.substr(2,2);
	y = dt.substr(4,4);
	
	temp.setFullYear(y,m-1,d);
	//temp.setTime(0);
	return temp;
}


function removeDates(aDates, today) {
	// Need to remove days from current month if before today
	// Rather, dont show days as available if the date has already passed
	
	// Set the time to zero, midnight.
	var i=0;
	var tempDate = new Date();
	tempDate.setFullYear(2006,0,1);
	while((tempDate < today) && (aDates.length > i)) {
		// do a substring to get days, months and years;
		tempDate = convertDate(aDates[i]);
		i++;
	}
	// We only want elements after and including i
	var result = aDates.slice(i-1);
	
	return result;
}

// Returns true if the passed value is found in the array.  Returns false if it is not.
Array.prototype.inArray = function( testStr ) {
	for ( index = 0; index < this.length; index++ ) {
		// Matches identical (===), not just similar (==).
		if ( this[index] === testStr ) {
			return true;
		}
	}
	return false;
};

// Returns the position of an array item (or -1 if not in array)
function findValueInArray( searchVal, aSearch ) {
	var count = 0;
	var iMin = 0;
	var iMax = aSearch.length - 1;
	var bFound = false;
	count = iMin - 1;
	while ( ( count <= iMax ) && ( !( bFound ) ) ) {
		count = count + 1;
		currValue = aSearch[ count ];
		bFound = ( searchVal == currValue );
	}
	if ( bFound ) {
		return( count );
	} else {
		return( -1 );
	}
}