//-----------------------------------------------------------
// These variables can be set in the calling HTML page after
// calling the initCalendar function. See the configCalendar
// function for reference.
//-----------------------------------------------------------

// Calendar Postion value to show n px to the left, 0 to show aligned with select box
var pos_left = 0;

// Calendar Postion value to show n px above, 0 to show default px below
var pos_top = 22;

// Today's date.
var today;

// Interface language. Initialize with appropriate language code.
var lang;

// Maximum number of days from today which are allowed for selection.
var daysLimit;

// Date formats.
var dateFormat;


//-----------------------------------------------------------
// These variables should not be changed.
//-----------------------------------------------------------

var shownDate;

// Arrays of date cells for better performance.
var c1cells = new Array(43);
//var c2cells = new Array(43);
//Months to num array for use with Flight Search JSP to handle request from Special Offers
var m2n = new Array(12);
m2n["Jan"] = "01";
m2n["Feb"] = "02";
m2n["Mar"] = "03";
m2n["Apr"] = "04";
m2n["May"] = "05";
m2n["Jun"] = "06";
m2n["Jul"] = "07";
m2n["Aug"] = "08";
m2n["Sep"] = "09";
m2n["Oct"] = "10";
m2n["Nov"] = "11";
m2n["Dec"] = "12";
// Arrays of month names by language.
var mNames   = new Array(2);
mNames["en"] = new Array("January", "February", "March", "April", "May", "June",
                         "July", "August", "September", "October", "November", "December");
mNames["fr"] = new Array("Janvier", "Février", "Mars", "Avril", "Mai", "Juin",
                         "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre");

// Associative array of drop-downs select by field name.
var selectList = new Object();

// Associative array of date values.
var dateValue = new Object();

var departureField;
var arrivalField;
var currentDateField = null;

var overCalendar = false;
var inDateField = false;

var previousClass;

// Flag set if month change buttons should be hidden.
var isEndReached = false;
var isAtBeginning = true;


//
// Initialize calendar. Call on page load.
//
function initCalendar(departure, arrival, language) 
{
    configCalendar(language);
    // Cache calendar1 cells for better performance.
    for (var i = 1; i <= 42; i++) {
        var elem = document.getElementById("c1c" + i);
        c1cells[i] = elem;
    }
    /*
		// Cache calendar2 cells for better performance.
    for (var i = 1; i <= 42; i++) {
        var elem = document.getElementById("c2c" + i);
        c2cells[i] = elem;
    }
		*/
    selectList[departure] = new Array();    
    selectList[arrival] = new Array();
	
    departureField = document.getElementById(departure);
    arrivalField = document.getElementById(arrival);
    
    // There is a bug in Third party Calendar code.
    // it does not read the value from field on init
	currentDateField = departureField;
	dateChange(departureField);
	currentDateField = arrivalField;
	dateChange(arrivalField);
	currentDateField = null;
    // end of code by PANKAJ
}

//
// Configure calendar with default values. These values can be overriden
// by the calling HTML page after it has called initCalendar().
//
/*private*/ function configCalendar(language) 
{
    today = new Date();

    // Interface language. Initialize with appropriate language code.
    if (language != null && language != "")
    	lang = language;
    else
    	lang = "en"; // default

    // Maximum number of days from today which are allowed for selection.
    daysLimit = 722;

    // Date formats.
    dateFormat = new Object();
    dateFormat["en"] = "YYYY/MM/DD";
    dateFormat["fr"] = "AAAA/MM/JJ";
    //dateFormat["en"] = "DD/MM/YYYY";
    //dateFormat["fr"] = "JJ/MM/AAAA";
    
    shownDate = new Date(today.getFullYear(), today.getMonth(), 1);
}

//
// Must be called when the user clicks or tabs into a date input field (onfocus event).
//
function dateFocus(o) 
{
    inDateField = true;
    currentDateField = o;
    if (! overCalendar)
        showCalendar(o);

    o.select();
}

//
// Must be called when the user clicks or tabs out of a date input field (onblur event).
//
function dateBlur(o) 
{
    inDateField = false;
    if (! overCalendar)
        hideCalendar();
}

//
// Must be called when the content of a date input field changes (onchange event.
//
function dateChange(o) 
{
    if (o.value.length == 0)
        o.value = dateFormat[lang];
    o.className = "";
        
    var theDate = parseDate(o.value);

    if (o.value == dateFormat[lang])
        return;
        
    if (theDate == null || isDateBeforeToday(theDate) || isDateTooFar(theDate, 1)) {
        o.className = "invalid";
        return;
    }
    
    doAdjustDates(theDate);
}


//
// Must be called when the mouse goes over the calendar (onmouseover event). Will be called
// whenever the mouse changes date cell too.
//
function calendarOver(o) 
{
    overCalendar = true;
}

//
// Must be called when the mouse leaves the calendar (onmouseout event). Will be called
// whenever the mouse changes date cell too.
//
function calendarOut(o) 
{
//    if (! inDateField)
//        hideCalendar();
    overCalendar = false;
}

//
// Changes display class when mouse is over element.
//
function mover(target) 
{
    previousClass = target.className;
    target.className = "over";
}

//
// Restores previous display class when mouse goes off element.
//
function mout(target) 
{
    target.className = previousClass;
}

//
// Changes display class when mouse is over element.
//
function cover(target) 
{
    if (Number(target.innerHTML) > 0 && target.className != "past" && target.className != "weekendpast") {
        previousClass = target.className;
        target.className = "over";
    }
}

//
// Restores previous display class when mouse goes off element.
//
function cout(target) 
{
    if (Number(target.innerHTML) > 0 && target.className != "past" && target.className != "weekendpast") {
        target.className = previousClass;
    }
}

//
// Registers a select drop-down field so it is hidden when the calendar for
// the specified date field is displayed. Required only because of a bug with
// Internet Explorer.
//
function registerSelect(dateId, selectId) 
{
    selectList[dateId][selectList[dateId].length] = selectId;
}

//
// Display the calendar beneath the current field.
//
function showCalendar(dateField) 
{
    today = new Date();
	
    var d = dateValue[dateField.id];

    if (d != null)
        shownDate = new Date(d.getFullYear(), d.getMonth(), 1);
    else
        shownDate = new Date(today.getFullYear(), today.getMonth(), 1);

    // Position (hidden) calendar underneath field.
    var c = document.getElementById("cal");
    c.style.position = "absolute";

	if (pos_left != 0) 
    	c.style.left = (findPosX(dateField) - pos_left) + "px";
	else
    	c.style.left = findPosX(dateField) + "px";
	
	if (pos_top != 0)
		c.style.top  = (findPosY(dateField) + pos_top) + "px";
	else
    	c.style.top  = (findPosY(dateField) + 25) + "px";

    // Loop through array of select elements to hide.
    var fields = selectList[dateField.id];
    for (var i = 0; i < fields.length; i++) {
    	if (document.getElementById(fields[i]) != null)
	        document.getElementById(fields[i]).style.display = "none";
    }

    // Show calendar.
    document.getElementById("cal").style.display = "block";
    // Display dates in calendar.
    displayDates();
}

//
// Hide the currently shown calendar.
//
function hideCalendar() 
{
    // Hide calendar.
    document.getElementById("cal").style.display = "none";

    // Loop through array of previously hidden select elements.
    if (currentDateField) {
        var fields = selectList[currentDateField.id];
        for (var i = 0; i < fields.length; i++) {
	    	if (document.getElementById(fields[i]) != null)
	        	document.getElementById(fields[i]).style.display = "block";
		}
    }
    // Make sure "over" variable is reset.
    overCalendar = false;
}

//
// Move by the specified number of months.
//
function changeMonth(i) 
{
    shownDate.setMonth(shownDate.getMonth() + i);
    displayDates();
    
    currentDateField.focus();
}

//
// Select a date and close calendar.
//
function selectDate(o, monthOffset) 
{
    if (o.className == "past" || o.className == "weekendpast" || ! Number(o.innerHTML) > 0) {
        currentDateField.focus();
        return;
    }
    var newDate = new Date(shownDate.getFullYear(), shownDate.getMonth() + monthOffset, o.innerHTML);
    doAdjustDates(newDate);
    hideCalendar();
}

//
// Adjust departure and arrival fields.
//
function doAdjustDates(newDate) 
{
    dateValue[currentDateField.id] = newDate;
    currentDateField.value = formatDate(newDate, dateFormat[lang]);
    currentDateField.className = "";

    // Change one of the dates if departure is later than arrival.
    var depDate = dateValue[departureField.id];
    var arrDate = dateValue[arrivalField.id];

    if (depDate != null && arrDate != null && depDate.getTime() > arrDate.getTime()) {
        if (currentDateField.id == departureField.id) {
            arrivalField.value = departureField.value;
            dateValue[arrivalField.id] = dateValue[departureField.id];
        }
        else if (currentDateField.id == arrivalField.id) {
            departureField.value = arrivalField.value;
            dateValue[departureField.id] = dateValue[arrivalField.id];
        }
    }
}

//
// Display dates in calendar.
//
/*private*/ function displayDates() 
{
    //var nextMonthDate = new Date(shownDate.getFullYear(), shownDate.getMonth() + 1, 1);

    // Display calendar titles.
    document.getElementById("cal1Title").innerHTML = ""; // First set to empty string, required for IE 5 Mac
    document.getElementById("cal1Title").innerHTML = mNames[lang][shownDate.getMonth()] + " " + shownDate.getFullYear();
    //document.getElementById("cal2Title").innerHTML = ""; // First set to empty string, required for IE 5 Mac
    //document.getElementById("cal2Title").innerHTML = mNames[lang][nextMonthDate.getMonth()] + " " + nextMonthDate.getFullYear();

    isEndReached = false;
    isAtBeginning = false;

    displayMonth(c1cells, shownDate);
    //displayMonth(c2cells, nextMonthDate);

    // Hide month navigation as appropriate.
    document.getElementById("calarrowback").style.display = (isAtBeginning) ? "none" : "block";
    document.getElementById("calarrowfwd").style.display =  (isEndReached) ? "none" : "block";
}

// Constant containing the number of milliseconds in one day, used for date arithmetics.
var msInDay = 24*60*60*1000;

//
// Display dates for specified month.
//
/*private*/ function displayMonth(cells, monthDate) 
{
    today = new Date();
	
    var lastDate = getMonthDays(monthDate);
    var offset = getCalendarOffset(monthDate);
    var cell = null;

    // Wipe first and last rows.
    for (var i = 1; i  <= offset; i++) {
        cell = cells[i];
        cell.innerHTML = ""; // First set to empty string, required for IE 5 Mac
        cell.innerHTML = "&nbsp;";
        if (i % 7 <= 1)
            cell.className = "weekend";
        else
            cell.className = "";
    }
    for (var i = offset + lastDate; i <= 42; i++) {
        cell = cells[i];
        cell.innerHTML = ""; // First set to empty string, required for IE 5 Mac
        cell.innerHTML = "&nbsp;";
        if (i % 7 <= 1)
            cell.className = "weekend";
        else
            cell.className = "";
    }

    // Display dates.
    var isTodayMonth    = isSameMonth(monthDate, today);
    var isSelectedMonth = isSameMonth(monthDate, dateValue[currentDateField.id]);
    var isDate1Month    = isSameMonth(monthDate, dateValue[departureField.id]);
    var isDate2Month    = isSameMonth(monthDate, dateValue[arrivalField.id]);

    for (var i = 1; i <= lastDate; i++) {
        // Display day of month.
        cell = cells[i + offset];
        cell.innerHTML = ""; // First set to empty string, required for IE 5 Mac
        cell.innerHTML = i;
        
        if (monthDate.getTime() <= today.getTime()) {
            isAtBeginning = true;
        }

        var normalClass = "";
        var pastClass = "past";
        var isWeekEnd = ((i + offset) % 7) <= 1;
        if (isWeekEnd) {
            normalClass = "weekend";
            pastClass = "weekendpast";
        }
        

        // Select display class.
        if (isTodayMonth && today.getDate() > i) {
            cell.className = pastClass;
            isAtBeginning = true;
        }
        else if (isSelectedMonth && dateValue[currentDateField.id].getDate() == i) {
            // This is the currently selected date.
            cell.className = "current";
        }
        else if (isDate1Month && dateValue[departureField.id].getDate() == i) {
            cell.className = "selected";
        }
        else if (isDate2Month && dateValue[arrivalField.id].getDate() == i) {
            cell.className = "selected";
        }
        else if (isDateTooFar(monthDate, i)) {
            // This date is too far in the future.
            cell.className = pastClass;
            isEndReached = true;
        }
        else {
            cell.className = normalClass;
        }
    }
}

//
// Returns true if specificed date is before today's date.
//
/*private*/ function isDateBeforeToday(theDate) 
{
    if (theDate.getFullYear() != today.getFullYear())
        return theDate.getFullYear() < today.getFullYear();
    if (theDate.getMonth() != today.getMonth())
        return theDate.getMonth() < today.getMonth();
    return theDate.getDate() < today.getDate();
}

//
// Returns true if date is further than allowed days limit. The offset is
// added to the date, set to 1 if no offset is desired.
//
/*private*/ function isDateTooFar(theDate, offset) 
{
    // Calculate the maximum number of days from today.
    var days = Math.ceil((theDate.getTime() - today.getTime()) / msInDay) + offset - 1;
    return days > daysLimit;
}

//
// Returns the number of days in the month.
//
/*private*/ function getMonthDays(theDate) 
{
    // Return the last day of the current month. Using 0 as a date substract
    // 1 days from the next month, which is what we need.
    var lastDate = new Date(theDate.getFullYear(), theDate.getMonth() + 1, 0);
    return lastDate.getDate();
}


//
// Returns the weekday offset of the first day of the month.
//
/*private*/ function getCalendarOffset(theDate) 
{
    var firstDay = new Date(theDate.getFullYear(), theDate.getMonth(), 1);
    return firstDay.getDay();
}

//
// Returns true is the two dates have the same year and month.
//
/*private*/ function isSameMonth(firstDate, secondDate) 
{
    if (firstDate == null || secondDate == null)
        return false;
    return firstDate.getFullYear() == secondDate.getFullYear() &&
           firstDate.getMonth() == secondDate.getMonth();
}

//
// Formats date according to specified format.
//
/*private*/ function formatDate(theDate, format) 
{
    var result = format.toLowerCase();
    result = result.replace(/[ya]+/, theDate.getFullYear());
    result = result.replace(/m+/, formatToTwoDigits(theDate.getMonth() + 1));
    result = result.replace(/[dj]+/, formatToTwoDigits(theDate.getDate()));
    return result;
}

//
// Adds a leading 0 to the number if necessay so it is always 2 digits.
//
/*private*/ function formatToTwoDigits(n) 
{
    if (n > 0 && n < 10)
        return "0" + n;
    else
        return n;
}

//
// Parse a text date in dd/mm/yyyy or dd/mm/yy format and a return a date object.
// The separator can be a dash '-' instead and the year can be left out.
//
/*private*/ function parseDate(text) 
{
    var parts = text.split(/[-\/]/);
    var origPartsLenght = parts.length;
    // Validate.
    if (parts.length < 2 || parts.length > 3)
        return null;
    if (parts.length == 2)
        parts[2] = String((new Date()).getFullYear());
    else if (parts[2].length <= 2)
        parts[2] = String(2000 + Number(parts[2]));
    if (parts[0].length < 1 || parts[0].length > 2 || ! parts[0].match(/[0-9]+/))
        return null;
    if (parts[1].length < 1 || parts[1].length > 2 || ! parts[1].match(/[0-9]+/))
        return null;

    if (parts[2].length == 0 || parts[2].length == 3 ||
        parts[2].length > 4  || ! parts[2].match(/[0-9]+/))
        return null;
    var newDate = new Date(parts[2], Number(parts[1]) - 1, parts[0]);

    // Adjust year if date is past and same date next year is not too far.
    if (origPartsLenght == 2 && newDate.getTime() < today.getTime()) {
        var dateYearAdjusted = new Date(newDate.getTime());
        dateYearAdjusted.setFullYear(dateYearAdjusted.getFullYear() + 1);
        if (! isDateTooFar(dateYearAdjusted, 1))
    	    newDate = dateYearAdjusted;
    }

    return newDate;
}

//
// Two positionning functions from site http://www.quirksmode.org/js/findpos.html.
//
/*private*/ function findPosX(obj) 
{
    var curleft = 0;
    if (obj.offsetParent) {
        while (obj.offsetParent) {
            curleft += obj.offsetLeft;
            obj = obj.offsetParent;
        }
    }
    else if (obj.x)
        curleft += obj.x;
    return curleft;
}

/*private*/ function findPosY(obj) 
{
    var curtop = 0;
    if (obj.offsetParent) {
        while (obj.offsetParent) {
            curtop += obj.offsetTop;
            obj = obj.offsetParent;
        }
    }
    else if (obj.y)
        curtop += obj.y;
    return curtop;
}

function parseMonthYear(myear) 
{
	if (myear != null && myear != "" && myear.length == 7)
	{
		return m2n[myear.substring(0,3)] + "/" + myear.substring(3,7);
	}
	else
		return formatToTwoDigits(today.getMonth()+1);
}

function displayDate(d) 
{
	return formatToTwoDigits(d.getDate()) + "/" + formatToTwoDigits(d.getMonth()+1) + "/" + d.getFullYear();
}


function isDateDefined(f) 
{
	if (f.value == "")
		return false;
	if (f.value != "")
	{
		if (f.value == dateFormat[lang])
			return false;
		var theDate = parseDate(f.value);
		if (theDate == null || isDateBeforeToday(theDate) || isDateTooFar(theDate, 1)) 
		        return false;
		
	}
	return true;
}
