﻿/******************************************************************************/
/**************************** AC_RunActiveContent.js **************************/
/******************************************************************************/
//v1.7
// Flash Player Version Detection
// Detect Client Browser type
// Copyright 2005-2007 Adobe Systems Incorporated.  All rights reserved.
var isIE = (navigator.appVersion.indexOf("MSIE") != -1) ? true : false;
var isWin = (navigator.appVersion.toLowerCase().indexOf("win") != -1) ? true : false;
var isOpera = (navigator.userAgent.indexOf("Opera") != -1) ? true : false;

function ControlVersion() {
    var version;
    var axo;
    var e;

    // NOTE : new ActiveXObject(strFoo) throws an exception if strFoo isn't in the registry

    try {
        // version will be set for 7.X or greater players
        axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");
        version = axo.GetVariable("$version");
    } catch (e) {
    }

    if (!version) {
        try {
            // version will be set for 6.X players only
            axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");

            // installed player is some revision of 6.0
            // GetVariable("$version") crashes for versions 6.0.22 through 6.0.29,
            // so we have to be careful. 

            // default to the first public version
            version = "WIN 6,0,21,0";

            // throws if AllowScripAccess does not exist (introduced in 6.0r47)		
            axo.AllowScriptAccess = "always";

            // safe to call for 6.0r47 or greater
            version = axo.GetVariable("$version");

        } catch (e) {
        }
    }

    if (!version) {
        try {
            // version will be set for 4.X or 5.X player
            axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");
            version = axo.GetVariable("$version");
        } catch (e) {
        }
    }

    if (!version) {
        try {
            // version will be set for 3.X player
            axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash.3");
            version = "WIN 3,0,18,0";
        } catch (e) {
        }
    }

    if (!version) {
        try {
            // version will be set for 2.X player
            axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash");
            version = "WIN 2,0,0,11";
        } catch (e) {
            version = -1;
        }
    }

    return version;
}

// JavaScript helper required to detect Flash Player PlugIn version information
function GetSwfVer() {
    // NS/Opera version >= 3 check for Flash plugin in plugin array
    var flashVer = -1;

    if (navigator.plugins != null && navigator.plugins.length > 0) {
        if (navigator.plugins["Shockwave Flash 2.0"] || navigator.plugins["Shockwave Flash"]) {
            var swVer2 = navigator.plugins["Shockwave Flash 2.0"] ? " 2.0" : "";
            var flashDescription = navigator.plugins["Shockwave Flash" + swVer2].description;
            var descArray = flashDescription.split(" ");
            var tempArrayMajor = descArray[2].split(".");
            var versionMajor = tempArrayMajor[0];
            var versionMinor = tempArrayMajor[1];
            var versionRevision = descArray[3];
            if (versionRevision == "") {
                versionRevision = descArray[4];
            }
            if (versionRevision[0] == "d") {
                versionRevision = versionRevision.substring(1);
            } else if (versionRevision[0] == "r") {
                versionRevision = versionRevision.substring(1);
                if (versionRevision.indexOf("d") > 0) {
                    versionRevision = versionRevision.substring(0, versionRevision.indexOf("d"));
                }
            }
            var flashVer = versionMajor + "." + versionMinor + "." + versionRevision;
        }
    }
    // MSN/WebTV 2.6 supports Flash 4
    else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.6") != -1) flashVer = 4;
    // WebTV 2.5 supports Flash 3
    else if (navigator.userAgent.toLowerCase().indexOf("webtv/2.5") != -1) flashVer = 3;
    // older WebTV supports Flash 2
    else if (navigator.userAgent.toLowerCase().indexOf("webtv") != -1) flashVer = 2;
    else if (isIE && isWin && !isOpera) {
        flashVer = ControlVersion();
    }
    return flashVer;
}

// When called with reqMajorVer, reqMinorVer, reqRevision returns true if that version or greater is available
function DetectFlashVer(reqMajorVer, reqMinorVer, reqRevision) 
{
    versionStr = GetSwfVer();
    if (versionStr == -1) {
        return false;
    } else if (versionStr != 0) {
        if (isIE && isWin && !isOpera) {
            // Given "WIN 2,0,0,11"
            tempArray = versionStr.split(" "); 	// ["WIN", "2,0,0,11"]
            tempString = tempArray[1]; 		// "2,0,0,11"
            versionArray = tempString.split(","); // ['2', '0', '0', '11']
        } else {
            versionArray = versionStr.split(".");
        }
        var versionMajor = versionArray[0];
        var versionMinor = versionArray[1];
        var versionRevision = versionArray[2];

        // is the major.revision >= requested major.revision AND the minor version >= requested minor
        if (versionMajor > parseFloat(reqMajorVer)) {
            return true;
        } else if (versionMajor == parseFloat(reqMajorVer)) {
            if (versionMinor > parseFloat(reqMinorVer))
                return true;
            else if (versionMinor == parseFloat(reqMinorVer)) {
                if (versionRevision >= parseFloat(reqRevision))
                    return true;
            }
        }
        return false;
    }
}

function AC_AddExtension(src, ext) 
{
    if (src.indexOf('?') != -1)
        return src.replace(/\?/, ext + '?');
    else
        return src + ext;
}

function AC_Generateobj(objAttrs, params, embedAttrs) 
{
    var str = '';
    if (isIE && isWin && !isOpera) {
        str += '<object ';
        for (var i in objAttrs) {
            str += i + '="' + objAttrs[i] + '" ';
        }
        str += '>';
        for (var i in params) {
            str += '<param name="' + i + '" value="' + params[i] + '" /> ';
        }
        str += '</object>';
    }
    else {
        str += '<embed ';
        for (var i in embedAttrs) {
            str += i + '="' + embedAttrs[i] + '" ';
        }
        str += '> </embed>';
    }

    document.write(str);
}

function AC_FL_RunContent() {
    var ret =
    AC_GetArgs
    (arguments, ".swf", "movie", "clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
     , "application/x-shockwave-flash"
    );
    AC_Generateobj(ret.objAttrs, ret.params, ret.embedAttrs);
}

function AC_SW_RunContent() {
    var ret =
    AC_GetArgs
    (arguments, ".dcr", "src", "clsid:166B1BCA-3F9C-11CF-8075-444553540000"
     , null
    );
    AC_Generateobj(ret.objAttrs, ret.params, ret.embedAttrs);
}

function AC_GetArgs(args, ext, srcParamName, classid, mimeType) {
    var ret = new Object();
    ret.embedAttrs = new Object();
    ret.params = new Object();
    ret.objAttrs = new Object();
    for (var i = 0; i < args.length; i = i + 2) {
        var currArg = args[i].toLowerCase();

        switch (currArg) {
            case "classid":
                break;
            case "pluginspage":
                ret.embedAttrs[args[i]] = args[i + 1];
                break;
            case "src":
            case "movie":
                args[i + 1] = AC_AddExtension(args[i + 1], ext);
                ret.embedAttrs["src"] = args[i + 1];
                ret.params[srcParamName] = args[i + 1];
                break;
            case "onafterupdate":
            case "onbeforeupdate":
            case "onblur":
            case "oncellchange":
            case "onclick":
            case "ondblclick":
            case "ondrag":
            case "ondragend":
            case "ondragenter":
            case "ondragleave":
            case "ondragover":
            case "ondrop":
            case "onfinish":
            case "onfocus":
            case "onhelp":
            case "onmousedown":
            case "onmouseup":
            case "onmouseover":
            case "onmousemove":
            case "onmouseout":
            case "onkeypress":
            case "onkeydown":
            case "onkeyup":
            case "onload":
            case "onlosecapture":
            case "onpropertychange":
            case "onreadystatechange":
            case "onrowsdelete":
            case "onrowenter":
            case "onrowexit":
            case "onrowsinserted":
            case "onstart":
            case "onscroll":
            case "onbeforeeditfocus":
            case "onactivate":
            case "onbeforedeactivate":
            case "ondeactivate":
            case "type":
            case "codebase":
            case "id":
                ret.objAttrs[args[i]] = args[i + 1];
                break;
            case "width":
            case "height":
            case "align":
            case "vspace":
            case "hspace":
            case "class":
            case "title":
            case "accesskey":
            case "name":
            case "tabindex":
                ret.embedAttrs[args[i]] = ret.objAttrs[args[i]] = args[i + 1];
                break;
            default:
                ret.embedAttrs[args[i]] = ret.params[args[i]] = args[i + 1];
        }
    }
    ret.objAttrs["classid"] = classid;
    if (mimeType) ret.embedAttrs["type"] = mimeType;
    return ret;
}



/******************************************************************************/
/***************************** sts-lowcost.js  ********************************/
/******************************************************************************/
var spanFromCountryList;
var spanToCountryList;
var spanFromPortList;
var spanToPortList;
var spanFareList;
var reloadPortData;

var LocationType = { "From": 1, "To": 2 };

function initLowCost(spanFromCountryListId, spanToCountryListId, spanFromPortListId, spanToPortListId, spanFareListId) {
    spanFromCountryList = $get(spanFromCountryListId);
    spanToCountryList = $get(spanToCountryListId);
    spanFromPortList = $get(spanFromPortListId);
    spanToPortList = $get(spanToPortListId);
    spanFareList = $get(spanFareListId);

    bindCountryData(LocationType.From, "");
}

function ShowLoading(span) {
    span.innerHTML = "<IMG src=\"/img/loading.gif\" />";
}

function FromSetSelected(countryName) {
    //   alert('hi');
    SetSelected(countryName, "From");
    bindCountryData(LocationType.To, countryName);
    reloadPortData = true;
}

function ToSetSelected(countryName) {
    SetSelected(countryName, "To");
    bindPortData(LocationType.To, bindPortToResults);
}

function SetSelected(countryName, type) {
    //   alert('ok2');
    $("#list" + type + " li:odd").removeClass("selected");
    $("#list" + type + " li:even").removeClass("selected").addClass("alt");
    $get("txt" + type + "CountryName").value = countryName;

    var liCountry = $get("li" + type + countryName.replace(" ", "_"));
    if (liCountry != null) {
        liCountry.className = "selected";
    }

    bindPriceData();
}


//=============== FARE DATA =======================//

function bindPriceData() {
    if (spanFareList) {
        ShowLoading(spanFareList);

        var url = "/JSON/GetSalesFareData/" + $get('txtFromCountryName').value + "/" + $get('txtToCountryName').value;
        $.getJSON(url, bindFareDataResults);
    }
}

function bindFareDataResults(data) {
    var html = new Sys.StringBuilder();
    var className = "";

    html.append("<ul>");
    for (var i = 0; i < data.length; i++) {
        className = "";
        if (i % 2 == 0) {
            className = "class=\"alt\"";
        }

        html.append("<li " + className + "'><img src=\"/img/airline-logos/lcc/" + data[i].AirlineCode + ".gif\" align=\"absmiddle\" style=\"margin-right:20px;\"/>$" + data[i].FromPrice + "</li>");
    }
    html.append("</ul>");
    spanFareList.innerHTML = html;
}
//=============== END FARE DATA =======================//


//=============== PORT DATA =======================//
function bindPortData(type) {
    var bindResultsFunction;

    if (spanFromPortList && spanToPortList) {
        if (type == LocationType.From) {
            bindResultsFunction = bindPortFromResults;
            ShowLoading(spanFromPortList);
        }
        else {
            bindResultsFunction = bindPortToResults;
            ShowLoading(spanToPortList);
        }

        countryNameFrom = $get('txtFromCountryName').value;
        countryNameTo = $get('txtToCountryName').value;

        var url = "/JSON/GetPortData/" + type + "/" + countryNameFrom;
        if (countryNameTo.length != 0)
            url += "/" + countryNameTo;
        $.getJSON(url, bindResultsFunction);
    }
}

function bindPortFromResults(data) {
    BindResults(false, data, spanFromPortList, "");
}

function bindPortToResults(data) {
    BindResults(false, data, spanToPortList, "");
}

//=============== END PORT DATA =======================//


//=============== COUNTRY DATA =======================//
function bindCountryData(type, countryName) {
    if (spanToCountryList && spanFromCountryList) {
        var bindResultsFunction

        if (type == LocationType.From) {
            ShowLoading(spanFromCountryList);
            bindResultsFunction = bindCountryFromResults;
        }
        else {
            ShowLoading(spanToCountryList);
            bindResultsFunction = bindCountryToResults;
        }

        var url = "/JSON/GetSalesCountryData/" + countryName;
        $.getJSON(url, bindResultsFunction);
    }
}


function bindCountryFromResults(data) {
    BindResults(true, data, spanFromCountryList, "From");
    countryName = $get('txtFromCountryName').value;

    if (spanFromPortList)
        bindPortData(LocationType.From);

    bindCountryData(LocationType.To, countryName);
}


function bindCountryToResults(data) {
    BindResults(true, data, spanToCountryList, "To");

    if (spanToPortList) {
        bindPortData(LocationType.To, bindPortToResults);
        if (reloadPortData) bindPortData(LocationType.From, bindPortToResults);
    }

    bindPriceData();
}

//=============== COUNTRY DATA =======================//


//=============== COMMON =======================//
function BindResults(renderSelected, data, span, type) {
    var html = new Sys.StringBuilder();
    var className = "";
    var linkText = "";

    html.append("<ul id=\"list" + type + "\">");
    for (var i = 0; i < data.length; i++) {
        className = "";
        if (i % 2 == 0) {
            className = "class=\"alt\"";
        }
        if (i == 0) {
            className = "class=\"selected\"";
            if (renderSelected) $get("txt" + type + "CountryName").value = data[i];
        }

        if (renderSelected)
            linkText = "<a href='javascript:" + type + "SetSelected(\"" + data[i] + "\");'>" + data[i] + "</a>";
        else
            linkText = data[i];

        html.append("<li " + className + " id='li" + type + data[i].replace(" ", "_") + "'>" + linkText + "</li>");
    }
    html.append("</ul>");
    span.innerHTML = html;
}
//=============== END COMMON =======================//



/******************************************************************************/
/****************************** sts-utilities.js ******************************/
/******************************************************************************/
function changeDivs(divName) {
    if (divName == '') {
        divName = 'dvAustralia';
    }
    document.getElementById('dvUkEurope').style.display = 'none';
    document.getElementById('dvNAmerica').style.display = 'none';
    document.getElementById('dvAsia').style.display = 'none';
    document.getElementById('dvAustralia').style.display = 'none';
    document.getElementById('dvSAmerica').style.display = 'none';
    document.getElementById('dvAfrica').style.display = 'none';

    document.getElementById(divName).style.display = 'block';
}

function changeDivsBeen(divName) {
    if (divName == '') {
        divName = 'dvEurope';
    }
    document.getElementById('dvAfrica').style.display = 'none';
    document.getElementById('dvNAmerica').style.display = 'none';
    document.getElementById('dvSAmerica').style.display = 'none';
    document.getElementById('dvAsia').style.display = 'none';
    document.getElementById('dvPacfic').style.display = 'none';
    document.getElementById('dvEurope').style.display = 'none';
    document.getElementById('dvMEast').style.display = 'none';

    document.getElementById(divName).style.display = 'block';
}

function changeDivs2Centre(divName) {
    if (divName == '') {
        divName = 'dvSingapore';
    }
    document.getElementById('dvKualaLumpur').style.display = 'none';
    document.getElementById('dvBangkok').style.display = 'none';
    document.getElementById('dvBrunei').style.display = 'none';
    document.getElementById('dvSingapore').style.display = 'none';

    document.getElementById(divName).style.display = 'block';
}

function CopyTextBoxValues(sourceName, targetName) {
    var sourceObject = document.getElementById(sourceName);
    var targetObject = document.getElementById(targetName);

    if (sourceObject != null && targetObject != null) {
        targetObject.value = sourceObject.value;
    }
}

function CopySelectListValues(sourceName, targetName) {
    var sourceObject = document.getElementById(sourceName);
    var targetObject = document.getElementById(targetName);

    if (sourceObject != null && targetObject != null) {
        targetObject.selectedIndex = sourceObject.selectedIndex;
    }
}



/******************************************************************************/
/********************************** date.js ***********************************/
/******************************************************************************/
/*
* Date prototype extensions. Doesn't depend on any
* other code. Doens't overwrite existing methods.
*
* Adds dayNames, abbrDayNames, monthNames and abbrMonthNames static properties and isLeapYear,
* isWeekend, isWeekDay, getDaysInMonth, getDayName, getMonthName, getDayOfYear, getWeekOfYear,
* setDayOfYear, addYears, addMonths, addDays, addHours, addMinutes, addSeconds methods
*
* Copyright (c) 2006 Jörn Zaefferer and Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
*
* Additional methods and properties added by Kelvin Luck: firstDayOfWeek, dateFormat, zeroTime, asString, fromString -
* I've added my name to these methods so you know who to blame if they are broken!
* 
* Dual licensed under the MIT and GPL licenses:
*   http://www.opensource.org/licenses/mit-license.php
*   http://www.gnu.org/licenses/gpl.html
*
*/

/**
* An Array of day names starting with Sunday.
* 
* @example dayNames[0]
* @result 'Sunday'
*
* @name dayNames
* @type Array
* @cat Plugins/Methods/Date
*/
Date.dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];

/**
* An Array of abbreviated day names starting with Sun.
* 
* @example abbrDayNames[0]
* @result 'Sun'
*
* @name abbrDayNames
* @type Array
* @cat Plugins/Methods/Date
*/
Date.abbrDayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];

/**
* An Array of month names starting with Janurary.
* 
* @example monthNames[0]
* @result 'January'
*
* @name monthNames
* @type Array
* @cat Plugins/Methods/Date
*/
Date.monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];

/**
* An Array of abbreviated month names starting with Jan.
* 
* @example abbrMonthNames[0]
* @result 'Jan'
*
* @name monthNames
* @type Array
* @cat Plugins/Methods/Date
*/
Date.abbrMonthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];

/**
* An Array of months translated from getDate().
* 
* @example monthArrayTranslation[0]
* @result '1'
*

*/
Date.monthArrayTranslation = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'];

/**
* The first day of the week for this locale.
*
* @name firstDayOfWeek
* @type Number
* @cat Plugins/Methods/Date
* @author Kelvin Luck
*/
Date.firstDayOfWeek = 1;

/**
* The format that string dates should be represented as (e.g. 'dd/mm/yyyy' for UK, 'mm/dd/yyyy' for US, 'yyyy-mm-dd' for Unicode etc).
*
* @name format
* @type String
* @cat Plugins/Methods/Date
* @author Kelvin Luck
*/
Date.format = 'dd/mm/yyyy';
//Date.format = 'mm/dd/yyyy';
//Date.format = 'yyyy-mm-dd';
//Date.format = 'dd mmm yy';

/**
* The first two numbers in the century to be used when decoding a two digit year. Since a two digit year is ambiguous (and date.setYear
* only works with numbers < 99 and so doesn't allow you to set years after 2000) we need to use this to disambiguate the two digit year codes.
*
* @name format
* @type String
* @cat Plugins/Methods/Date
* @author Kelvin Luck
*/
Date.fullYearStart = '20';

(function() {

    /**
    * Adds a given method under the given name 
    * to the Date prototype if it doesn't
    * currently exist.
    *
    * @private
    */
    function add(name, method) {
        if (!Date.prototype[name]) {
            Date.prototype[name] = method;
        }
    };

    /**
    * Checks if the year is a leap year.
    *
    * @example var dtm = new Date("01/12/2008");
    * dtm.isLeapYear();
    * @result true
    *
    * @name isLeapYear
    * @type Boolean
    * @cat Plugins/Methods/Date
    */
    add("isLeapYear", function() {
        var y = this.getFullYear();
        return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
    });

    /**
    * Checks if the day is a weekend day (Sat or Sun).
    *
    * @example var dtm = new Date("01/12/2008");
    * dtm.isWeekend();
    * @result false
    *
    * @name isWeekend
    * @type Boolean
    * @cat Plugins/Methods/Date
    */
    add("isWeekend", function() {
        return this.getDay() == 0 || this.getDay() == 6;
    });

    /**
    * Check if the day is a day of the week (Mon-Fri)
    * 
    * @example var dtm = new Date("01/12/2008");
    * dtm.isWeekDay();
    * @result false
    * 
    * @name isWeekDay
    * @type Boolean
    * @cat Plugins/Methods/Date
    */
    add("isWeekDay", function() {
        return !this.isWeekend();
    });

    /**
    * Gets the number of days in the month.
    * 
    * @example var dtm = new Date("01/12/2008");
    * dtm.getDaysInMonth();
    * @result 31
    * 
    * @name getDaysInMonth
    * @type Number
    * @cat Plugins/Methods/Date
    */
    add("getDaysInMonth", function() {
        return [31, (this.isLeapYear() ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][this.getMonth()];
    });

    /**
    * Gets the name of the day.
    * 
    * @example var dtm = new Date("01/12/2008");
    * dtm.getDayName();
    * @result 'Saturday'
    * 
    * @example var dtm = new Date("01/12/2008");
    * dtm.getDayName(true);
    * @result 'Sat'
    * 
    * @param abbreviated Boolean When set to true the name will be abbreviated.
    * @name getDayName
    * @type String
    * @cat Plugins/Methods/Date
    */
    add("getDayName", function(abbreviated) {
        return abbreviated ? Date.abbrDayNames[this.getDay()] : Date.dayNames[this.getDay()];
    });

    /**
    * Gets the name of the month.
    * 
    * @example var dtm = new Date("01/12/2008");
    * dtm.getMonthName();
    * @result 'Janurary'
    *
    * @example var dtm = new Date("01/12/2008");
    * dtm.getMonthName(true);
    * @result 'Jan'
    * 
    * @param abbreviated Boolean When set to true the name will be abbreviated.
    * @name getDayName
    * @type String
    * @cat Plugins/Methods/Date
    */
    add("getMonthName", function(abbreviated) {
        return abbreviated ? Date.abbrMonthNames[this.getMonth()] : Date.monthNames[this.getMonth()];
    });

    /**
    * Get the number of the day of the year.
    * 
    * @example var dtm = new Date("01/12/2008");
    * dtm.getDayOfYear();
    * @result 11
    * 
    * @name getDayOfYear
    * @type Number
    * @cat Plugins/Methods/Date
    */
    add("getDayOfYear", function() {
        var tmpdtm = new Date("1/1/" + this.getFullYear());
        return Math.floor((this.getTime() - tmpdtm.getTime()) / 86400000);
    });

    /**
    * Get the number of the week of the year.
    * 
    * @example var dtm = new Date("01/12/2008");
    * dtm.getWeekOfYear();
    * @result 2
    * 
    * @name getWeekOfYear
    * @type Number
    * @cat Plugins/Methods/Date
    */
    add("getWeekOfYear", function() {
        return Math.ceil(this.getDayOfYear() / 7);
    });

    /**
    * Set the day of the year.
    * 
    * @example var dtm = new Date("01/12/2008");
    * dtm.setDayOfYear(1);
    * dtm.toString();
    * @result 'Tue Jan 01 2008 00:00:00'
    * 
    * @name setDayOfYear
    * @type Date
    * @cat Plugins/Methods/Date
    */
    add("setDayOfYear", function(day) {
        this.setMonth(0);
        this.setDate(day);
        return this;
    });

    /**
    * Add a number of years to the date object.
    * 
    * @example var dtm = new Date("01/12/2008");
    * dtm.addYears(1);
    * dtm.toString();
    * @result 'Mon Jan 12 2009 00:00:00'
    * 
    * @name addYears
    * @type Date
    * @cat Plugins/Methods/Date
    */
    add("addYears", function(num) {
        this.setFullYear(this.getFullYear() + num);
        return this;
    });

    /**
    * Add a number of months to the date object.
    * 
    * @example var dtm = new Date("01/12/2008");
    * dtm.addMonths(1);
    * dtm.toString();
    * @result 'Tue Feb 12 2008 00:00:00'
    * 
    * @name addMonths
    * @type Date
    * @cat Plugins/Methods/Date
    */
    add("addMonths", function(num) {
        var tmpdtm = this.getDate();

        this.setMonth(this.getMonth() + num);

        if (tmpdtm > this.getDate())
            this.addDays(-this.getDate());

        return this;
    });

    /**
    * Add a number of days to the date object.
    * 
    * @example var dtm = new Date("01/12/2008");
    * dtm.addDays(1);
    * dtm.toString();
    * @result 'Sun Jan 13 2008 00:00:00'
    * 
    * @name addDays
    * @type Date
    * @cat Plugins/Methods/Date
    */
    add("addDays", function(num) {
        //this.setDate(this.getDate() + num);
        this.setTime(this.getTime() + (num * 86400000));
        return this;
    });

    /**
    * Add a number of hours to the date object.
    * 
    * @example var dtm = new Date("01/12/2008");
    * dtm.addHours(24);
    * dtm.toString();
    * @result 'Sun Jan 13 2008 00:00:00'
    * 
    * @name addHours
    * @type Date
    * @cat Plugins/Methods/Date
    */
    add("addHours", function(num) {
        this.setHours(this.getHours() + num);
        return this;
    });

    /**
    * Add a number of minutes to the date object.
    * 
    * @example var dtm = new Date("01/12/2008");
    * dtm.addMinutes(60);
    * dtm.toString();
    * @result 'Sat Jan 12 2008 01:00:00'
    * 
    * @name addMinutes
    * @type Date
    * @cat Plugins/Methods/Date
    */
    add("addMinutes", function(num) {
        this.setMinutes(this.getMinutes() + num);
        return this;
    });

    /**
    * Add a number of seconds to the date object.
    * 
    * @example var dtm = new Date("01/12/2008");
    * dtm.addSeconds(60);
    * dtm.toString();
    * @result 'Sat Jan 12 2008 00:01:00'
    * 
    * @name addSeconds
    * @type Date
    * @cat Plugins/Methods/Date
    */
    add("addSeconds", function(num) {
        this.setSeconds(this.getSeconds() + num);
        return this;
    });

    /**
    * Sets the time component of this Date to zero for cleaner, easier comparison of dates where time is not relevant.
    * 
    * @example var dtm = new Date();
    * dtm.zeroTime();
    * dtm.toString();
    * @result 'Sat Jan 12 2008 00:01:00'
    * 
    * @name zeroTime
    * @type Date
    * @cat Plugins/Methods/Date
    * @author Kelvin Luck
    */
    add("zeroTime", function() {
        this.setMilliseconds(0);
        this.setSeconds(0);
        this.setMinutes(0);
        this.setHours(0);
        return this;
    });

    /**
    * Returns a string representation of the date object according to Date.format.
    * (Date.toString may be used in other places so I purposefully didn't overwrite it)
    * 
    * @example var dtm = new Date("01/12/2008");
    * dtm.asString();
    * @result '12/01/2008' // (where Date.format == 'dd/mm/yyyy'
    * 
    * @name asString
    * @type Date
    * @cat Plugins/Methods/Date
    * @author Kelvin Luck
    */
    add("asString", function(format) {
        var r = format || Date.format;
        return r
			.split('yyyy').join(this.getFullYear())
			.split('yy').join((this.getFullYear() + '').substring(2))
			.split('mmmm').join(this.getMonthName(false))
			.split('mmm').join(this.getMonthName(true))
			.split('mm').join(_zeroPad(this.getMonth() + 1))
			.split('dd').join(_zeroPad(this.getDate()));
    });

    /**
    * Returns a new date object created from the passed String according to Date.format or false if the attempt to do this results in an invalid date object
    * (We can't simple use Date.parse as it's not aware of locale and I chose not to overwrite it incase it's functionality is being relied on elsewhere)
    *
    * @example var dtm = Date.fromString("12/01/2008");
    * dtm.toString();
    * @result 'Sat Jan 12 2008 00:00:00' // (where Date.format == 'dd/mm/yyyy'
    * 
    * @name fromString
    * @type Date
    * @cat Plugins/Methods/Date
    * @author Kelvin Luck
    */
    Date.fromString = function(s) {
        var f = Date.format;
        var d = new Date('01/01/1977');

        var mLength = 0;

        var iM = f.indexOf('mmmm');
        if (iM > -1) {
            for (var i = 0; i < Date.monthNames.length; i++) {
                var mStr = s.substr(iM, Date.monthNames[i].length);
                if (Date.monthNames[i] == mStr) {
                    mLength = Date.monthNames[i].length - 4;
                    break;
                }
            }
            d.setMonth(i);
        } else {
            iM = f.indexOf('mmm');
            if (iM > -1) {
                var mStr = s.substr(iM, 3);
                for (var i = 0; i < Date.abbrMonthNames.length; i++) {
                    if (Date.abbrMonthNames[i] == mStr) break;
                }
                d.setMonth(i);
            } else {
                d.setMonth(Number(s.substr(f.indexOf('mm'), 2)) - 1);
            }
        }

        var iY = f.indexOf('yyyy');

        if (iY > -1) {
            if (iM < iY) {
                iY += mLength;
            }
            d.setFullYear(Number(s.substr(iY, 4)));
        } else {
            if (iM < iY) {
                iY += mLength;
            }
            // TODO - this doesn't work very well - are there any rules for what is meant by a two digit year?
            d.setFullYear(Number(Date.fullYearStart + s.substr(f.indexOf('yy'), 2)));
        }
        var iD = f.indexOf('dd');
        if (iM < iD) {
            iD += mLength;
        }
        d.setDate(Number(s.substr(iD, 2)));
        if (isNaN(d.getTime())) {
            return false;
        }
        return d;
    };

    // utility method
    var _zeroPad = function(num) {
        var s = '0' + num;
        return s.substring(s.length - 2)
        //return ('0'+num).substring(-2); // doesn't work on IE :(
    };

})();



/******************************************************************************/
/******************************* obe-utlities.js ******************************/
/******************************************************************************/
// sets the selected inbound itinerary hidden field value
function SelectInbound(selectedId, fee, departureDate, hasBag, airlineCode) {
    $("#selectedInbound").val(selectedId);
    $("#feeInbound").val(fee);
    $("#dateInbound").val(departureDate);
    
    if (airlineCode == "TA" || airlineCode == "TR" || airlineCode == "TT") {
        OutboundChanged(hasBag, airlineCode, true);
    }

    if ($("#dateInbound").val() <= $("#dateOutbound").val()) {
        this.checked = false;
        alert('Sorry, this option is not available! The inbound departure time should be later than outbound arrival.');
    }
}

// sets the selected outbound itinerary hidden field value
function SelectOutbound(selectedId, fee, arrivalDate, hasBag, airlineCode) {
    $("#selected").val(selectedId);
    $("#fee").val(fee);
    $("#dateOutbound").val(arrivalDate);

    if (airlineCode == "TA" || airlineCode == "TR" || airlineCode == "TT") {
        OutboundChanged(hasBag, airlineCode, false);
    }
}



var alertMessage = "Your outbound & inbound Tiger Airways fares must have the same baggage choice";
var storedMessages = new Array();

// Enables/disables no-baggage/with-baggage inbound options based on the outbound selection of the user
function OutboundChanged(hasBag, airlineCode, isInbound) {
    if (storedMessages["noBagMsg" + airlineCode] == null) {
        storedMessages["noBagMsg" + airlineCode] = $(".noBagMsg" + airlineCode).html();
    }

    if (storedMessages["withBagMsg" + airlineCode] == null) {
        storedMessages["withBagMsg" + airlineCode] = $(".withBagMsg" + airlineCode).html();
    }

    if (hasBag) 
    {
        // user has selected a flight with-baggage

        // first grab the ID of the inbound, no-baggage radiobutton they have selected
        var selectedID = $(".inNoBaggage" + airlineCode + ":radio:checked").attr("id");

        if (selectedID != null && selectedID != "undefined") {
            // change the selected inbound option from no-baggage to with-baggage
            var newSelectedID = selectedID.replace("No", "With");
            $("#" + newSelectedID).attr("checked", true);
        }

        if (!isInbound) 
        {
            // uncheck and disable all no-baggage inbound options for this airline
            $(".inNoBaggage" + airlineCode).attr("disabled", "disabled");
            $(".inNoBaggage" + airlineCode).removeAttr("checked");
            // enable all with-baggage inbound options
            $(".inWithBaggage" + airlineCode).removeAttr("disabled");
        }

        if (!isInbound) 
        {
            // the inbound no-bag option must have tooltip set to the alertMessage and
            // inbound with-bag option tooltip set to stored carryOnMessage if it exists

            // first store the outgoing no-bag message for use later
            storedMessages["noBagMsg" + airlineCode] = $(".noBagMsg" + airlineCode).html();
            // now change no-bag message to the alert message
            $(".noBagMsg" + airlineCode).html(alertMessage);

            // change with-bag message to carryOnMessage
            if (storedMessages["withBagMsg" + airlineCode] != null) {
                $(".withBagMsg" + airlineCode).html(storedMessages["withBagMsg" + airlineCode]);
            }
        }
    }
    else 
    {
        // user has selected a flight no-baggage

        // first grab the ID of the inbound, with-baggage radiobutton they have selected
        var selectedID = $(".inWithBaggage" + airlineCode + ":radio:checked").attr("id");

        if (selectedID != null && selectedID != "undefined") {
            // change the selected inbound option from with-baggage to no-baggage
            var newSelectedID = selectedID.replace("With", "No");
            $("#" + newSelectedID).attr("checked", true);
        }

        if (!isInbound) {
            // uncheck and disable all with-baggage inbound options for this airline
            $(".inWithBaggage" + airlineCode).attr("disabled", "disabled");
            $(".inWithBaggage" + airlineCode).removeAttr("checked");
            // enable all no-baggage inbound options
            $(".inNoBaggage" + airlineCode).removeAttr("disabled");
        }

        if (!isInbound) {
            // the inbound with-bag option must have tooltip set to the alertMessage and
            // inbound no-bag option tooltip set to stored carryOnMessage if it exists

            // first store the outgoing with-bag message for use later
            storedMessages["withBagMsg" + airlineCode] = $(".withBagMsg" + airlineCode).html();
            // change with-bag message to the alert message
            $(".withBagMsg" + airlineCode).html(alertMessage);

            // change no-bag message to carryOnMessage
            if (storedMessages["noBagMsg" + airlineCode] != null) {
                $(".noBagMsg" + airlineCode).html(storedMessages["noBagMsg" + airlineCode]);
            }
        }
    }

    // re-enable all other airlines with-bag and no-bag options
    $("input[name='rbInboundPrice']")
    .not(".outNoBaggage" + airlineCode)
    .not(".outWithBaggage" + airlineCode)
    .not(".inNoBaggage" + airlineCode)
    .not(".inWithBaggage" + airlineCode).removeAttr("disabled")
}


function SwapDivs(divToShow, divToHide) {
    var myObj = document.getElementById(divToShow);

    if (myObj != null) {
        myObj.style.display = 'block';
    }

    myObj = document.getElementById(divToHide);

    if (myObj != null) {
        myObj.style.display = 'none';
    }
}



/******************************************************************************/
/***************************** Flight booking engine **************************/
/******************************************************************************/
var selectCountryFrom;
var selectCountryTo;
var selectPortFrom;
var selectPortTo;
var selectPort;
var selectPortCode;
var selectDepartureDateDay;
var selectDepartureDateMonth;
var selectReturnDateDay;
var selectReturnDateMonth;
var selectedFlightClass;
var selectedAirline;
var selectNumAdults;
var selectNumChildren;
var selectNumInfants;
var selectAirlines;
var selectFlightClass;
var selectCurrency;
var selectSecondDepartureDateDay;
var selectSecondDepartureDateMonth;
var secondCountryFrom;
var secondCountryTo;
var currentFlightSegementNo;
var clientCountry;

// vars for initPhoneFinder (named differently to stop clashing with OBE vars when both items are on same page
var pf_selectCountryTo;
var pf_selectDepartureDateMonth;
var pf_selectFlightClass;

var selectMonth;
var selectDay;
var nextDaySelect;
var nextMonthSelect;
var previousDaySelect;
var previousMonthSelect;

var reloadData = false;
var selectedNumAdults = -1;
var selectedNumChildren = -1;
var selectedNumInfants = -1;
var selectedCountryFrom = '';
var selectedCountryTo = '';
var selectedPortFromName;
var selectedPortToName;
var selectedDateFrom;
var selectedPortFrom;
var selectedPortTo;
var selectedDateTo;
var selectedCurrency;
var isOneWayTrip = false;
var searchRequestId;

var currentPort;
var originalPortControl = null;
var initialStartDate = new Date();



//--------- Start - Added to Support Stopover Flights ---------------------------------
function incrementFlightSegements() {
    if (currentFlightSegementNo) {
        currentFlightSegementNo++;
    }
    else {
        currentFlightSegementNo = 10;
    }
}


function resetFlightSegements() {
    currentFlightSegementNo = 10;
}


function preselectPort() {
    if (originalPortControl != null) {
        currentPort.selectedIndex = originalPortControl.selectedIndex;
        originalPortControl = null;
    }
}


function decrementFlightSegements() {
    currentFlightSegementNo--;
}


function urldecode(str) {
    str = str.replace('+', ' ');
    str = unescape(str);
    return str;
}


function datesAreEqual(date1, date2) {
    var retValue = false;
    if (date1.getDate() == date2.getDate() && date1.getMonth() == date2.getMonth() && date1.getFullYear() == date2.getFullYear()) {
        retValue = true;
    }

    return retValue;
}


function updateStopoverDateSelectionControls(isDeparture, defaultDate, returnDateIncrement) {
    var startDate = getStartDate();
    var endDate = getEndDate();

    updateSingularDateSelectionControls(selectDepartureDateDay, selectDepartureDateMonth, startDate, endDate, defaultDate);
    var defaultReturnDate = new Date();
    defaultReturnDate.setFullYear(defaultDate.getFullYear(), defaultDate.getMonth(), defaultDate.getDate());
    defaultReturnDate.addDays(returnDateIncrement);

    if (defaultReturnDate > endDate || datesAreEqual(defaultReturnDate, endDate)) {
        defaultReturnDate.setFullYear(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
    }
    updateSingularDateSelectionControls(selectSecondDepartureDateDay, selectSecondDepartureDateMonth, defaultDate, endDate, defaultReturnDate);

}


function bindStopoverDateData(departDateControl, arriveDateControl, selectedDepartureDay, selectedDepartureMnthYr) {
    var departureDate = new Date();
    departureDate.addDays(3);
    updateStopoverDateSelectionControls(true, departureDate, 3);
}


function bindPreselectedDates(dateControl, monthControl, departureDate) {
    var endDate = getEndDate();
    var startDate = getStartDate();
    updateSingularDateSelectionControls(dateControl, monthControl, startDate, endDate, departureDate);
}


function bindPortResults(result) {
    // get control
    var control = $(result.SelectedControlId)[0];

    control.options.length = 0;

    var onlyOnePort = (result.Data.length == 1);

    if (!onlyOnePort) {
        // more than one port in list - add header
        control.options.add(new Option("Select Airport", ""));
    }

    var found = false;

    // create a select option for each port
    $.each(result.Data, function(index, optionData) {
        var option = new Option(optionData.PortName, optionData.PortCode);

        if (optionData.PortCode == "") {
            option.disabled = "disabled";
        }

        // add select option to control
        if ($.browser.msie) {
            control.add(option);
        }
        else {
            control.add(option, null);
        }
    });

    // set the appropriate port to be "selected"
    if (result.SelectedPort == null || result.SelectedPort == "undefined") {
        if (!$.browser.msie) {
            $(result.SelectedControlId).val("Select Airport");
        }
    }
    else {
        $(result.SelectedControlId).val(result.SelectedPort);
    }

    preselectPort();
}


function bindPortData(countryName, portCtrlId, selectedPort, selectedPortName) {
    var selectPort = $("#" + portCtrlId)[0];
    currentPort = selectPort;
    selectPort.options.length = 0;
    selectPort.options.add(new Option("-- loading --", ""));

    var url = "/JSON/GetFlightPortData/" + countryName.replace(/ /g, "_");

    if (portCtrlId != '') {
        url = url + "/" + portCtrlId;
    }

    if (selectedPort != '') {
        url = url + "/" + selectedPort;
    }

    if (selectedPortName != '') {
        url = url + "/" + selectedPortName;
    }

    $.getJSON(url, bindPortResults);
}


function portChanged(idx) {
    var nextPortControlId = 'selFromPort';
    var nextCountryControlId = 'selFromCountry';

    var countryControlId = 'selToCountry';
    var portControlId = 'selToPort';

    if (idx) {
        idx = parseInt(idx, 10);
        portControlId = portControlId + idx;
        countryControlId = countryControlId + idx;
        nextPortControlId = nextPortControlId + (idx + 1);
        nextCountryControlId = nextCountryControlId + (idx + 1);
    }
    else {
        nextPortControlId = 'selFromPort10';
        nextCountryControlId = 'selFromCountry10';
    }

    if ($("#" + nextCountryControlId)[0]) {
        $("#" + nextCountryControlId.toString())[0].selectedIndex = $("#" + countryControlId.toString())[0].selectedIndex;
        originalPortControl = $("#" + portControlId.toString())[0];
        var countryName = $("#" + countryControlId.toString()).find(':selected').text();
        bindPortData(countryName, nextPortControlId, '', '');
    }
    else {
        originalPortControl = null;
    }
}


function selectStopoverDateControls(controlIdx) {
    var nextSelectId;
    var minDate;
    var nextMonthSelectId;
    var nextId;
    var previousId = 0;
    var dayControlId = "#selDepartureDateDay";
    var monthControlId = "#selDepartureDateMonth";
    var currentDayControlId;
    var currentMonthControlId;

    previousDaySelect = null;
    previousMonthSelect = null;
    nextDaySelect = null;
    nextMonthSelect = null;

    if (controlIdx) {
        previousId = parseInt(controlIdx, 10) - 1;
        nextId = parseInt(controlIdx, 10) + 1;
        currentDayControlId = dayControlId + controlIdx;
        currentMonthControlId = monthControlId + controlIdx;

        if (previousId == 9) {
            previousDaySelect = $(dayControlId)[0];
            previousMonthSelect = $(monthControlId)[0];
        }
        else {
            previousDaySelect = $(dayControlId + previousId)[0];
            previousMonthSelect = $(monthControlId + previousId)[0];
        }
    }
    else {
        nextId = 10;
        currentDayControlId = dayControlId;
        currentMonthControlId = monthControlId;
    }

    nextMonthSelectId = monthControlId + nextId;
    nextDaySelectId = dayControlId + nextId;

    selectMonth = $(currentMonthControlId)[0];
    selectDay = $(currentDayControlId)[0];

    nextDaySelect = $(nextDaySelectId)[0];
    nextMonthSelect = $(nextMonthSelectId)[0];
}


function setNextDateControls(nextDaySelectId, nextMonthSelectId) {
    nextDaySelect = $(nextDaySelectId)[0];
    nextMonthSelect = $(nextMonthSelectId)[0];
}


function updateDateStopoverDateControls(isDeparture, defaultDate, returnDateIncrement, selectDepartDateDay, selectDepartDateMonth, selectRetDateDay, selectRetDateMonth) {
    var startDate = getStartDate();
    var endDate = getEndDate();

    if (isDeparture) {
        updateSingularDateSelectionControls(selectDepartDateDay, selectDepartDateMonth, startDate, endDate, defaultDate);
        var defaultReturnDate = new Date();
        defaultReturnDate.setFullYear(defaultDate.getFullYear(), defaultDate.getMonth(), defaultDate.getDate());
        defaultReturnDate.addDays(returnDateIncrement);

        if (defaultReturnDate > endDate || datesAreEqual(defaultReturnDate, endDate)) {
            defaultReturnDate.setFullYear(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
        }
        updateSingularDateSelectionControls(selectRetDateDay, selectRetDateMonth, defaultDate, endDate, defaultReturnDate);
    }
    else {
        updateSingularDateSelectionControls(selectRetDateDay, selectRetDateMonth, defaultDate, endDate, defaultDate);
    }
}


function updateDateControls() {
    var departureDate = getSelectedDate(selectDay, selectMonth);
    var startDate = getStartDate();
    var endDate = getEndDate();

    if (nextMonthSelect) {
        var currentDate = new Date();
        var returnDate = getSelectedDate(nextDaySelect, nextMonthSelect);
        var updated = false;

        if (departureDate < currentDate) {
            departureDate = currentDate;
            updateSingularDateSelectionControls(selectDay, selectMonth, startDate, endDate, departureDate);
            updateSingularDateSelectionControls(nextDaySelect, nextMonthSelect, departureDate, endDate, returnDate);
            updated = true;
        }

        var lastDepartureDate = getLastDepartureDate();

        if (departureDate > lastDepartureDate) {
            departureDate = lastDepartureDate;
        }

        if (departureDate > returnDate) {
            updateDateStopoverDateControls(true, departureDate, 0, selectDay, selectMonth, nextDaySelect, nextMonthSelect);
        }
        else {
            if (!updated) {
                startDate = getStartDate();
                endDate = getEndDate();
                updateSingularDateSelectionControls(selectDay, selectMonth, startDate, endDate, departureDate);
                updateSingularDateSelectionControls(nextDaySelect, nextMonthSelect, departureDate, endDate, returnDate);
            }
        }
    }

    if (previousDaySelect) {
        var previousDepartureDate = getSelectedDate(previousDaySelect, previousMonthSelect);

        if (previousDepartureDate > departureDate) {
            selectMonth.selectedIndex = previousMonthSelect.selectedIndex;
        }
        else {
            updateSingularDateSelectionControls(selectDay, selectMonth, previousDepartureDate, endDate, departureDate);
        }
    }
}


function stopoverDepartureDateMonthChanged() {
    var controlIdx = $(this).attr('id').substr(21, 2);
    selectStopoverDateControls(controlIdx);
    var dayControlId = "#selDepartureDateDay";
    var monthControlId = "#selDepartureDateMonth";
    var segNo = currentFlightSegementNo;

    while (segNo >= controlIdx) {
        nextMonthSelectId = monthControlId + segNo;
        nextDaySelectId = dayControlId + segNo;
        updateDateControls();
        setNextDateControls(nextDaySelectId, nextMonthSelectId);
        segNo--;
    }

    if (previousDaySelect) {
        var departureDate = getSelectedDate(previousDaySelect, previousMonthSelect);
        var nextDate = getSelectedDate(selectDay, selectMonth);
        var endDate = getEndDate();

        if (departureDate > nextDate) {
            selectDay.selectedIndex = previousDaySelect.selectedIndex;
        }
    }
}


function addFlightStop() {
    var currentIndex = $("#id").val();
    var bindingIndex = $("#idx").val();
    var newIndex = parseInt(currentIndex) + 1;

    // we only allow a maximum of 6 flights to be booked via stopover engine - so we hide the button when we reach 6
    if (newIndex == 14) {
        $("#addFlightContainer").hide();
    }

    var div = $('#Div' + currentIndex);

    // clone current row
    var div = $('#Div' + currentIndex).clone(true).attr('id', 'Div' + newIndex);
    div.find("#flightSegmentContent" + currentIndex).attr('id', 'flightSegmentContent' + newIndex);

    var countryFromSelect = div.find('#selFromCountry' + currentIndex);
    countryFromSelect.attr('id', 'selFromCountry' + newIndex);
    countryFromSelect.attr('name', 'FlightLegs[' + bindingIndex + '].DepartureCountry');
    countryFromSelect.unbind();
    countryFromSelect.change(countryFromChangedNew);
    countryFromSelect.attr('selectedIndex', 0);

    var countryToSelect = div.find('#selToCountry' + currentIndex);
    countryToSelect.attr('id', 'selToCountry' + newIndex);
    countryToSelect.attr('name', 'FlightLegs[' + bindingIndex + '].ArrivalCountry');
    countryToSelect.unbind();
    countryToSelect.change(countryToChangedNew);
    countryToSelect.attr('selectedIndex', 0);

    // set new ID's
    var portFromSelect = div.find('#selFromPort' + currentIndex);
    portFromSelect.attr('id', 'selFromPort' + newIndex);
    var portToSelect = div.find('#selToPort' + currentIndex);
    portToSelect.attr('id', 'selToPort' + newIndex);

    var departureDay = div.find('#selDepartureDateDay' + currentIndex);
    departureDay.attr('id', 'selDepartureDateDay' + newIndex);
    departureDay.attr('selectedIndex', $('#selDepartureDateDay' + currentIndex)[0].selectedIndex);

    var departureMonth = div.find('#selDepartureDateMonth' + currentIndex);
    departureMonth.attr('id', 'selDepartureDateMonth' + newIndex);
    departureMonth.attr('selectedIndex', $('#selDepartureDateMonth' + currentIndex)[0].selectedIndex);
    div.find('#flightSegmentContent').attr('id', 'flightSegmentContent' + newIndex);

    // Rename for binding to the model
    portFromSelect.attr('name', 'FlightLegs[' + bindingIndex + '].DeparturePort');
    portToSelect.attr('name', 'FlightLegs[' + bindingIndex + '].ArrivalPort');
    departureDay.attr('name', 'FlightLegs[' + bindingIndex + '].DepartureDateDay');
    departureMonth.attr('name', 'FlightLegs[' + bindingIndex + '].DepartureDateMonthYr');
    departureMonth.unbind();
    departureMonth.change(stopoverDepartureDateMonthChanged);

    portFromSelect.html("");
    portFromSelect.append("<option value='...'>Select Airport</option>");
    portToSelect.html("");
    portToSelect.append("<option value='...'>Select Airport</option>");

    // Set the flight number
    var flightLine = parseInt(bindingIndex) + 1;
    div.find('#tdFlightSegment').text('Flight ' + flightLine);

    //div.find("#flightSegmentContent" + newIndex).find("td:last").replaceWith("<td><a id='remove" + newIndex + "' href='#' onClick='removeFormField(\"#Div" + newIndex + "\"); return false;'>Remove</a></td>");
    div.appendTo('#flightStops');

    currentIndex++;
    bindingIndex++;

    $("#idx").val(bindingIndex);
    $("#id").val(currentIndex);

    // Preset the country and port
    portChanged(currentIndex - 1);
    incrementFlightSegements();

    $("a[name=removeLink]:last").show();
}


function removeFlightStop() {
    // if we are removing a flight - redisplay the addflight button
    $("#addFlightContainer").show();

    var bindingIndex = $("#idx").val();
    var lastIndex = $("#id").val();
    $('#Div' + lastIndex).remove();
    $("a[name=removeLink]").hide();

    if (lastIndex > 11) {
        $("a[name=removeLink]:last").show();
    }

    lastIndex--;
    bindingIndex--;
    decrementFlightSegements();
    $("#id").val(lastIndex);
    $("#idx").val(bindingIndex);
}


function validateForm() {
    var originDestinationValid = true;
    var datesValid = true;
    var departureValid = true;

    jQuery.each(jQuery.validator.messages, function(i) {
        jQuery.validator.messages[i] = "*";
    });

    $('#dvValMsgArrivalDestinationPortSame').hide();
    $('#dvValMsgReturnDateBeforeDepartureDate').hide();
    $('#dvValMsgDepartureDateInPast').hide();
    if ($('#bookingengineForm').valid()) {
        var idIndex = parseInt($("#id").val(), 10);
        if ($('#selToPort').find(':selected').text() == $('#selFromPort').find(':selected').text()) {
            originDestinationValid = false;
        }

        var firstDate = getSelectedDate($('#selDepartureDateDay')[0], $('#selDepartureDateMonth')[0]);
        var today = new Date();

        if (firstDate < today) {
            departureValid = false;
        }

        while (idIndex >= 10) {
            if ($('#selToPort' + idIndex).find(':selected').text() == $('#selFromPort' + idIndex).find(':selected').text()) {
                originDestinationValid = false;
                break;
            }

            var currentDate = getSelectedDate($('#selDepartureDateDay' + idIndex)[0], $('#selDepartureDateMonth' + idIndex)[0]);
            var previousDate;

            idIndex--;

            if (idIndex >= 10) {
                previousDate = getSelectedDate($('#selDepartureDateDay' + idIndex)[0], $('#selDepartureDateMonth' + idIndex)[0]);
            }
            else {
                previousDate = getSelectedDate($('#selDepartureDateDay')[0], $('#selDepartureDateMonth')[0]);
            }

            if (previousDate > currentDate) {
                datesValid = false;
                break;
            }
        }

        if (!originDestinationValid) {
            $('#dvValMsgArrivalDestinationPortSame').show();
        }

        if (!datesValid) {
            $('#dvValMsgReturnDateBeforeDepartureDate').show();
        }

        if (!departureValid) {
            $('#dvValMsgDepartureDateInPast').show();
        }
        return originDestinationValid && datesValid && departureValid;
    }
    else {
        return false;
    }
}


function initStopoverObe(selectCountryFromId, selectCountryToId, selectPortFromId, selectPortToId, selectNumAdultsId, selectNumChildrenId,
    selectNumInfantsId, departureDateDayId, departureDateMonthId, secondDepartureDateDayId, secondDepartureDateMonthId, selectAirlineId,
    selectFlightClassId, selectSecondCountryTo, selectSecondCountryFrom, selectCurrencyId) {
    selectCountryFrom = $get(selectCountryFromId);
    selectCountryTo = $get(selectCountryToId);
    selectNumAdults = $get(selectNumAdultsId);
    selectNumChildren = $get(selectNumChildrenId);
    selectNumInfants = $get(selectNumInfantsId);
    selectDepartureDateDay = $get(departureDateDayId);
    selectDepartureDateMonth = $get(departureDateMonthId);
    selectAirlines = $get(selectAirlineId);
    selectFlightClass = $get(selectFlightClassId);
    selectCurrency = $get(selectCurrencyId);
    selectSecondDepartureDateDay = $get(secondDepartureDateDayId);
    selectSecondDepartureDateMonth = $get(secondDepartureDateMonthId);
    secondCountryFrom = $get(selectSecondCountryFrom);
    secondCountryTo = $get(selectSecondCountryTo);

    if (selectCountryFrom && selectCountryTo) {
        bindCountryData(selectCountryFromId, selectCountryToId, '', '', '', '');
    }

    if (secondCountryFrom && secondCountryTo) {
        bindCountryData(selectSecondCountryFrom, selectSecondCountryTo, '', '', '', '');
    }

    if (selectNumAdults && selectNumChildren && selectNumInfants) {
        bindQuantityData();
    }

    if (selectCurrency) {
        bindCurrencyData();
    }

    bindStopoverDateData();

    if (selectAirlines) {
        bindAirlinesData();
    }

    if (selectFlightClass) {
        bindFlightClassData();
    }

    if (departureCountries.length > 0) {
        var counter = "";
        for (i = 0; i < departureCountries.length; i++) {
            var countryFromSelectName = 'selFromCountry';
            var countryToSelectName = 'selToCountry';
            var countryFromSelectId;
            var countryToSelectId;

            var portFromSelectName = '#selFromPort';
            var portToSelectName = '#selToPort';
            var departureDayName = '#selDepartureDateDay';
            var departureMonthName = '#selDepartureDateMonth';

            var portFromSelectId;
            var portToSelectId;

            if (i >= 1) {
                if (i >= 2) {
                    addFlightStop();
                }
                counter = i + 9;
            }

            countryFromSelectId = countryFromSelectName + counter;
            countryToSelectId = countryToSelectName + counter;

            portFromSelectId = portFromSelectName + counter;
            portToSelectId = portToSelectName + counter;

            departureDayId = departureDayName + counter;
            departureMonthId = departureMonthName + counter;

            selectedCountryFrom = departureCountries[i];
            selectedCountryTo = arrivalCountries[i];
            selectedPortFromName = portFromNames[i];
            selectedPortToName = portToNames[i];

            selectDepartureDateDay = $(departureDayId)[0];
            selectDepartureDateMonth = $(departureMonthId)[0];

            bindCountryData(countryFromSelectId, countryToSelectId, departurePorts[i], selectedPortFromName, arrivalPorts[i], selectedPortToName);
            bindPreselectedDates(selectDepartureDateDay, selectDepartureDateMonth, departureDates[i]);
        }
    }
}


function countryFromChangedNew(select) {
    var countryName = $(this).find(':selected').text();
    var idx = $(this).attr('id').substr(14, 2);
    var ctrlId = 'selFromPort';

    if (idx) {
        ctrlId = ctrlId + idx;
    }
    bindPortData(countryName, ctrlId, '', '');
}


function countryToChangedNew(select) {
    var countryName = $(this).find(':selected').text();

    var idx = $(this).attr('id').substr(12, 2);
    var ctrlId = 'selToPort';

    if (idx) {
        ctrlId = ctrlId + idx;
    }

    bindPortData(countryName, ctrlId, '', '');
}


function portToChanged() {
    var idx = $(this).attr('id').substr(9, 2);
    portChanged(idx);
}


function stopoverDepatureDayDateChanged() {
    var currentDate = new Date();
    var controlIdx = $(this).attr('id').substr(19, 2);
    var startDate = getStartDate();
    var endDate = getEndDate();

    selectStopoverDateControls(controlIdx);
    var currentDepartureDate = getSelectedDate(selectDay, selectMonth);

    if (previousMonthSelect) {
        var previousDepartureDate = getSelectedDate(previousDaySelect, previousMonthSelect);

        if (currentDepartureDate < previousDepartureDate) {
            currentDepartureDate.addMonths(1);
            updateSingularDateSelectionControls(selectDay, selectMonth, previousDepartureDate, endDate, currentDepartureDate);
        }
    }

    var nextDate;

    if (nextDaySelect) {
        var departureDate = getSelectedDate(selectDay, selectMonth);
        nextDate = getSelectedDate(nextDaySelect, nextMonthSelect);

        if (departureDate > nextDate) {
            updateSingularDateSelectionControls(nextDaySelect, nextMonthSelect, departureDate, endDate, departureDate);
        }
    }

    if (currentDepartureDate < currentDate) {
        currentDepartureDate.addMonths(1);
        updateSingularDateSelectionControls(selectDay, selectMonth, currentDate, endDate, currentDepartureDate);

        if (nextDate && currentDepartureDate > nextDate) {
            updateSingularDateSelectionControls(nextDaySelect, nextMonthSelect, currentDepartureDate, endDate, currentDepartureDate);
        }
    }
}


//--------- End - Added to Support Stopover Flights ---------------------------------
function validateForReload() {
    if (isOneWayTrip) {
        $('input[name=flightType]')[1].checked = true;
        selectReturnDateDay.disabled = true;
        selectReturnDateMonth.disabled = true;
    }
    else {
        $('input[name=flightType]')[0].checked = true;
        selectReturnDateDay.disabled = false;
        selectReturnDateMonth.disabled = false;
    }
}


function initObe(selectCountryFromId, selectCountryToId, selectPortFromId, selectPortToId, selectNumAdultsId, selectNumChildrenId, selectNumInfantsId,
    departureDateDayId, departureDateMonthId, returnDateDayId, returnDateMonthId, selectAirlineId, selectFlightClassId, selectCurrencyId)
{
    selectCountryFrom = $get(selectCountryFromId);
    selectCountryTo = $get(selectCountryToId);
    selectPortFrom = $get(selectPortFromId);
    selectPortTo = $get(selectPortToId);
    selectNumAdults = $get(selectNumAdultsId);
    selectNumChildren = $get(selectNumChildrenId);
    selectNumInfants = $get(selectNumInfantsId);
    selectDepartureDateDay = $get(departureDateDayId);
    selectDepartureDateMonth = $get(departureDateMonthId);
    selectReturnDateDay = $get(returnDateDayId);
    selectReturnDateMonth = $get(returnDateMonthId);
    selectAirlines = $get(selectAirlineId);
    selectFlightClass = $get(selectFlightClassId);
    selectCurrency = $get(selectCurrencyId);

    if (selectCountryFrom && selectCountryTo) 
    {
        bindCountryData(selectCountryFromId, selectCountryToId, selectedPortFrom, selectedPortFromName, selectedPortTo, selectedPortToName);
    }

    if (selectNumAdults && selectNumChildren && selectNumInfants)
    {
        bindQuantityData();
    }

    if (selectCurrency) 
    {
        bindCurrencyData();
    }

    bindDateData();

    if (selectAirlines) 
    {
        bindAirlinesData();
    }

    if (selectFlightClass) 
    {
        bindFlightClassData();
    }

    if (reloadData) 
    {
        validateForReload();
    }
}


function initPhoneFinder(selectCountryToId, departureDateMonthId, selectFlightClassId, selectedDateFromstring) {
    pf_selectCountryTo = $get(selectCountryToId);
    pf_selectDepartureDateMonth = $get(departureDateMonthId);
    pf_selectFlightClass = $get(selectFlightClassId);

    var startDate = new Date();
    startDate.addDays(3);
    var endDate = new Date();
    endDate.setFullYear(startDate.getFullYear(), startDate.getMonth(), 1);
    endDate.addYears(1);

    var iterationDate = new Date();
    iterationDate.setFullYear(startDate.getFullYear(), startDate.getMonth(), 1);
    var startMonth = iterationDate.getMonth();
    var startYear = iterationDate.getFullYear();
    var daySelectedIndex = 0;
    var monthSelectedIndex = 0;
    var dayIndex = 0;
    var monthIndex = 0;
    var dayDisplay;
    var dayValue;
    var monthDisplay;
    var monthValue;
    var cnt = 0;

    while (iterationDate < endDate) {
        if (iterationDate.getMonth() == startMonth && iterationDate.getFullYear() == startYear) {
            dayDisplay = iterationDate.getDayName(false) + " " + iterationDate.getDate();
            dayValue = iterationDate.getDate();

            if (dayIndex == 0) {
                monthDisplay = iterationDate.getMonthName(false) + " " + iterationDate.getFullYear() + "";
                monthValue = "01-" + (parseInt(iterationDate.getMonth(), 10) + 1) + "-" + iterationDate.getFullYear();
                pf_selectDepartureDateMonth.options.add(new Option(monthDisplay, monthValue));
                ++monthIndex;
            }

            if (monthValue + "" == selectedDateFromstring + "") {
                monthSelectedIndex = parseInt(monthIndex, 10) + 1;
            }
            else
            { }

            if (selectedDateFrom && datesAreEqual(iterationDate, selectedDateFrom)) {
                daySelectedIndex = dayIndex;
                monthSelectedIndex = monthIndex - 1;
            }
            iterationDate.addDays(1);
            ++dayIndex;
        }
        else {
            monthDisplay = iterationDate.getMonthName(false) + " " + iterationDate.getFullYear() + "";
            monthValue = "01-" + (parseInt(iterationDate.getMonth(), 10) + 1) + "-" + iterationDate.getFullYear();
            pf_selectDepartureDateMonth.options.add(new Option(monthDisplay, monthValue));

            if (datesAreEqual(iterationDate, startDate)) {
                monthSelectedIndex = monthIndex - 1;
            }
            if (monthValue + "" == selectedDateFromstring + "") {
                monthSelectedIndex = parseInt(monthIndex, 10) + 1;
            }
            else {
            }

            iterationDate.addMonths(1);
            ++monthIndex;
            ++cnt;
        }
    }

    pf_selectDepartureDateMonth.selectedIndex = monthSelectedIndex;
}


function showResults(url, newWindow, affiliateId) {
    url += "?depport=" + selectPortFrom.options[selectPortFrom.selectedIndex].value;
    url += "&depportname=" + escape(selectPortFrom.options[selectPortFrom.selectedIndex].text);
    url += "&depcountry=" + selectCountryFrom.options[selectCountryFrom.selectedIndex].text.replace(/ /g, '_');
    url += "&arrport=" + selectPortTo.options[selectPortTo.selectedIndex].value;
    url += "&arrportname=" + escape(selectPortTo.options[selectPortTo.selectedIndex].text);
    url += "&arrcountry=" + selectCountryTo.options[selectCountryTo.selectedIndex].text.replace(/ /g, '_');
    url += "&fclass=" + selectFlightClass.options[selectFlightClass.selectedIndex].value;
    url += "&airline=" + selectAirlines.options[selectAirlines.selectedIndex].value;
    url += "&depdate=" + getDepartureDateValue();
    url += "&arrdate=" + getReturnDateValue();
    url += "&adults=" + selectNumAdults.options[selectNumAdults.selectedIndex].value;
    url += "&children=" + selectNumChildren.options[selectNumChildren.selectedIndex].value;
    url += "&infants=" + selectNumInfants.options[selectNumInfants.selectedIndex].value;
    if (affiliateId != null && affiliateId != "") {
        url += "&affiliate=" + affiliateId;
    }
    if (selectCurrency != null) {
        url += "&currency=" + selectCurrency.options[selectCurrency.selectedIndex].value;
    }

    url += "&pgnum=1";
    url += "&type=" + $('input:radio[name=flightType]:checked').val();
    url += "&requestid=" + searchRequestId;

    newWindow ? window.open(url) : top.location = url;
}




// ================ DATES ===================
function getDepartureDateValue() {
    var day;
    var month;
    var year;

    day = parseInt(selectDepartureDateDay.options[selectDepartureDateDay.selectedIndex].value, 10);
    var splitMonthValues = selectDepartureDateMonth.options[selectDepartureDateMonth.selectedIndex].value.split(";");

    if (splitMonthValues.length > 1) {
        month = parseInt(splitMonthValues[0], 10) + 1;
        year = splitMonthValues[1];
    }
    return day + "/" + month + "/" + year;
}


function getReturnDateValue() {
    var day;
    var month;
    var year;

    day = parseInt(selectReturnDateDay.options[selectReturnDateDay.selectedIndex].value, 10);
    var splitMonthValues = selectReturnDateMonth.options[selectReturnDateMonth.selectedIndex].value.split(";");

    if (splitMonthValues.length > 1) {
        month = parseInt(splitMonthValues[0], 10) + 1;
        year = splitMonthValues[1];
    }
    return day + "/" + month + "/" + year;
}


function getDayDisplayText(displayDate) {
    var dayValue = displayDate.getDate().toString();
    if (dayValue.length == 1) {
        dayValue = "0" + dayValue;
    }
    return displayDate.getDayName(false) + " " + dayValue;
}


function bindDateData() {
    var departureDate = new Date();

    if (reloadData && selectedDateFrom != null) {
        departureDate = selectedDateFrom;
        var returnDate = selectedDateTo;

        if (returnDate == null) {
            returnDate = selectedDateFrom;
        }
        var endDate = getEndDate();
        var startDate = getStartDate();
        updateSingularDateSelectionControls(selectDepartureDateDay, selectDepartureDateMonth, startDate, endDate, departureDate);
        updateSingularDateSelectionControls(selectReturnDateDay, selectReturnDateMonth, departureDate, endDate, returnDate);
    }
    else {
        departureDate.addDays(3);
        updateDateSelectionControls(true, departureDate, 3);
    }
}


function updateDateSelectionControls(isDeparture, defaultDate, returnDateIncrement) {
    var startDate = getStartDate();
    var endDate = getEndDate();

    if (isDeparture) {
        updateSingularDateSelectionControls(selectDepartureDateDay, selectDepartureDateMonth, startDate, endDate, defaultDate);
        var defaultReturnDate = new Date();
        defaultReturnDate.setFullYear(defaultDate.getFullYear(), defaultDate.getMonth(), defaultDate.getDate());
        defaultReturnDate.addDays(returnDateIncrement);

        if (defaultReturnDate > endDate || datesAreEqual(defaultReturnDate, endDate)) {
            defaultReturnDate.setFullYear(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
        }
        updateSingularDateSelectionControls(selectReturnDateDay, selectReturnDateMonth, defaultDate, endDate, defaultReturnDate);
    }
    else {
        updateSingularDateSelectionControls(selectReturnDateDay, selectReturnDateMonth, defaultDate, endDate, defaultDate);
    }
}


function updateSingularDateSelectionControls(daySelectionControl, monthSelectionControl, minimumDateSelectable, maxDateSelectable, defaultDate) {
    try {
        if (daySelectionControl != null && monthSelectionControl != null) {
            daySelectionControl.options.length = 0;
            monthSelectionControl.options.length = 0;
            var startDate = new Date();
            startDate.setFullYear(minimumDateSelectable.getFullYear(), minimumDateSelectable.getMonth(), 1);
            var endDate = maxDateSelectable;

            // BMX
            var dayDisplay;
            var dayValue;
            var daySelectedIndex;
            var monthSelectedIndex = 0;
            var dayIndex = 0;
            var monthIndex = 0;
            var monthValue;
            var monthDisplay;

            var iterationDate = new Date();
            iterationDate.setFullYear(startDate.getFullYear(), startDate.getMonth(), 1);

            daySelectedIndex = defaultDate.getDate() - 1;
            iterationDate.setHours(0, 0, 0);
            endDate.setHours(0, 0, 0);

            while (iterationDate < endDate || datesAreEqual(iterationDate, endDate)) {
                if (iterationDate.getFullYear() == defaultDate.getFullYear() && iterationDate.getMonth() == defaultDate.getMonth()) {
                    dayDisplay = getDayDisplayText(iterationDate);
                    dayValue = iterationDate.getDate();

                    daySelectionControl.options.add(new Option(dayDisplay, dayValue));

                    if (dayIndex == 0) {
                        monthDisplay = iterationDate.getMonthName(false) + " " + iterationDate.getFullYear();
                        monthValue = iterationDate.getMonth() + ";" + iterationDate.getFullYear();
                        monthSelectionControl.options.add(new Option(monthDisplay, monthValue));
                        monthSelectedIndex = monthIndex;
                        ++monthIndex;
                    }
                    iterationDate.addDays(1);
                    ++dayIndex;
                }
                else {
                    monthDisplay = iterationDate.getMonthName(false) + " " + iterationDate.getFullYear();
                    monthValue = iterationDate.getMonth() + ";" + iterationDate.getFullYear();
                    monthSelectionControl.options.add(new Option(monthDisplay, monthValue));

                    if (iterationDate.getMonth() == defaultDate.getMonth()) {
                        monthSelectedIndex = monthIndex;
                    }
                    iterationDate.addMonths(1);
                    ++monthIndex;
                }
            }

            if (daySelectedIndex >= daySelectionControl.options.length) {
                daySelectedIndex = daySelectionControl.options.length - 1;
            }
            daySelectionControl.selectedIndex = daySelectedIndex;
            monthSelectionControl.selectedIndex = monthSelectedIndex;
        }
    }
    catch (e) {
        alert(e.message);
    }
}


function departureDateDayChanged() {
    var currentDate = new Date();
    var departureDate = getSelectedDepartureDate();
    var returnDate = getSelectedReturnDate();
    var startDate = getStartDate();
    var endDate = getEndDate();

    if (departureDate < currentDate) {
        departureDate.addMonths(1);
        updateSingularDateSelectionControls(selectDepartureDateDay, selectDepartureDateMonth, startDate, endDate, departureDate);
        updateSingularDateSelectionControls(selectReturnDateDay, selectReturnDateMonth, departureDate, endDate, returnDate);
    }
    var lastDepartureDate = getLastDepartureDate();

    if (departureDate > lastDepartureDate) {
        departureDate = lastDepartureDate;
        updateSingularDateSelectionControls(selectDepartureDateDay, selectDepartureDateMonth, startDate, endDate, departureDate);
    }

    if (departureDate > returnDate) {
        updateSingularDateSelectionControls(selectReturnDateDay, selectReturnDateMonth, departureDate, endDate, departureDate);
    }
}


function departureDateMonthChanged() {
    var currentDate = new Date();
    // get selected date
    var departureDate = getSelectedDepartureDate();
    var returnDate = getSelectedReturnDate();
    var startDate = getStartDate();
    var endDate = getEndDate();
    var updated = false;

    if (departureDate < currentDate) {
        departureDate = currentDate;
        updateSingularDateSelectionControls(selectDepartureDateDay, selectDepartureDateMonth, startDate, endDate, departureDate);
        updateSingularDateSelectionControls(selectReturnDateDay, selectReturnDateMonth, departureDate, endDate, returnDate);
        updated = true;
    }

    var lastDepartureDate = getLastDepartureDate();

    if (departureDate > lastDepartureDate) {
        departureDate = lastDepartureDate;
    }

    if (departureDate > returnDate) {
        updateDateSelectionControls(true, departureDate, 0);
    }
    else {
        if (!updated) {
            updateSingularDateSelectionControls(selectDepartureDateDay, selectDepartureDateMonth, startDate, endDate, departureDate);
            updateSingularDateSelectionControls(selectReturnDateDay, selectReturnDateMonth, departureDate, endDate, returnDate);
        }
    }
}


function returnDateMonthChanged() {
    var departureDate = getSelectedDepartureDate();
    var returnDate = getSelectedReturnDate();

    if (returnDate) {
        if (departureDate > returnDate) {
            updateDateSelectionControls(true, departureDate, 0);
        }
        else {
            var endDate = getEndDate();
            updateSingularDateSelectionControls(selectReturnDateDay, selectReturnDateMonth, departureDate, endDate, returnDate);
        }
    }
}


function returnDateDayChanged() {
    var departureDate = getSelectedDepartureDate();
    var returnDate = getSelectedReturnDate();

    if (departureDate > returnDate) {
        returnDate.addMonths(1);
        var lastSelectableDate = getLastSelectableDate();

        if (returnDate > lastSelectableDate) {
            returnDate = lastSelectableDate;
        }

        if (returnDate) {
            var endDate = getEndDate();
            updateSingularDateSelectionControls(selectReturnDateDay, selectReturnDateMonth, departureDate, endDate, returnDate);
        }
    }
}


function getSelectedDate(selDateDay, selDateMonth) {
    var selectedDate = new Date();
    var day;
    var month;
    var year;

    day = parseInt(selDateDay.options[selDateDay.selectedIndex].value, 10);
    var splitMonthValues = selDateMonth.options[selDateMonth.selectedIndex].value.split(";");

    if (splitMonthValues.length > 1) {
        month = parseInt(splitMonthValues[0], 10);
        year = parseInt(splitMonthValues[1], 10);
    }
    selectedDate.setFullYear(year, month, 1);
    selectedDate.addMonths(1);
    selectedDate.addDays(-1);

    if (selectedDate.getDate() >= day) {
        selectedDate.setFullYear(year, month, day);
    }
    return selectedDate;
}


function getSelectedDepartureDate() {
    var selectedDate = getSelectedDate(selectDepartureDateDay, selectDepartureDateMonth);
    return selectedDate;
}


function getSelectedReturnDate() {
    var selectedDate = getSelectedDate(selectReturnDateDay, selectReturnDateMonth);
    return selectedDate;
}


function getStartDate() {
    var startDate = new Date();
    startDate.setFullYear(initialStartDate.getFullYear(), initialStartDate.getMonth(), 1);
    startDate.setHours(0, 0, 0);
    return startDate;
}


function getEndDate() {
    // var startDate = getStartDate();
    var endDate = new Date();
    // endDate.setFullYear(startDate.getFullYear(), startDate.getMonth(), 1);
    // endDate.addDays(331);
    endDate.addMonths(12);
    endDate.setFullYear(endDate.getFullYear(), endDate.getMonth(), 1);
    endDate.addDays(-1);
    endDate.setHours(0, 0, 0);
    return endDate;
}


function getLastSelectableDate() {
    var lastSelectableDate = getEndDate();
    //lastSelectableDate.addDays(-1);
    return lastSelectableDate;
}


function getLastDepartureDate() {
    var lastDepartureDate = getEndDate();
    return lastDepartureDate;
}


function datesAreEqual(date1, date2) {
    var retValue = false;
    if (date1.getDate() == date2.getDate() && date1.getMonth() == date2.getMonth() && date1.getFullYear() == date2.getFullYear()) {
        retValue = true;
    }

    return retValue;
}
// ================ END OF DATES ===================


function bindCurrencyData() {
    var found = false;
    if (reloadData) {
        $.each(selectCurrency.options, function(index1, optionData) {
            if (!found && optionData.text == selectedCurrency) {
                var ctrlId = 'selCurrency';
                optionData.selected = "selected";
                found = true;
            }
        });
    }
}


// ================ QUANTITY ===================
function bindQuantityData() {
    selectNumAdults.options.length = 0;
    for (count = 1; count < 10; count++) {
        selectNumAdults.options.add(new Option(count, count));
    }

    if (reloadData && selectedNumAdults != -1) { selectNumAdults.selectedIndex = selectedNumAdults - 1; }

    qtyAdultsChanged();

    if (reloadData && selectedNumChildren != -1) { selectNumChildren.selectedIndex = selectedNumChildren; }

    qtyChildrenChanged();

    if (reloadData && selectedNumInfants != -1) {
        selectNumInfants.selectedIndex = selectedNumInfants;
    }
    else {
        selectNumInfants.selectedIndex = 0;
    }
}


function qtyAdultsChanged() {
    var qtyAdultsSelected = selectNumAdults.selectedIndex + 1;
    var qtyChildrenSelected = selectNumChildren.selectedIndex;
    var qtyInfantsSelected = selectNumInfants.selectedIndex;

    if (qtyAdultsSelected > 0) {
        selectNumChildren.options.length = 0;

        for (count = 0; count < 10 - qtyAdultsSelected - qtyInfantsSelected; count++) {
            selectNumChildren.options.add(new Option(count, count));
        }

        if (qtyChildrenSelected > selectNumChildren.options.length) {
            selectNumChildren.selectedIndex = selectNumChildren.options.length - 1;
        }
        else {
            selectNumChildren.selectedIndex = qtyChildrenSelected;
        }

        qtyChildrenChanged();
    }
}


function qtyChildrenChanged() {
    var qtyAdultsSelected = selectNumAdults.selectedIndex + 1;
    var qtyChildrenSelected = selectNumChildren.options.selectedIndex;
    var qtyInfantsSelected = selectNumInfants.options.selectedIndex;

    if (qtyAdultsSelected > 0) {
        selectNumInfants.options.length = 0;

        for (count = 0; count < 10 - qtyAdultsSelected - qtyChildrenSelected && count <= qtyAdultsSelected; count++) {
            selectNumInfants.options.add(new Option(count, count));
        }

        if (qtyInfantsSelected > selectNumInfants.options.length) {
            selectNumInfants.selectedIndex = selectNumInfants.options.length - 1;
        }
        else {
            selectNumInfants.selectedIndex = qtyInfantsSelected;
        }
    }

    if (selectNumInfants.selectedIndex == -1) {
        selectNumInfants.selectedIndex = 0;
    }

}
// ================ END QUANTITY ===================


// ================ COUNTRIES ===================
function countryFromChanged(select) {
    var countryName = $(this).find(':selected').text(); //select.srcElement.options[select.target.selectedIndex].text;
    bindPortDataFrom(countryName);
}


function countryToChanged(select) {
    var countryName = $(this).find(':selected').text(); //select.srcElement.options[select.target.selectedIndex].text;
    bindPortDataTo(countryName);
}


function bindCountryData(selectCountryFromId, selectCountryToId, selectedPortFrom, selectedPortFromName, selectedToPort, selectedPortToName) {
    var selectCountryFrom = $("#" + selectCountryFromId)[0];
    var selectCountryTo = $("#" + selectCountryToId)[0];

    if (selectCountryFrom.options.length == 0) {
        selectCountryFrom.options.length = 0;
        selectCountryTo.options.length = 0;
        selectCountryFrom.options.add(new Option("-- loading --", ""));
        selectCountryTo.options.add(new Option("-- loading --", ""));

        var url = "/JSON/GetFlightCountryData/";
        $.getJSON(url, bindCountryResults);
    }
    else {
        bindCountryDataPreload(selectCountryFromId, selectCountryToId, selectedPortFrom, selectedPortFromName, selectedToPort, selectedPortToName);
    }
}


function bindCountryDataPreload(selectCountryFromId, selectCountryToId, selectedPortFrom, selectedPortFromName, selectedToPort, selectedPortToName) {
    var selectCountryFrom = $("#" + selectCountryFromId)[0];
    var selectCountryTo = $("#" + selectCountryToId)[0];

    // if no "header" option is present in origin country - add one
    if ($("#" + selectCountryFromId + " option:first").text() != "Select Country") {
        var toOption = document.createElement("option");
        toOption.value = "";
        toOption.innerHTML = "Select Country";
        selectCountryFrom.insertBefore(toOption, selectCountryFrom.firstChild);
        selectCountryFrom.selectedIndex = 0;
    }

    // if no "header" option is present in destination country- add one
    if ($("#" + selectCountryToId + " option:first").text() != "Select Country") {
        var fromOption = document.createElement("option");
        fromOption.value = "";
        fromOption.innerHTML = "Select Country";
        selectCountryTo.insertBefore(fromOption, selectCountryTo.firstChild);
        selectCountryTo.selectedIndex = 0;
    }

    var index = 0;
    var found = false;
    var idx = selectCountryFromId.substr(14, 2);

    if (reloadData) {
        $.each(selectCountryFrom.options, function(index1, optionData) {
            if (!found && optionData.text == selectedCountryFrom.replace(/_/g, ' ')) {
                var ctrlId = 'selFromPort';
                if (idx) {
                    ctrlId = ctrlId + idx;
                }

                optionData.selected = "selected";
                bindPortData(optionData.text, ctrlId, selectedPortFrom, selectedPortFromName);
                found = true;
            }
            if (optionData.value == "" && optionData.text != "Select Country") {
                optionData.disabled = "disabled";
            }
        });

        found = false;
        $.each(selectCountryTo.options, function(index2, optionData) {
            if (!found && optionData.text == selectedCountryTo.replace(/_/g, ' ')) {
                var ctrlId = 'selToPort';

                if (idx) {
                    ctrlId = ctrlId + idx;
                }
                optionData.selected = "selected";
                bindPortData(optionData.text, ctrlId, selectedToPort, selectedPortToName);
                found = true;
            }
            if (optionData.value == "" && optionData.text != "Select Country") {
                optionData.disabled = "disabled";
            }
        });

        $.each(selectFlightClass.options, function(index3, optionData) {
            if (optionData.value == selectedFlightClass.replace(/_/g, ' ')) {
                optionData.selected = "selected";
            }
        });
    }
    else if (clientCountry) {
        var select = $("#selFromCountry")[0];
        $.each(select.options, function(index1, optionData) {
            if (!found && optionData.text == clientCountry.replace(/_/g, ' ')) {
                var ctrlId = 'selFromPort';
                optionData.selected = "selected";
                bindPortData(optionData.text, ctrlId, '', '');
                found = true;
            }
        });
    }
}


function bindCountryResults(data) {
    selectCountryFrom.options.length = 0;
    selectCountryTo.options.length = 0;

    selectCountryFrom.options.add(new Option("Select Country", ""));
    selectCountryTo.options.add(new Option("Select Country", ""));

    $.each(data, function(index, optionData) {
        var option1 = new Option(optionData.CountryName, optionData.CountryCode);
        var option2 = new Option(optionData.CountryName, optionData.CountryCode);

        if (reloadData && optionData.CountryName == selectedCountryFrom.replace(/_/g, ' ')) {
            bindPortDataFrom(optionData.CountryName);
            option1.selected = "selected";
        }

        if (optionData.CountryCode == "") {
            option1.disabled = "disabled";
        }

        if (reloadData && optionData.CountryName == selectedCountryTo.replace(/_/g, ' ')) {
            bindPortDataTo(optionData.CountryName);
            option2.selected = "selected";
        }

        if (optionData.CountryCode == "") {
            option2.disabled = "disabled";
        }

        if ($.browser.msie) {
            selectCountryFrom.add(option1);
            selectCountryTo.add(option2);
        }
        else {
            selectCountryFrom.add(option1, null);
            selectCountryTo.add(option2, null);
        }
    });
}
// ================ END COUNTRIES ===================


// ================ AIRLINES ================
function bindAirlinesData() {
    var toOption = document.createElement("option");
    toOption.value = "";
    toOption.innerHTML = "No Preference";
    selectAirlines.insertBefore(toOption, selectAirlines.firstChild);

    var found = false;
    if (reloadData) {
        $.each(selectAirlines.options, function(index1, optionData) {
            if (!found && optionData.value == selectedAirline) {
                optionData.selected = "selected";
                found = true;
            }
        });
    }

    if (!found) {
        selectAirlines.selectedIndex = 0;
    }
}
// ================ AIRLINES ================


// ================ FLIGHT CLASS ================
function bindFlightClassData() {
    if (selectFlightClass.options.length == 0) {
        selectFlightClass.options.length = 0;
        selectFlightClass.options.add(new Option("-- loading --", ""));

        var url = "/JSON/GetFlightClassData/";
        $.getJSON(url, bindFlightClassResults);
    }
}


function bindFlightClassResults(data) {
    selectFlightClass.options.length = 0;
    $.each(data, function(index, optionData) {
        var option = new Option(optionData.Name, optionData.Code);

        if (reloadData && optionData.Code == selectedFlightClass) {
            option.selected = "selected";
        }

        if ($.browser.msie) {
            selectFlightClass.add(option);
        }
        else {
            selectFlightClass.add(option, null);
        }
    });
}
// ================ AIRLINES ================


// ================ PORTS ===================
function bindPortDataFrom(countryName) {
    selectPortFrom.options.length = 0;
    selectPortFrom.options.add(new Option("-- loading --", ""));
    var url = "/JSON/GetFlightPortData/" + countryName.replace(/ /g, "_");
    $.getJSON(url, bindPortResultsFrom);
}

function bindPortDataTo(countryName) {
    selectPortTo.options.length = 0;
    selectPortTo.options.add(new Option("-- loading --", ""));
    var url = "/JSON/GetFlightPortData/" + countryName.replace(/ /g, "_");
    $.getJSON(url, bindPortResultsTo);
}

function bindPortResultsFrom(result) {
    var onlyOnePort = (result.Data.length == 1);
    selectPortFrom.options.length = 0;

    if (!onlyOnePort) {
        selectPortFrom.options.add(new Option("Select Airport", ""));
    }

    var found = false;

    $.each(result.Data, function(index, optionData) {
        var option = new Option(optionData.PortName, optionData.PortCode);

        if (!found &&
            (onlyOnePort ||
            (selectedPortFrom != null && optionData.PortCode == selectedPortFrom &&
            (selectedPortFromName == null || selectedPortFromName == "" || optionData.PortName == selectedPortFromName)))) {
            option.selected = "selected";
            found = true;
        }

        if (optionData.PortCode == "") {
            option.disabled = "disabled";
        }

        if ($.browser.msie) {
            selectPortFrom.add(option);
        }
        else {
            selectPortFrom.add(option, null);
        }
    });
}


function bindPortResultsTo(result) {
    var onlyOnePort = (result.Data.length == 1);
    selectPortTo.options.length = 0;

    if (!onlyOnePort) {
        selectPortTo.options.add(new Option("Select Airport", ""));
    }

    var found = false;
    $.each(result.Data, function(index, optionData) {
        var option = new Option(optionData.PortName, optionData.PortCode);
        if (!found && (onlyOnePort || (selectedPortTo != null && optionData.PortCode == selectedPortTo && (selectedPortToName == null || selectedPortToName == "" || optionData.PortName == selectedPortToName)))) {
            option.selected = "selected";
            found = true;
        }

        if (optionData.PortCode == "") {
            option.disabled = "disabled";
        }

        if ($.browser.msie) {
            selectPortTo.add(option);
        }
        else {
            selectPortTo.add(option, null);
        }
    });
}
// ================ END PORTS ===================


// Booking process validation
function allow_alpha(obj) {
    if (/[^a-z]/i.test(obj.value)) {
        obj.value = obj.value.replace(/[^a-z' ''\-''\'']/gi, '');
    }
    obj.value += '';
    obj.focus();
}


function allow_numeric(obj) {
    if (/[^0-9]/i.test(obj.value)) {
        obj.value = obj.value.replace(/[^0-9]/g, '');
    }
    obj.value += '';
    obj.focus();
}


function allow_phone(obj) {
    if (/[^0-9' ''\-''('')']/i.test(obj.value)) {
        obj.value = obj.value.replace(/[^0-9' ''\-''('')']/gi, '');
    }
    obj.value += '';
    obj.focus();
}


function allow_alphaNumeric(obj) {
    if (/[^\w]/i.test(obj.value)) {
        obj.value = obj.value.replace(/[^\w]/gi, '');
    }
    obj.value += '';
    obj.focus();
}

function allow_alphaNumericSpace(obj) {
    if (/[^\w' ,\-']/i.test(obj.value)) {
        obj.value = obj.value.replace(/[^\w' ,\-']/gi, '');
    }
    obj.value += '';
    obj.focus();
}

function ValidateForm(validateCreditCard) {
    return CheckTermsAndConditions() && CheckDOB() && CheckPassengerDetails() && CheckCarcCvvNumber() && CheckCardExpiryDate() && CheckCardNumber(validateCreditCard);
}


function IsPayByPhoneSelected() {
    var isSelected = false;

    if ($("input[name='PaymentDetails.PaymentType']:checked").val() == "2") {
        isSelected = true;
    }
    return isSelected;
}


function CheckTermsAndConditions() {
    var isValid = false;
    var myObj = document.getElementById('confirm_terms_1');

    if (myObj != null) {
        if (myObj.checked) {
            isValid = true;
        }
    }

    myObj = document.getElementById('divPromptTermsAndConditions');

    if (myObj != null) {
        if (isValid) {
            myObj.style.display = 'none';
            changeDOBids();
        }
        else {
            myObj.style.display = '';
        }
    }

    return isValid;
}


function CheckCarcCvvNumber() {
    var isValid = true;
    $('divInvalidSecurityCode').hide();

    if (!IsPayByPhoneSelected()) {
        var txtSecurityCode = $("#PaymentDetails_CardSecurityCode").val();
        var txtCardType = $("#PaymentDetails_CardType").val();
        isValid = ValidateSecurityCode(txtSecurityCode, txtCardType);

        if (isValid) {
            $('#divInvalidSecurityCode').hide();
        }
        else {
            $('#divInvalidSecurityCode').show();
        }
    }
    return isValid;
}


function CheckCardExpiryDate() {
    var isValid = true;

    if (!IsPayByPhoneSelected()) {        
        var selMonth = document.getElementById('PaymentDetails_ExpiryMonth');
        var selYear = document.getElementById('PaymentDetails_ExpiryYear');

        if (selMonth != null && selYear != null) {            
            var selectedMonth = selMonth.options[selMonth.selectedIndex].value;
            var selectedYear = selYear.options[selYear.selectedIndex].value;

            if (selectedMonth != "" && selectedYear != "") {
                var selectedDate = new Date();
                selectedDate.setFullYear(selectedYear, selectedMonth - 1, 1);
                selectedDate.addMonths(1);
                selectedDate.addDays(-1);
                currentDate = new Date();
                currentDate.setFullYear(new Date().getFullYear(), new Date().getMonth(), 1);
                var myObj = document.getElementById('dvInvalidExpiryDate');

                if (myObj != null) {
                    if (selectedDate < currentDate) {
                        isValid = false;
                        myObj.style.display = '';
                    }
                    else {
                        myObj.style.display = 'none';
                        isValid = true;
                    }
                }
            }
        }
    }
    return isValid;
}


function CheckCardNumber(validateCreditCard) {
    var isValid = true;
    if (!IsPayByPhoneSelected()) {
        var selCardType = document.getElementById('PaymentDetails_CardType');
        var txtCardNumber = document.getElementById('PaymentDetails_CardNumber');

        if (selCardType != null && txtCardNumber != null) {
            var selectedCardType = selCardType.options[selCardType.selectedIndex].value;
            var cardNumber = txtCardNumber.value;

            if (selectedCardType != "" && cardNumber != "" && validateCreditCard) {
                isValid = ValidateCreditCardNumber(cardNumber, selectedCardType);
                var myObj = document.getElementById('dvInvalidCard');

                if (myObj != null) {
                    if (isValid) {
                        myObj.style.display = 'none';
                    }
                    else {
                        myObj.style.display = '';
                    }
                }

            }
        }
    }
    return isValid;
}


var DEFAULT_NAME = "As appears on passport";


function NameFocus(textbox) {
    if (textbox.value == DEFAULT_NAME) {
        textbox.value = '';
        textbox.style.color = '#000';
    }
}


function NameBlur(textbox) {
    if (textbox.value == '') {
        textbox.value = DEFAULT_NAME;
        textbox.style.color = '#666';
    }
}


function CheckPassengerDetails() {
    var isValid = true;
    var isDefaultTitle = false;
    var isDefaultFirstName = false;
    var isDefaultLastName = false;
    var isDuplicated = false;
    var isFirstNameTooShort = false;
    var isFullNameTooLong = false;
    var isEmailConfirmed = false;
    var isPassportSupplied = false;
    var MIN_FIRSTNAME_LENGTH = 2;
    var MAX_FULLNAME_LENGTH = 28;
    var myObj;

    try {
        for (var i = 0; i < 9; i++) {
            var sourceFirstName;
            var sourceLastName;
            var targetFirstName;
            var targetLastName;
            var fullName;

            myObj = document.getElementById('Passengers_' + i + '__FirstName');

            if (myObj != null) {
                sourceFirstName = myObj.value;
            }

            myObj = document.getElementById('Passengers_' + i + '__LastName');

            if (myObj != null) {
                sourceLastName = myObj.value;
            }

            sourceLastName = document.getElementById('Passengers_' + i + '__LastName').value;

            var selectTitle = $get('Passengers_' + i + '__Title');
            var sourceTitle = "";

            if (selectTitle != null) {
                sourceTitle = selectTitle.options[selectTitle.selectedIndex].value;

                if (sourceTitle == "") {
                    isDefaultTitle = true;
                    $('#Passengers' + i + 'DefaultTitleError').show();
                }
                else {
                    $('#Passengers' + i + 'DefaultTitleError').hide();
                }
            }

            fullName = sourceTitle + " " + sourceFirstName + " " + sourceLastName;

            if (sourceFirstName == DEFAULT_NAME) {
                isDefaultFirstName = true;
                $('#Passengers' + i + 'DefaultFirstNameError').show();
            }
            else {
                $('#Passengers' + i + 'DefaultFirstNameError').hide();
            }

            if (sourceLastName == DEFAULT_NAME) {
                isDefaultLastName = true;
                $('#Passengers' + i + 'DefaultLastNameError').show();
            }
            else {
                $('#Passengers' + i + 'DefaultLastNameError').hide();
            }

            for (var j = 0; j < 9; j++) {
                if (j != i) {
                    myObj = document.getElementById('Passengers_' + j + '__FirstName');

                    if (myObj != null) {
                        targetFirstName = myObj.value;
                    }

                    myObj = document.getElementById('Passengers_' + j + '__LastName');

                    if (myObj != null) {
                        targetLastName = myObj.value;
                    }

                    var targetName = targetFirstName + targetLastName;

                    if (targetName.toString().toLowerCase() == sourceFirstName.toString().toLowerCase() + sourceLastName.toString().toLowerCase()) {
                        isDuplicated = true;
                        $('#Passengers' + i + 'DuplicateNameError').show();
                        $('#Passengers' + j + 'DuplicateNameError').show();
                        break;
                    }
                }
            }

            if (!isDuplicated) {
                $('#Passengers' + i + 'DuplicateNameError').hide();
            }

            if (sourceFirstName.length < MIN_FIRSTNAME_LENGTH) {
                isFirstNameTooShort = true;
                $('#Passengers' + i + 'MinimumLengthNameError').show();
            }
            else {
                $('#Passengers' + i + 'MinimumLengthNameError').hide();
            }

            if (!isDefaultFirstName && !isDefaultLastName) {
                if (fullName.length > MAX_FULLNAME_LENGTH) {
                    isFullNameTooLong = true;
                    $('#Passengers' + i + 'MaximumLengthFullNameError').show();
                }
                else {
                    $('#Passengers' + i + 'MaximumLengthFullNameError').hide();
                }
            }

            var emailAdddress;
            var confirmEmailAddress;
            myObj = document.getElementById('Passengers_' + i + '__Email');

            if (myObj != null) {
                emailAdddress = myObj.value;
            }

            myObj = document.getElementById('Passengers_' + i + '__EmailConfirm');

            if (myObj != null) {
                confirmEmailAddress = myObj.value;
            }

            if (emailAdddress == confirmEmailAddress) {
                isEmailConfirmed = true;
                $('#Passengers' + i + 'EmailMismatchError').hide();
            }
            else {
                $('#Passengers' + i + 'EmailMismatchError').show();
            }
        }
    } catch (e) { }

    return !isDefaultTitle && !isDefaultLastName && !isDefaultFirstName && !isDuplicated && !isFirstNameTooShort && !isFullNameTooLong && isEmailConfirmed;
}


function changeDOBids() {
    for (var i = 0; i < 9; i++) {
        var dobday = document.getElementById('Passengers' + i + 'DateOfBirthDay');

        if (dobday != null) {
            document.getElementById('Passengers[' + i + ']_DateOfBirthDay').value = dobday.options[dobday.selectedIndex].value;
        }

        var dobmonth = document.getElementById('Passengers' + i + 'DateOfBirthMonth');

        if (dobmonth != null) {
            document.getElementById('Passengers[' + i + ']_DateOfBirthMonth').value = dobmonth.options[dobmonth.selectedIndex].value;
        }

        var dobyear = document.getElementById('Passengers' + i + 'DateOfBirthYear');

        if (dobyear != null) {
            document.getElementById('Passengers[' + i + ']_DateOfBirthYear').value = dobyear.options[dobyear.selectedIndex].value;
        }
    }
}


function CheckDOB() {
    var isValid = true;

    for (var i = 0; i < 9; i++) {
        //if ($('#Passengers' + i + 'DateOfBirthDay') != null)
        try {
            if (!$('#Passengers' + i + 'DateOfBirthDay').valid() ||
                !$('#Passengers' + i + 'DateOfBirthMonth').valid() ||
                !$('#Passengers' + i + 'DateOfBirthYear').valid()) {
                $('#Passengers' + i + 'DateOfBirthError').show();
            }
            else {
                $('#Passengers' + i + 'DateOfBirthError').hide();
                var selDay = document.getElementById('Passengers' + i + 'DateOfBirthDay');
                var selMonth = document.getElementById('Passengers' + i + 'DateOfBirthMonth');
                var selYear = document.getElementById('Passengers' + i + 'DateOfBirthYear');

                if (selDay != null && selMonth != null && selYear != null) {
                    var selectedDay = selDay.options[selDay.selectedIndex].value;
                    var selectedMonth = selMonth.options[selMonth.selectedIndex].value;
                    var selectedYear = selYear.options[selYear.selectedIndex].value;

                    if (selectedDay != "" && selectedMonth != "" && selectedYear != "") {
                        // create the pax's DOB - assume they turn 18 at the start of the day
                        var selectedDate = new Date(selectedYear, selectedMonth - 1, selectedDay, 0, 0, 0);
                        var passengerTypeObj = document.getElementById('Passengers[' + i + ']_PassengerType');

                        if (passengerTypeObj != null) {
                            var passengerType = passengerTypeObj.value;
                            var errorDivObj;

                            // copy page-global date variable to a local copy - as this is the cutoff - make it the end of the day
                            var tempDate = new Date(departureDate.getFullYear(), departureDate.getMonth(), departureDate.getDate(), 23, 59, 59);

                            if (i == 0 && passengerType == "1") {
                                var minDate = tempDate.addYears(-18);
                                errorDivObj = document.getElementById('Passengers' + i + 'DateOfBirthAdultAgeError');

                                if (errorDivObj != null && selectedDate > minDate) {
                                    // DOB is after the DOB for an exactly 18yo - so the pax is under 18
                                    isValid = false;
                                    errorDivObj.style.display = '';
                                }
                                else {
                                    errorDivObj.style.display = 'none';
                                    isValid = true;
                                }
                            }
                            else if (passengerType == "2") {
                                var minDate = tempDate.addYears(-12);
                                errorDivObj = document.getElementById('Passengers' + i + 'DateOfBirthChildAgeError');

                                if (errorDivObj != null && selectedDate < minDate) {
                                    isValid = false;
                                    errorDivObj.style.display = '';
                                }
                                else {
                                    errorDivObj.style.display = 'none';
                                    isValid = true;
                                }
                            }
                            else if (passengerType == "3") {
                                var minDate = tempDate.addYears(-2);
                                errorDivObj = document.getElementById('Passengers' + i + 'DateOfBirthInfantAgeError');

                                if (errorDivObj != null && selectedDate < minDate) {
                                    isValid = false;
                                    errorDivObj.style.display = '';
                                }
                                else {
                                    errorDivObj.style.display = 'none';
                                    isValid = true;
                                }
                            }
                        }
                    }
                }
            }
        } catch (e) { }
    }
    return isValid;
}


function selectedDayMonthYearChanged(selectDayId, selectMonthId, selectYearId) {
    var selectDay = $get(selectDayId);
    var selectMonth = $get(selectMonthId);
    var selectYear = $get(selectYearId);

    if (selectDay != null && selectMonth != null && selectYear != null) {
        var selectedDate = new Date();
        var selectedDayValue = 0;
        var selectedMonthValue = selectedDate.getMonth();
        var selectedYearValue = selectedDate.getFullYear();

        if (selectDay.selectedIndex > 0) {
            selectedDayValue = parseInt(selectDay.options[selectDay.selectedIndex].value, 10);
        }

        if (selectMonth.selectedIndex > 0) {
            selectedMonthValue = parseInt(selectMonth.options[selectMonth.selectedIndex].value, 10);
        }

        if (selectYear.selectedIndex > 0) {
            selectedYearValue = parseInt(selectYear.options[selectYear.selectedIndex].value, 10);
        }

        selectedDate.setFullYear(selectedYearValue, selectedMonthValue - 1, 1);
        selectedDate.addMonths(1);
        selectedDate.addDays(-1);
        var maxDay = selectedDate.getDate();

        selectDay.length = 0;
        var option = new Option('Day', '');

        if ($.browser.msie) {
            selectDay.add(option);
        }
        else {
            selectDay.add(option, null);
        }

        for (count = 1; count <= maxDay; count++) {
            option = new Option(count, count);
            if ($.browser.msie) {
                selectDay.add(option);
            }
            else {
                selectDay.add(option, null);
            }
        }
        if (selectedDayValue > maxDay) {
            selectDay.selectedIndex = maxDay;
        }
        else {
            selectDay.selectedIndex = selectedDayValue;
        }
    }
}
// End Booking process validation



/******************************************************************************/
/**************************** Hotel Booking Engine ****************************/
/******************************************************************************/
var selectCountryCtrl;
var selectCityCtrl;
var selectSuburbCtrl;
var selectHotelCtrl;
var selectCurrencyCtrl;
var selectCheckInDateDayCtrl;
var selectCheckInDateMonthCtrl;
var selectCheckOutDateDayCtrl;
var selectCheckOutDateMonthCtrl;

var selectedCountry;
var selectedCity;
var selectedSuburb;
var selectedHotel;
var selectedHotelId;
var selectedCurrency;
var selectedCheckInDate;
var selectedCheckOutDate;
var reloadHotelData = false;
var selectedRatings = "";

function initObeHotel(selectCountryId, selectCityId, selectSuburbId, selectHotelId, selectCurrencyId, checkInDateDayId, checkInDateMonthId, checkOutDateDayId, checkOutDateMonthId) {    
    selectCountryCtrl = $get(selectCountryId);
    selectCityCtrl = $get(selectCityId);
    selectSuburbCtrl = $get(selectSuburbId);
    selectHotelCtrl = $get(selectHotelId);
    selectCurrencyCtrl = $get(selectCurrencyId);
    selectCheckInDateDayCtrl = $get(checkInDateDayId);
    selectCheckInDateMonthCtrl = $get(checkInDateMonthId);
    selectCheckOutDateDayCtrl = $get(checkOutDateDayId);
    selectCheckOutDateMonthCtrl = $get(checkOutDateMonthId);
   
    if (selectCountryCtrl)
    {
        bindHotelCountryData(selectCountryId, selectCityId);
    }

    // Pre-select hotel
    if (selectHotelCtrl) {
        $('#selHotelSection1').hide();
        $('#selHotelSection2').hide();
        
        if (selectedHotel.length > 0) {
            $('#selHotelSection1').show();
            $('#selHotelSection2').show();
            var option1 = new Option(selectedHotel, selectedHotelId);
            option1.selected = "selected";
            
            if ($.browser.msie) {
                selectHotelCtrl.add(option1);
            }
            else {
                selectHotelCtrl.add(option1, null);
            }
        }
    }

    bindHotelDateData();

    bindHotelCurrencyData();
}

function validateHotelBookingEngine() {
    var isValid = false;
    
    // Not allow booking for more than 25 days
    var checkInDateValue = getSelectedDate(selectCheckInDateDayCtrl, selectCheckInDateMonthCtrl);
    var checkOutDateValue = getSelectedDate(selectCheckOutDateDayCtrl, selectCheckOutDateMonthCtrl);
    var coming25Date = checkInDateValue;
    coming25Date.addDays(25);

    if (coming25Date < checkOutDateValue) {
        isValid = false;
        alert('If you wish to book for more than 25 nights, please call us on 1300 767 757');
        return isValid;
    }
    
    
    // Rating must be selected    
    $('#dvValMsgStarRatingNotSet').hide();
    var valArray = $("input:checked").serializeArray();                
    if (valArray.length == 0)
    {
        $('#dvValMsgStarRatingNotSet').show();
        isValid = false;
    }                
    else
    {
        selectedRatings == "";        
        $.each(valArray, function(i, field)
        {
            if(field.name == "rating")
            {
                if (selectedRatings == "")
                    selectedRatings = field.value;
                else
                    selectedRatings += "-" + field.value;
            }                            
        });        
        if (selectedRatings == "")
        {
            $('#dvValMsgStarRatingNotSet').show();
            isValid = false;
        }   
        else                        
            isValid = true;
    }

    return isValid;
}

function showHotelResults(url, src)
{
    url += "?hotelcity=" + escape(selectCityCtrl.options[selectCityCtrl.selectedIndex].text);
    url += "&hotelcountry=" + escape(selectCountryCtrl.options[selectCountryCtrl.selectedIndex].text);
    if (selectSuburbCtrl.selectedIndex == 0)
        url += "&hotelsuburb=";
    else
        url += "&hotelsuburb=" + escape(selectSuburbCtrl.options[selectSuburbCtrl.selectedIndex].text);
    url += "&currency=" + escape(selectCurrencyCtrl.options[selectCurrencyCtrl.selectedIndex].value);
    url += "&currencyDesc=" + escape(selectCurrencyCtrl.options[selectCurrencyCtrl.selectedIndex].text);
    url += "&chkinDate=" + getDateValue(selectCheckInDateDayCtrl, selectCheckInDateMonthCtrl);
    url += "&chkoutDate=" + getDateValue(selectCheckOutDateDayCtrl, selectCheckOutDateMonthCtrl);
    url += "&strratings=" + selectedRatings;

    url += "&requestid=" + searchRequestId;
    url += "&pgnum=1";
    url += "&sort=recommend"; // sort by recommend as default
    url += "&src=" + src;

    top.location = url;
}

function showHotelAvailability(url, hotelid, brand, requestid) {
    url += "?id=" + hotelid;
    url += "&checkin=" + getDateValue(selectCheckInDateDayCtrl, selectCheckInDateMonthCtrl);
    url += "&checkout=" + getDateValue(selectCheckOutDateDayCtrl, selectCheckOutDateMonthCtrl);    
    url += "&brandname=" + brand;
    url += "&currency=" + escape(selectCurrencyCtrl.options[selectCurrencyCtrl.selectedIndex].value);
    url += "&requestid=" + requestid;

    top.location = url;
    return true;
}

// ================ HOTEL CURRENCY =======
function bindHotelCurrencyData() {
    if (selectCurrencyCtrl == null) return;

    if (selectCurrencyCtrl.options.length == 0) {
        selectCurrencyCtrl.options.length = 0;
        selectCurrencyCtrl.options.add(new Option("-- loading --", ""));

        var url = "/JSON/GetHotelCurrencies/";
        $.getJSON(url, bindHotelCurrencyResults);
    }
    else {
        var found = false;
        $.each(selectCurrencyCtrl.options, function(index1, optionData) {
            if (!found && optionData.value == selectedCurrency) {
                optionData.selected = "selected";
                found = true;
            }
        });
    }
}

function bindHotelCurrencyResults(data) {
    if (selectCurrencyCtrl == null) return;

    selectCurrencyCtrl.options.length = 0;

    selectCurrencyCtrl.options.add(new Option("Select Currency", ""));

    $.each(data, function(index, optionData) {
        var option1 = new Option(optionData.Description, optionData.Code);
        if (optionData.Code.trim() == selectedCurrency) {
            option1.selected = "selected";
        }

        if ($.browser.msie) {
            selectCurrencyCtrl.add(option1);
        }
        else {
            selectCurrencyCtrl.add(option1, null);
        }
    });
}

// ================ END HOTEL CURRENCY =======

// ================ COUNTRIES =======
function bindHotelCountryData(selectCountryId, selectCityId)
{
    selectCountryCtrl = $("#" + selectCountryId)[0];
    selectCityCtrl = $("#" + selectCityId)[0];

    if (selectCountryCtrl.options.length == 0)
    {
        selectCountryCtrl.options.length = 0;
        selectCountryCtrl.options.add(new Option("-- loading --", ""));

        var url = "/JSON/GetHotelCountryData/";
        $.getJSON(url, bindHotelCountryResults);
    }
    else
    {
        bindHotelCountryDataPreload(selectCountryId, selectCityId);
    }
}

function bindHotelCountryResults(data)
{
    if (selectCountryCtrl == null) return;

    selectCountryCtrl.options.length = 0;

    selectCountryCtrl.options.add(new Option("Select Country", ""));

    $.each(data, function(index, optionData) {
        var option1 = new Option(optionData.CountryName, optionData.CountryId);        
        if (optionData.CountryName.trim() == selectedCountry) {
            bindHotelCityData(optionData.CountryId);
            option1.selected = "selected";
        }

        if ($.browser.msie) {
            selectCountryCtrl.add(option1);
        }
        else {
            selectCountryCtrl.add(option1, null);
        }
    });
}

function bindHotelCountryDataPreload(selectCountryId, selectCityId)
{
    selectCountryCtrl = $("#" + selectCountryId)[0];
    selectCityCtrl = $("#" + selectCityId)[0];

    // if no "header" option is present in origin country - add one
    if ($("#" + selectCountryId + " option:first").text() != "Select Country")
    {
        var toOption = document.createElement("option");
        toOption.value = "";
        toOption.innerHTML = "Select Country";
        selectCountryCtrl.insertBefore(toOption, selectCountryCtrl.firstChild);
        selectCountryCtrl.selectedIndex = 0;
    }

    var found = false;
    if (reloadHotelData)
    {
        $.each(selectCountryCtrl.options, function(index1, optionData)
        {
            if (!found && optionData.text == selectedCountry)
            {
                optionData.selected = "selected";
                found = true;
                bindHotelCityData(optionData.value);
            }
        });
    }
    else if (selectedCountry)
    {
        $.each(selectCountryCtrl.options, function(index1, optionData)
        {
            if (!found && optionData.text == selectedCountry.replace(/_/g, ' '))
            {
                optionData.selected = "selected";
                found = true;
                bindHotelCityData(optionData.value);
            }
        });
    }
}

function hotelCountryChanged(select) {    

    var countryId = $(this).find(':selected').val();
    bindHotelCityData(countryId);
}
// ================ END OF COUNTRIES==


// ================ CITIES ===========
function bindHotelCityData(countryId)
{
    selectCityCtrl = $("#selCity")[0];

    selectCityCtrl.options.length = 0;
    selectCityCtrl.options.add(new Option("-- loading --", ""));

    var url = "/JSON/GetHotelCityDataByCountryId/" + countryId;

    $.getJSON(url, bindHotelCityResults);
}

function bindHotelCityResults(data)
{
    // get control
    selectCityCtrl = $("#selCity")[0];

    selectCityCtrl.options.length = 0;

    var onlyOneCity = (data.length == 1);

    if (!onlyOneCity)
    {
        // more than one port in list - add header
        selectCityCtrl.options.add(new Option("Select City", ""));
    }

    // create a select option for each port
    $.each(data, function(index, optionData)
    {
        var option = new Option(optionData.CityName, optionData.CityId);

        if (optionData.CityId == "")
        {
            option.disabled = "disabled";
        }

        if (optionData.CityName.trim() == selectedCity) 
        {
            option.selected = "selected";
            bindHotelSuburbData(optionData.CityId);
        }

        // add select option to control
        if ($.browser.msie)
        {
            selectCityCtrl.add(option);
        }
        else
        {
            selectCityCtrl.add(option, null);
        }
    });
}

function hotelCityChanged(select) {

    var cityId = $(this).find(':selected').val();
    bindHotelSuburbData(cityId);
}

// ================ END OF CITIES ===========

// ================ BEGIN OF SUBURBS===========

function bindHotelSuburbData(cityId) {
    selectSuburbCtrl = $("#selSuburb")[0];

    selectSuburbCtrl.options.length = 0;
    selectSuburbCtrl.options.add(new Option("-- loading --", ""));

    var url = "/JSON/GetHotelSuburbDataByCityId/" + cityId;

    $.getJSON(url, bindHotelSuburbResults);
}

function bindHotelSuburbResults(data) {
    // get control
    selectSuburbCtrl = $("#selSuburb")[0];

    selectSuburbCtrl.options.length = 0;

    var onlyOneSuburb = (data.length == 1);

    if (!onlyOneSuburb) {
        // more than one port in list - add header
        selectSuburbCtrl.options.add(new Option("Select Suburb", ""));
    }

    // create a select option for each port
    $.each(data, function(index, optionData) {
        var option = new Option(optionData.SuburbName, optionData.SuburbId);

        if (optionData.SuburbId == "") {
            option.disabled = "disabled";
        }

        if (reloadHotelData && optionData.SuburbName.trim() == selectedSuburb) {
            option.selected = "selected";
        }

        // add select option to control
        if ($.browser.msie) {
            selectSuburbCtrl.add(option);
        }
        else {
            selectSuburbCtrl.add(option, null);
        }
    });
}

// ================ END OF SUBURBS ===========

// ================ DATES ===================
function bindHotelDateData()
{
    var checkInDate = new Date();

    if (reloadHotelData && selectedCheckInDate != null)
    {
        checkInDate = selectedCheckInDate;
        var checkOutDate = selectedCheckOutDate;

        if (checkOutDate == null)
        {
            checkOutDate = selectedCheckInDate;
        }
        var endDate = getEndDate();
        var startDate = getStartDate();
        
        updateSingularDateSelectionControls(selectCheckInDateDayCtrl, selectCheckInDateMonthCtrl, startDate, endDate, checkInDate);
        updateSingularDateSelectionControls(selectCheckOutDateDayCtrl, selectCheckOutDateMonthCtrl, checkInDate, endDate, checkOutDate);
    }
    else
    {
        checkInDate.addDays(3);
        updateHotelDateSelectionControls(selectCheckInDateDayCtrl, selectCheckInDateMonthCtrl, selectCheckOutDateDayCtrl, selectCheckOutDateMonthCtrl, true, checkInDate, 3);
    }
}

function checkInDateDayOBEChanged() {
    checkInDateDayChanged('selCheckInDateDay', 'selCheckInDateMonth', 'selCheckOutDateDay', 'selCheckOutDateMonth');
}

function checkInDateMonthOBEChanged() {
    checkInDateMonthChanged('selCheckInDateDay', 'selCheckInDateMonth', 'selCheckOutDateDay', 'selCheckOutDateMonth');
}

function checkOutDateDayOBEChanged() {
    checkOutDateDayChanged('selCheckInDateDay', 'selCheckInDateMonth', 'selCheckOutDateDay', 'selCheckOutDateMonth');
}

function checkOutDateMonthOBEChanged() {
    checkOutDateMonthChanged('selCheckInDateDay', 'selCheckInDateMonth', 'selCheckOutDateDay', 'selCheckOutDateMonth');
}

function bindAHotelDateData() {
    var checkInDate = new Date();

    var checkInDateDayCtrl = $get('selAHotelCheckInDateDay');
    var checkInDateMonthCtrl = $get('selAHotelCheckInDateMonth');
    var checkOutDateDayCtrl = $get('selAHotelCheckOutDateDay');
    var checkOutDateMonthCtrl = $get('selAHotelCheckOutDateMonth');

    checkInDate.addDays(3);
    updateHotelDateSelectionControls(checkInDateDayCtrl, checkInDateMonthCtrl, checkOutDateDayCtrl, checkOutDateMonthCtrl, true, checkInDate, 3);
}


function checkInDateDayAHotelChanged() {
    checkInDateDayChanged('selAHotelCheckInDateDay', 'selAHotelCheckInDateMonth', 'selAHotelCheckOutDateDay', 'selAHotelCheckOutDateMonth');
}

function checkInDateMonthAHotelChanged() {
    checkInDateMonthChanged('selAHotelCheckInDateDay', 'selAHotelCheckInDateMonth', 'selAHotelCheckOutDateDay', 'selAHotelCheckOutDateMonth');
}

function checkOutDateDayAHotelChanged() {
    checkOutDateDayChanged('selAHotelCheckInDateDay', 'selAHotelCheckInDateMonth', 'selAHotelCheckOutDateDay', 'selAHotelCheckOutDateMonth');
}

function checkOutDateMonthAHotelChanged() {
    checkOutDateMonthChanged('selAHotelCheckInDateDay', 'selAHotelCheckInDateMonth', 'selAHotelCheckOutDateDay', 'selAHotelCheckOutDateMonth');
}


function updateHotelDateSelectionControls(checkInDateDayCtrl, checkInDateMonthCtrl, checkOutDateDayCtrl, checkOutDateMonthCtrl, isCheckIn, defaultDate, returnDateIncrement)
{
    var startDate = getStartDate();
    var endDate = getEndDate();

    if (isCheckIn)
    {
        updateSingularDateSelectionControls(checkInDateDayCtrl, checkInDateMonthCtrl, startDate, endDate, defaultDate);
        var defaultCheckOutDate = new Date();
        defaultCheckOutDate.setFullYear(defaultDate.getFullYear(), defaultDate.getMonth(), defaultDate.getDate());
        defaultCheckOutDate.addDays(returnDateIncrement);

        if (defaultCheckOutDate > endDate || datesAreEqual(defaultCheckOutDate, endDate))
        {
            defaultCheckOutDate.setFullYear(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
        }
        updateSingularDateSelectionControls(checkOutDateDayCtrl, checkOutDateMonthCtrl, defaultDate, endDate, defaultCheckOutDate);
    }
    else
    {
        updateSingularDateSelectionControls(checkOutDateDayCtrl, checkOutDateMonthCtrl, defaultDate, endDate, defaultDate);
    }
}

function getDateValue(selectDateDayCtrl, selectDateMonthCtrl)
{
    var day;
    var month;
    var year;

    day = parseInt(selectDateDayCtrl.options[selectDateDayCtrl.selectedIndex].value, 10);
    var splitMonthValues = selectDateMonthCtrl.options[selectDateMonthCtrl.selectedIndex].value.split(";");

    if (splitMonthValues.length > 1)
    {
        month = parseInt(splitMonthValues[0], 10) + 1;
        year = splitMonthValues[1];
    }
    return day + "/" + month + "/" + year;
}

function checkInDateDayChanged(checkInDateDayCtrlId, checkInDateMonthCtrlId, checkOutDateDayCtrlId, checkOutDateMonthCtrlId) {
    var checkInDateDayCtrl = $get(checkInDateDayCtrlId);
    var checkInDateMonthCtrl = $get(checkInDateMonthCtrlId);
    var checkOutDateDayCtrl = $get(checkOutDateDayCtrlId);
    var checkOutDateMonthCtrl = $get(checkOutDateMonthCtrlId);
    
    var currentDate = new Date();
    var checkInDate = getSelectedDate(checkInDateDayCtrl, checkInDateMonthCtrl);
    var checkOutDate = getSelectedDate(checkOutDateDayCtrl, checkOutDateMonthCtrl);
    var startDate = getStartDate();
    var endDate = getEndDate();

    if (checkInDate < currentDate)
    {
        checkInDate.addMonths(1);
        updateSingularDateSelectionControls(checkInDateDayCtrl, checkInDateMonthCtrl, startDate, endDate, checkInDate);
        updateSingularDateSelectionControls(checkOutDateDayCtrl, checkOutDateMonthCtrl, checkInDate, endDate, checkOutDate);
    }

    if (checkInDate > endDate)
    {
        checkInDate = endDate;
        updateSingularDateSelectionControls(checkInDateDayCtrl, checkInDateMonthCtrl, startDate, endDate, checkInDate);
    }

    if (checkInDate > checkOutDate)
    {
        updateSingularDateSelectionControls(checkOutDateDayCtrl, checkOutDateMonthCtrl, checkInDate, endDate, checkInDate);
    }
}

function checkInDateMonthChanged(checkInDateDayCtrlId, checkInDateMonthCtrlId, checkOutDateDayCtrlId, checkOutDateMonthCtrlId) {
    var checkInDateDayCtrl = $get(checkInDateDayCtrlId);
    var checkInDateMonthCtrl = $get(checkInDateMonthCtrlId);
    var checkOutDateDayCtrl = $get(checkOutDateDayCtrlId);
    var checkOutDateMonthCtrl = $get(checkOutDateMonthCtrlId);
    
    var currentDate = new Date();
    // get selected date
    var checkInDate = getSelectedDate(checkInDateDayCtrl, checkInDateMonthCtrl);
    var checkOutDate = getSelectedDate(checkOutDateDayCtrl, checkOutDateMonthCtrl);
    var startDate = getStartDate();
    var endDate = getEndDate();
    var updated = false;

    if (checkInDate < currentDate)
    {
        checkInDate = currentDate;
        updateSingularDateSelectionControls(checkInDateDayCtrl, checkInDateMonthCtrl, startDate, endDate, checkInDate);
        updateSingularDateSelectionControls(checkOutDateDayCtrl, checkOutDateMonthCtrl, checkInDate, endDate, checkOutDate);
        updated = true;
    }

    if (checkInDate > endDate)
    {
        checkInDate = endDate;
        updateSingularDateSelectionControls(checkInDateDayCtrl, checkInDateMonthCtrl, startDate, endDate, checkInDate);
    }

    if (checkInDate > checkOutDate)
    {
        updateHotelDateSelectionControls(checkInDateDayCtrl, checkInDateMonthCtrl, checkOutDateDayCtrl, checkOutDateMonthCtrl, true, checkInDate, 0);
    }
    else
    {
        if (!updated)
        {
            updateSingularDateSelectionControls(checkInDateDayCtrl, checkInDateMonthCtrl, startDate, endDate, checkInDate);
            updateSingularDateSelectionControls(checkOutDateDayCtrl, checkOutDateMonthCtrl, checkInDate, endDate, checkOutDate);
        }
    }
}

function checkOutDateMonthChanged(checkInDateDayCtrlId, checkInDateMonthCtrlId, checkOutDateDayCtrlId, checkOutDateMonthCtrlId) {
    var checkInDateDayCtrl = $get(checkInDateDayCtrlId);
    var checkInDateMonthCtrl = $get(checkInDateMonthCtrlId);
    var checkOutDateDayCtrl = $get(checkOutDateDayCtrlId);
    var checkOutDateMonthCtrl = $get(checkOutDateMonthCtrlId);
    
    var checkInDate = getSelectedDate(checkInDateDayCtrl, checkInDateMonthCtrl);
    var checkOutDate = getSelectedDate(checkOutDateDayCtrl, checkOutDateMonthCtrl);

    if (checkOutDate)
    {
        if (checkInDate > checkOutDate)
        {
            updateHotelDateSelectionControls(checkInDateDayCtrl, checkInDateMonthCtrl, checkOutDateDayCtrl, checkOutDateMonthCtrl, true, checkInDate, 0);
        }
        else
        {
            var endDate = getEndDate();
            updateSingularDateSelectionControls(checkOutDateDayCtrl, checkOutDateMonthCtrl, checkInDate, endDate, checkOutDate);
        }
    }
}


function checkOutDateDayChanged(checkInDateDayCtrlId, checkInDateMonthCtrlId, checkOutDateDayCtrlId, checkOutDateMonthCtrlId) {
    var checkInDateDayCtrl = $get(checkInDateDayCtrlId);
    var checkInDateMonthCtrl = $get(checkInDateMonthCtrlId);
    var checkOutDateDayCtrl = $get(checkOutDateDayCtrlId);
    var checkOutDateMonthCtrl = $get(checkOutDateMonthCtrlId);
    
    var checkInDate = getSelectedDate(checkInDateDayCtrl, checkInDateMonthCtrl);
    var checkOutDate = getSelectedDate(checkOutDateDayCtrl, checkOutDateMonthCtrl);

    if (checkInDate > checkOutDate)
    {
        checkOutDate.addMonths(1);
        var endDate = getEndDate();

        if (checkOutDate > endDate)
        {
            checkOutDate = endDate;
        }

        if (checkOutDate)
        {
            updateSingularDateSelectionControls(checkOutDateDayCtrl, checkOutDateMonthCtrl, checkInDate, endDate, checkOutDate);
        }
    }
}

function SelectHotel(selectedId, checkInDate, checkOutDate, brandName) {
    $("#selectedHotelId").val(selectedId);
    $("#selectedCheckInDate").val(checkInDate);
    $("#selectedCheckOutDate").val(checkOutDate);
    $("#selectedBrandName").val(brandName);

}

// ================ END OF DATES ===================

// ================ NUMBER OF ROOM ===================

function GenerateSelectListValue(selectListId, fromValue, toValue, isDefaultBlank, firstItemText) {
    var selectListCtrl = $get(selectListId);

    if (isDefaultBlank == true)
        selectListCtrl.options.add(new Option('', 0));

    var startFrom = fromValue;
    
    if (firstItemText.length > 0) {
        selectListCtrl.options.add(new Option(firstItemText, fromValue));
        startFrom = fromValue + 1;
    }

    for (var i = startFrom; i <= toValue; i++) {        
        selectListCtrl.options.add(new Option(i, i));   
    }
}

function NumberOfRoomControlChanged(roomId, subTotalCtrlId, roomTypeId, qtyAvailable, totalCtrlId, subTotalPerRoom, recordedItineraryUrl, btnBookingId,
                                    recordedRoomTypeId, recordedBeddingId, recordedNumberOfBeddingId, messageboxId, pageContentId,
                                    tmpBtnBookingId, tmpRoomCtrlIdId, tmpRoomCtrlValueId, tmpSubTotalCtrllIdId,
                                    tmpRoomTypeId, tmpRoomTypeQtyAvailableId, tmpTotalCtrlIdId, tmpSubTotalPerRoomId) {

    // Validate if user selects same room type.
    var isSelectedSameRoomType = false;
    var recordedRoomTypeCtrl = $('#' + recordedRoomTypeId);
    
    if (recordedRoomTypeCtrl.val().length == 0) {
        isSelectedSameRoomType = true;
    }
    else if (recordedRoomTypeCtrl.val().trim() == roomTypeId.trim()) {
        isSelectedSameRoomType = true;
    }

    // HotelClub support booking per room type, hence a message box for switching difference selection of room type must be triggered
    if (isSelectedSameRoomType == true)
        CalculateRoomTotal(roomId, subTotalCtrlId, roomTypeId, qtyAvailable, totalCtrlId, subTotalPerRoom, recordedItineraryUrl, btnBookingId, recordedRoomTypeId, recordedBeddingId, recordedNumberOfBeddingId);
    else {        
        // record user new selection
        $get(tmpRoomCtrlIdId).value = roomId;
        $get(tmpRoomCtrlValueId).value = $get(roomId).value;
        $get(tmpSubTotalCtrllIdId).value = subTotalCtrlId;
        $get(tmpRoomTypeId).value = roomTypeId;
        $get(tmpRoomTypeQtyAvailableId).value = qtyAvailable;
        $get(tmpTotalCtrlIdId).value = totalCtrlId;
        $get(tmpSubTotalPerRoomId).value = subTotalPerRoom;
        $get(tmpBtnBookingId).value = btnBookingId;

        // Confirmation for switching room type
        HotelConfirmChangeRoomTypeMsgToggle(true, messageboxId, pageContentId);
    }    
}

function CalculateRoomTotal(roomId, subTotalCtrlId, roomTypeId, qtyAvailable, totalCtrlId, subTotalPerRoom, recordedItineraryUrl, btnBookingId, recordedRoomTypeId, recordedBeddingId, recordedNumberOfBeddingId) {
    // Calculate sub total per bedding option
    var roomCtrl = $get(roomId);
    var orderQty = parseInt(roomCtrl.value);
    var previousQty = 0;

    // Record selected room type
    var recordedRoomTypeCtrl = $get(recordedRoomTypeId);
    var recordedBeddingCtrl = $get(recordedBeddingId);
    var recordedNumberOfBeddingCtrl = $get(recordedNumberOfBeddingId);
    
    

    var recordedBeddings = recordedBeddingCtrl.value.split('/');
    var recordedNumberOfBeddings = recordedNumberOfBeddingCtrl.value.split('/');
    if (recordedNumberOfBeddingCtrl.value.length > 0 && recordedNumberOfBeddings.length > 0) {
        for (var i = 0; i < recordedNumberOfBeddings.length; i++) {
            if (recordedBeddings[i] == roomId) {
                previousQty = parseInt(recordedNumberOfBeddings[i]);
            }
            else {
                orderQty += parseInt(recordedNumberOfBeddings[i]);
            }
        }
    }

    if ((orderQty > qtyAvailable) && (qtyAvailable > 0)) {
        // Reset selected quantity
        roomCtrl.value = previousQty;              
        HotelConfirmChangeRoomTypeMsgToggle(true, 'errorBoxId', 'pageContent');
        return;
    }
    
    
    $('#' + subTotalCtrlId).html((roomCtrl.value * subTotalPerRoom).toFixed(2));

    // Calculate total per room type
    // Sub total Id are defined follow this pattern [totalCtrlId-roomId]
    var totalCtrl = $get(totalCtrlId);
    var total = 0.00;
    $("span[id^='" + totalCtrlId + "_']").each(function() {
        var str = $(this).text();
        if (str.length > 0) {
            total = total + parseFloat(str);
        }
    });
    if (document.all)
        totalCtrl.innerText = total.toFixed(2);
    else
        totalCtrl.textContent = total.toFixed(2);
    
    recordedRoomTypeCtrl.value = roomTypeId;

    // No selection before, this is the first selected action.
    if (recordedBeddingCtrl.value == "" || recordedBeddingCtrl.value.length == 0)
    {
        recordedBeddingCtrl.value = roomId;
        recordedNumberOfBeddingCtrl.value = roomCtrl.value;
    }
    else 
    {
        // From second selection actions, need to verify if user selects a new bedding options or revises the previous one.
        var revised = false;
        
        if (recordedBeddings.length > 0) 
            for (var i = 0; i < recordedBeddings.length; i++) 
                if (recordedBeddings[i] == roomId) 
                {
                    recordedNumberOfBeddings[i] = roomCtrl.value;
                    revised = true;
                    break;
                }
        
        // re-build list of selected bedding options
        recordedBeddingCtrl.value = recordedBeddings[0];
        recordedNumberOfBeddingCtrl.value = recordedNumberOfBeddings[0];
        for (var i = 1; i < recordedBeddings.length; i++) 
        {
            recordedBeddingCtrl.value = recordedBeddingCtrl.value + '/' + recordedBeddings[i];
            recordedNumberOfBeddingCtrl.value = recordedNumberOfBeddingCtrl.value + '/' + recordedNumberOfBeddings[i];
        }
        
        // add current selected bedding option to the end if it's new selected
        if (revised == false)
        {
            recordedBeddingCtrl.value = recordedBeddingCtrl.value + '/' + roomId;
            recordedNumberOfBeddingCtrl.value = recordedNumberOfBeddingCtrl.value + '/' + roomCtrl.value;
        }
    }   

    var btnBookingCtrl = $('#' + btnBookingId);
    
    if (btnBookingCtrl != null) {
        var itiUrl = $get(recordedItineraryUrl).value;
        // create parameter
        itiUrl = itiUrl + "&" + "roomtypeid=" + roomTypeId;
        itiUrl = itiUrl + "&" + "beddings=" + recordedBeddingCtrl.value;
        itiUrl = itiUrl + "&" + "numberofbeds=" + recordedNumberOfBeddingCtrl.value;
        
        btnBookingCtrl.attr('href', itiUrl);
    }
}

function HotelConfirmChangeRoomTypeMsg(isConfirmed, recordedRoomTypeId, recordedBeddingId, recordedNumberOfBeddingId, 
                                        recordedItineraryUrl, tmpBtnBookingIdId, messageBoxId, pageContentId,
                                        tmpRoomCtrlIdId, tmpRoomCtrlValueId, tmpSubTotalCtrlIdId,
                                        tmpRoomTypeId, tmpRoomTypeQtyAvailableId, tmpTotalCtrlIdId, tmpSubTotalPerRoomId) {

    // Hide confirmation box
    HotelConfirmChangeRoomTypeMsgToggle(false, messageBoxId, pageContentId);

    var roomId = $get(tmpRoomCtrlIdId).value;
    var roomTypeId = $get(tmpRoomTypeId).value;
        
    if (isConfirmed == true) {
        // Reset recorded information
        $get(recordedRoomTypeId).value = "";
        $get(recordedBeddingId).value = "";
        $get(recordedNumberOfBeddingId).value = "";

        // Reset all sub total/total to blank
        $("span[id^='total_']").each(function() {
            $(this).text("");
        });

        // Reset all room selectors, except the current/entire one
        $("select:not([id^='" + roomTypeId + "'])").each(function() {
            $(this).val("0");
        });

        // Remove all booking href links, prevent unexpecting mistake from users.
        // TODO: It is better to use difference image (gray color) to present the button as disabled
        $("a:not([id$='" + roomTypeId + "'])").each(function() {
            $(this).removeAttr("href");
        });

        $get(roomId).value = $get(tmpRoomCtrlValueId).value;

        CalculateRoomTotal(roomId, $get(tmpSubTotalCtrlIdId).value, roomTypeId, $get(tmpRoomTypeQtyAvailableId).value,
                           $get(tmpTotalCtrlIdId).value, $get(tmpSubTotalPerRoomId).value, 
                           recordedItineraryUrl, $get(tmpBtnBookingIdId).value,
                           recordedRoomTypeId, recordedBeddingId, recordedNumberOfBeddingId)
    }
    else {
        // Not to change room type, reverse it back to blank
        $get(roomId).value = "0";
    }

    // Reset temporary value
    $get(tmpRoomCtrlIdId).value = "";
    $get(tmpRoomCtrlValueId).value = "";
    $get(tmpSubTotalCtrlIdId).value = "";
    $get(tmpRoomTypeId).value = "";
    $get(tmpTotalCtrlIdId).value = "";
    $get(tmpSubTotalPerRoomId).value = "";
    $get(tmpBtnBookingIdId).value = "";
}

function HotelConfirmChangeRoomTypeMsgToggle(isShown, messageBoxId, pageContentId) {
    var messageBoxCtrl = $('#' + messageBoxId);
    if (messageBoxCtrl == null) return;

    if (isShown == false) {        
        messageBoxCtrl.css("display", "none");        
        $('#' + pageContentId + ' :input').removeAttr('disabled');        
    }
    else {
        $('#' + pageContentId + ' :input').attr('disabled', true);
        $('#' + messageBoxId + ' :input').removeAttr('disabled');
        messageBoxCtrl.css("display", "block");
        messageBoxCtrl.css("position", "absolute");
        messageBoxCtrl.css("top", (($(window).height() - messageBoxCtrl.outerHeight()) / 2) + $(window).scrollTop() + "px");
        messageBoxCtrl.css("left", (($(window).width() - messageBoxCtrl.outerWidth()) / 2) + $(window).scrollLeft() + "px");
    }      
}


function ValidateRoomAvailability(linkCtrl, qtyAvailable, recordedNumberOfBeddingId, errorBoxId, pageContentId) {
    var valid = true;

    // no information about room quantity available => skip validation
    if (qtyAvailable <= 0)
        return valid;

    var recordedBeddings = $get(recordedNumberOfBeddingId).value.split('/');
    var selectedQty = 0;

    if (recordedBeddings.length > 0) {
        for (var i = 0; i < recordedBeddings.length; i++) {
            selectedQty = selectedQty + recordedBeddings[i];
        }
    }   

    if (selectedQty > qtyAvailable)
        valid = false;

    if (valid == false) {
        alert(linkCtrl.href);
        event.preventDefault();
        HotelConfirmChangeRoomTypeMsgToggle(true, errorBoxId, pageContentId);
    }        
                        
    return valid;
    
}
// ================ END OF NUMBER OF ROOM ===================

// ================ NUMBER OF CHILD ===================
function numOfChildrenChanged(numOfChildrenSelCtrl, rowSelectChildrenAgeId, maxNumOfChildren) {
    
    if ((numOfChildrenSelCtrl == null) || (numOfChildrenSelCtrl == undefined))
        return;
        
    // Hide all children age by default
    toggleChildrenAgeCtrl(rowSelectChildrenAgeId, maxNumOfChildren, false)

    // Show the children age according to selected number of children per room
    if (numOfChildrenSelCtrl.value > 0) {
        toggleChildrenAgeCtrl(rowSelectChildrenAgeId, numOfChildrenSelCtrl.value, true)
    }
}

function toggleChildrenAgeCtrl(rowSelectChildrenAgeId, maxNumOfChildren, isShow)
{
    var showChildAge = "none";
    
    if (isShow == true)
        showChildAge = "block"
        
    var rowSelectChildrenAgeCtrl = $('#' + rowSelectChildrenAgeId);

    if ((rowSelectChildrenAgeCtrl == null) || (rowSelectChildrenAgeCtrl == undefined))
        return;
    
    rowSelectChildrenAgeCtrl.css("display", showChildAge);
    for(var i=0; i<maxNumOfChildren; i++)
    {
        var childrenAgeCtrl = $('#' + rowSelectChildrenAgeId + '_' + i);
        if ((childrenAgeCtrl != null) && (childrenAgeCtrl != undefined))
            childrenAgeCtrl.css("display", showChildAge);
    }
}

// ================ END OF NUMBER OF CHILD ===================

// ================ BEGIN of Hotel Confirmation/Validation ===================

function ValidateHotelForm(validateCreditCard) {
    var isValid = $('#formBook').valid() & CheckGuestDetails() && CheckRoomDetails() && CheckTermsAndConditions() && CheckCardExpiryDate() && CheckCardNumber(validateCreditCard);
    
    // Display general error message at the bottom
    if (isValid == false)
        $('#GeneralErrorMessage').show();
    else
        $('#GeneralErrorMessage').hide();
        
    return isValid;
}

function CheckRoomDetails() {
    var isValid = false;
    var maxPax = 0;
    var numOfAdult = 0;
    var numOfChildren = 0;
    var totalPax = 0;
    var myObj;

    try {
        myObj = document.getElementById('RoomCount');
        var roomCount = 0;
        if (myObj != null) {
            roomCount = parseInt(myObj.value);
        }        
        
        for (var i = 0; i < roomCount; i++) {
            myObj = document.getElementById('Rooms_' + i + '__MaxPax');
            if (myObj != null) {
                maxPax = parseInt(myObj.value);
            }

            myObj = document.getElementById('Rooms_' + i + '__NumOfAdult');
            if (myObj != null) {
                numOfAdult = parseInt(myObj.value);
            }

            myObj = document.getElementById('Rooms_' + i + '__NumOfChildren');
            if (myObj != null) {
                numOfChildren = parseInt(myObj.value);
            }

            totalPax = numOfAdult + numOfChildren;

            if (totalPax == 0) {
                $('#Rooms' + i + 'NoPaxError').show();
            }
            else {
                $('#Rooms' + i + 'NoPaxError').hide();
                if (totalPax > maxPax) {
                    $('#Rooms' + i + 'ExcessMaxPaxError').show();
                }
                else {
                    $('#Rooms' + i + 'ExcessMaxPaxError').hide();
                    isValid = true;
                }
            }
        }
    }
    catch (e) {
        return false;
    }

    return isValid;
}

function CheckGuestDetails() {    
    var isValid = false;
    var MIN_FIRSTNAME_LENGTH = 2;    
    var myObj;

    try {        
            var sourceFirstName;
            var sourceLastName;
            var sourceEmail;
            var sourceEmailConfirm;

            myObj = document.getElementById('Guest_FirstName');
            if (myObj != null) {
                sourceFirstName = myObj.value;
            }

            myObj = document.getElementById('Guest_LastName');
            if (myObj != null) {
                sourceLastName = myObj.value;
            }
            
            if (sourceFirstName.length < MIN_FIRSTNAME_LENGTH) {
                $('#GuestsMinimumLengthNameError').show();
                isValid = false;
            }
            else {
                isValid = true;
                $('#GuestsMinimumLengthNameError').hide();
            }

            myObj = document.getElementById('Guest_Email');
            if (myObj != null) {
                sourceEmail = myObj.value;
            }
            
            myObj = document.getElementById('Guest_EmailConfirm');
            if (myObj != null) {
                sourceEmailConfirm = myObj.value;
            }

            if (sourceEmail != sourceEmailConfirm) {
                $('#GuestsEmailMismatchError').show();
                isValid = false;
            }
            else {
                $('#GuestsEmailMismatchError').hide();
                isValid = true;
            }            
        }
        catch (e) {
            return false;
        }

    return isValid;
}

// ================ END of Hotel Confirmation/Validation ===================
/****************************************************************/

/*              jQuery.countdown.js                             */

/* http://keith-wood.name/countdown.html
Countdown for jQuery v1.5.9.
Written by Keith Wood (kbwood{at}iinet.com.au) January 2008.
Dual licensed under the GPL (http://dev.jquery.com/browser/trunk/jquery/GPL-LICENSE.txt) and 
MIT (http://dev.jquery.com/browser/trunk/jquery/MIT-LICENSE.txt) licenses. 
Please attribute the author if you use it. */

/* Display a countdown timer.
Attach it with options like:
$('div selector').countdown(
{until: new Date(2009, 1 - 1, 1, 0, 0, 0), onExpiry: happyNewYear}); */

(function($) { // Hide scope, no $ conflict

    /* Countdown manager. */
    function Countdown() {
        this.regional = []; // Available regional settings, indexed by language code
        this.regional[''] = { // Default regional settings
            // The display texts for the counters
            labels: ['Years', 'Months', 'Weeks', 'Days', 'Hours', 'Minutes', 'Seconds'],
            // The display texts for the counters if only one
            labels1: ['Year', 'Month', 'Week', 'Day', 'Hour', 'Minute', 'Second'],
            compactLabels: ['y', 'm', 'w', 'd'], // The compact texts for the counters
            whichLabels: null, // Function to determine which labels to use
            timeSeparator: ':', // Separator for time periods
            isRTL: false // True for right-to-left languages, false for left-to-right
        };
        this._defaults = {
            until: null, // new Date(year, mth - 1, day, hr, min, sec) - date/time to count down to
            // or numeric for seconds offset, or string for unit offset(s):
            // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds
            since: null, // new Date(year, mth - 1, day, hr, min, sec) - date/time to count up from
            // or numeric for seconds offset, or string for unit offset(s):
            // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds
            timezone: null, // The timezone (hours or minutes from GMT) for the target times,
            // or null for client local
            serverSync: null, // A function to retrieve the current server time for synchronisation
            format: 'dHMS', // Format for display - upper case for always, lower case only if non-zero,
            // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds
            layout: '', // Build your own layout for the countdown
            compact: false, // True to display in a compact format, false for an expanded one
            significant: 0, // The number of periods with values to show, zero for all
            description: '', // The description displayed for the countdown
            expiryUrl: '', // A URL to load upon expiry, replacing the current page
            expiryText: '', // Text to display upon expiry, replacing the countdown
            alwaysExpire: false, // True to trigger onExpiry even if never counted down
            onExpiry: null, // Callback when the countdown expires -
            // receives no parameters and 'this' is the containing division
            onTick: null, // Callback when the countdown is updated -
            // receives int[7] being the breakdown by period (based on format)
            // and 'this' is the containing division
            tickInterval: 1 // Interval (seconds) between onTick callbacks
        };
        $.extend(this._defaults, this.regional['']);
        this._serverSyncs = [];
    }

    var PROP_NAME = 'countdown';

    var Y = 0; // Years
    var O = 1; // Months
    var W = 2; // Weeks
    var D = 3; // Days
    var H = 4; // Hours
    var M = 5; // Minutes
    var S = 6; // Seconds

    $.extend(Countdown.prototype, {
        /* Class name added to elements to indicate already configured with countdown. */
        markerClassName: 'hasCountdown',

        /* Shared timer for all countdowns. */
        _timer: setInterval(function() { $.countdown._updateTargets(); }, 980),
        /* List of currently active countdown targets. */
        _timerTargets: [],

        /* Override the default settings for all instances of the countdown widget.
        @param  options  (object) the new settings to use as defaults */
        setDefaults: function(options) {
            this._resetExtraLabels(this._defaults, options);
            extendRemove(this._defaults, options || {});
        },

        /* Convert a date/time to UTC.
        @param  tz     (number) the hour or minute offset from GMT, e.g. +9, -360
        @param  year   (Date) the date/time in that timezone or
        (number) the year in that timezone
        @param  month  (number, optional) the month (0 - 11) (omit if year is a Date)
        @param  day    (number, optional) the day (omit if year is a Date)
        @param  hours  (number, optional) the hour (omit if year is a Date)
        @param  mins   (number, optional) the minute (omit if year is a Date)
        @param  secs   (number, optional) the second (omit if year is a Date)
        @param  ms     (number, optional) the millisecond (omit if year is a Date)
        @return  (Date) the equivalent UTC date/time */
        UTCDate: function(tz, year, month, day, hours, mins, secs, ms) {
            if (typeof year == 'object' && year.constructor == Date) {
                ms = year.getMilliseconds();
                secs = year.getSeconds();
                mins = year.getMinutes();
                hours = year.getHours();
                day = year.getDate();
                month = year.getMonth();
                year = year.getFullYear();
            }
            var d = new Date();
            d.setUTCFullYear(year);
            d.setUTCDate(1);
            d.setUTCMonth(month || 0);
            d.setUTCDate(day || 1);
            d.setUTCHours(hours || 0);
            d.setUTCMinutes((mins || 0) - (Math.abs(tz) < 30 ? tz * 60 : tz));
            d.setUTCSeconds(secs || 0);
            d.setUTCMilliseconds(ms || 0);
            return d;
        },

        /* Convert a set of periods into seconds.
        Averaged for months and years.
        @param  periods  (number[7]) the periods per year/month/week/day/hour/minute/second
        @return  (number) the corresponding number of seconds */
        periodsToSeconds: function(periods) {
            return periods[0] * 31557600 + periods[1] * 2629800 + periods[2] * 604800 +
			periods[3] * 86400 + periods[4] * 3600 + periods[5] * 60 + periods[6];
        },

        /* Retrieve one or more settings values.
        @param  name  (string, optional) the name of the setting to retrieve
        or 'all' for all instance settings or omit for all default settings
        @return  (any) the requested setting(s) */
        _settingsCountdown: function(target, name) {
            if (!name) {
                return $.countdown._defaults;
            }
            var inst = $.data(target, PROP_NAME);
            return (name == 'all' ? inst.options : inst.options[name]);
        },

        /* Attach the countdown widget to a div.
        @param  target   (element) the containing division
        @param  options  (object) the initial settings for the countdown */
        _attachCountdown: function(target, options) {
            var $target = $(target);
            if ($target.hasClass(this.markerClassName)) {
                return;
            }
            $target.addClass(this.markerClassName);
            var inst = { options: $.extend({}, options),
                _periods: [0, 0, 0, 0, 0, 0, 0]
            };
            $.data(target, PROP_NAME, inst);
            this._changeCountdown(target);
        },

        /* Add a target to the list of active ones.
        @param  target  (element) the countdown target */
        _addTarget: function(target) {
            if (!this._hasTarget(target)) {
                this._timerTargets.push(target);
            }
        },

        /* See if a target is in the list of active ones.
        @param  target  (element) the countdown target
        @return  (boolean) true if present, false if not */
        _hasTarget: function(target) {
            return ($.inArray(target, this._timerTargets) > -1);
        },

        /* Remove a target from the list of active ones.
        @param  target  (element) the countdown target */
        _removeTarget: function(target) {
            this._timerTargets = $.map(this._timerTargets,
			function(value) { return (value == target ? null : value); }); // delete entry
        },

        /* Update each active timer target. */
        _updateTargets: function() {
            for (var i = this._timerTargets.length - 1; i >= 0; i--) {
                this._updateCountdown(this._timerTargets[i]);
            }
        },

        /* Redisplay the countdown with an updated display.
        @param  target  (jQuery) the containing division
        @param  inst    (object) the current settings for this instance */
        _updateCountdown: function(target, inst) {
            var $target = $(target);
            inst = inst || $.data(target, PROP_NAME);
            if (!inst) {
                return;
            }
            $target.html(this._generateHTML(inst));
            $target[(this._get(inst, 'isRTL') ? 'add' : 'remove') + 'Class']('countdown_rtl');
            var onTick = this._get(inst, 'onTick');
            if (onTick) {
                var periods = inst._hold != 'lap' ? inst._periods :
				this._calculatePeriods(inst, inst._show, this._get(inst, 'significant'), new Date());
                var tickInterval = this._get(inst, 'tickInterval');
                if (tickInterval == 1 || this.periodsToSeconds(periods) % tickInterval == 0) {
                    onTick.apply(target, [periods]);
                }
            }
            var expired = inst._hold != 'pause' &&
			(inst._since ? inst._now.getTime() < inst._since.getTime() :
			inst._now.getTime() >= inst._until.getTime());
            if (expired && !inst._expiring) {
                inst._expiring = true;
                if (this._hasTarget(target) || this._get(inst, 'alwaysExpire')) {
                    this._removeTarget(target);
                    var onExpiry = this._get(inst, 'onExpiry');
                    if (onExpiry) {
                        onExpiry.apply(target, []);
                    }
                    var expiryText = this._get(inst, 'expiryText');
                    if (expiryText) {
                        var layout = this._get(inst, 'layout');
                        inst.options.layout = expiryText;
                        this._updateCountdown(target, inst);
                        inst.options.layout = layout;
                    }
                    var expiryUrl = this._get(inst, 'expiryUrl');
                    if (expiryUrl) {
                        window.location = expiryUrl;
                    }
                }
                inst._expiring = false;
            }
            else if (inst._hold == 'pause') {
                this._removeTarget(target);
            }
            $.data(target, PROP_NAME, inst);
        },

        /* Reconfigure the settings for a countdown div.
        @param  target   (element) the containing division
        @param  options  (object) the new settings for the countdown or
        (string) an individual property name
        @param  value    (any) the individual property value
        (omit if options is an object) */
        _changeCountdown: function(target, options, value) {
            options = options || {};
            if (typeof options == 'string') {
                var name = options;
                options = {};
                options[name] = value;
            }
            var inst = $.data(target, PROP_NAME);
            if (inst) {
                this._resetExtraLabels(inst.options, options);
                extendRemove(inst.options, options);
                this._adjustSettings(target, inst);
                $.data(target, PROP_NAME, inst);
                var now = new Date();
                if ((inst._since && inst._since < now) ||
					(inst._until && inst._until > now)) {
                    this._addTarget(target);
                }
                this._updateCountdown(target, inst);
            }
        },

        /* Reset any extra labelsn and compactLabelsn entries if changing labels.
        @param  base     (object) the options to be updated
        @param  options  (object) the new option values */
        _resetExtraLabels: function(base, options) {
            var changingLabels = false;
            for (var n in options) {
                if (n != 'whichLabels' && n.match(/[Ll]abels/)) {
                    changingLabels = true;
                    break;
                }
            }
            if (changingLabels) {
                for (var n in base) { // Remove custom numbered labels
                    if (n.match(/[Ll]abels[0-9]/)) {
                        base[n] = null;
                    }
                }
            }
        },

        /* Calculate interal settings for an instance.
        @param  target  (element) the containing division
        @param  inst    (object) the current settings for this instance */
        _adjustSettings: function(target, inst) {
            var now;
            var serverSync = this._get(inst, 'serverSync');
            var serverOffset = 0;
            var serverEntry = null;
            for (var i = 0; i < this._serverSyncs.length; i++) {
                if (this._serverSyncs[i][0] == serverSync) {
                    serverEntry = this._serverSyncs[i][1];
                    break;
                }
            }
            if (serverEntry != null) {
                serverOffset = (serverSync ? serverEntry : 0);
                now = new Date();
            }
            else {
                var serverResult = (serverSync ? serverSync.apply(target, []) : null);
                now = new Date();
                serverOffset = (serverResult ? now.getTime() - serverResult.getTime() : 0);
                this._serverSyncs.push([serverSync, serverOffset]);
            }
            var timezone = this._get(inst, 'timezone');
            timezone = (timezone == null ? -now.getTimezoneOffset() : timezone);
            inst._since = this._get(inst, 'since');
            if (inst._since != null) {
                inst._since = this.UTCDate(timezone, this._determineTime(inst._since, null));
                if (inst._since && serverOffset) {
                    inst._since.setMilliseconds(inst._since.getMilliseconds() + serverOffset);
                }
            }
            inst._until = this.UTCDate(timezone, this._determineTime(this._get(inst, 'until'), now));
            if (serverOffset) {
                inst._until.setMilliseconds(inst._until.getMilliseconds() + serverOffset);
            }
            inst._show = this._determineShow(inst);
        },

        /* Remove the countdown widget from a div.
        @param  target  (element) the containing division */
        _destroyCountdown: function(target) {
            var $target = $(target);
            if (!$target.hasClass(this.markerClassName)) {
                return;
            }
            this._removeTarget(target);
            $target.removeClass(this.markerClassName).empty();
            $.removeData(target, PROP_NAME);
        },

        /* Pause a countdown widget at the current time.
        Stop it running but remember and display the current time.
        @param  target  (element) the containing division */
        _pauseCountdown: function(target) {
            this._hold(target, 'pause');
        },

        /* Pause a countdown widget at the current time.
        Stop the display but keep the countdown running.
        @param  target  (element) the containing division */
        _lapCountdown: function(target) {
            this._hold(target, 'lap');
        },

        /* Resume a paused countdown widget.
        @param  target  (element) the containing division */
        _resumeCountdown: function(target) {
            this._hold(target, null);
        },

        /* Pause or resume a countdown widget.
        @param  target  (element) the containing division
        @param  hold    (string) the new hold setting */
        _hold: function(target, hold) {
            var inst = $.data(target, PROP_NAME);
            if (inst) {
                if (inst._hold == 'pause' && !hold) {
                    inst._periods = inst._savePeriods;
                    var sign = (inst._since ? '-' : '+');
                    inst[inst._since ? '_since' : '_until'] =
					this._determineTime(sign + inst._periods[0] + 'y' +
						sign + inst._periods[1] + 'o' + sign + inst._periods[2] + 'w' +
						sign + inst._periods[3] + 'd' + sign + inst._periods[4] + 'h' +
						sign + inst._periods[5] + 'm' + sign + inst._periods[6] + 's');
                    this._addTarget(target);
                }
                inst._hold = hold;
                inst._savePeriods = (hold == 'pause' ? inst._periods : null);
                $.data(target, PROP_NAME, inst);
                this._updateCountdown(target, inst);
            }
        },

        /* Return the current time periods.
        @param  target  (element) the containing division
        @return  (number[7]) the current periods for the countdown */
        _getTimesCountdown: function(target) {
            var inst = $.data(target, PROP_NAME);
            return (!inst ? null : (!inst._hold ? inst._periods :
			this._calculatePeriods(inst, inst._show, this._get(inst, 'significant'), new Date())));
        },

        /* Get a setting value, defaulting if necessary.
        @param  inst  (object) the current settings for this instance
        @param  name  (string) the name of the required setting
        @return  (any) the setting's value or a default if not overridden */
        _get: function(inst, name) {
            return (inst.options[name] != null ?
			inst.options[name] : $.countdown._defaults[name]);
        },

        /* A time may be specified as an exact value or a relative one.
        @param  setting      (string or number or Date) - the date/time value
        as a relative or absolute value
        @param  defaultTime  (Date) the date/time to use if no other is supplied
        @return  (Date) the corresponding date/time */
        _determineTime: function(setting, defaultTime) {
            var offsetNumeric = function(offset) { // e.g. +300, -2
                var time = new Date();
                time.setTime(time.getTime() + offset * 1000);
                return time;
            };
            var offsetString = function(offset) { // e.g. '+2d', '-4w', '+3h +30m'
                offset = offset.toLowerCase();
                var time = new Date();
                var year = time.getFullYear();
                var month = time.getMonth();
                var day = time.getDate();
                var hour = time.getHours();
                var minute = time.getMinutes();
                var second = time.getSeconds();
                var pattern = /([+-]?[0-9]+)\s*(s|m|h|d|w|o|y)?/g;
                var matches = pattern.exec(offset);
                while (matches) {
                    switch (matches[2] || 's') {
                        case 's': second += parseInt(matches[1], 10); break;
                        case 'm': minute += parseInt(matches[1], 10); break;
                        case 'h': hour += parseInt(matches[1], 10); break;
                        case 'd': day += parseInt(matches[1], 10); break;
                        case 'w': day += parseInt(matches[1], 10) * 7; break;
                        case 'o':
                            month += parseInt(matches[1], 10);
                            day = Math.min(day, $.countdown._getDaysInMonth(year, month));
                            break;
                        case 'y':
                            year += parseInt(matches[1], 10);
                            day = Math.min(day, $.countdown._getDaysInMonth(year, month));
                            break;
                    }
                    matches = pattern.exec(offset);
                }
                return new Date(year, month, day, hour, minute, second, 0);
            };
            var time = (setting == null ? defaultTime :
			(typeof setting == 'string' ? offsetString(setting) :
			(typeof setting == 'number' ? offsetNumeric(setting) : setting)));
            if (time) time.setMilliseconds(0);
            return time;
        },

        /* Determine the number of days in a month.
        @param  year   (number) the year
        @param  month  (number) the month
        @return  (number) the days in that month */
        _getDaysInMonth: function(year, month) {
            return 32 - new Date(year, month, 32).getDate();
        },

        /* Determine which set of labels should be used for an amount.
        @param  num  (number) the amount to be displayed
        @return  (number) the set of labels to be used for this amount */
        _normalLabels: function(num) {
            return num;
        },

        /* Generate the HTML to display the countdown widget.
        @param  inst  (object) the current settings for this instance
        @return  (string) the new HTML for the countdown display */
        _generateHTML: function(inst) {
            // Determine what to show
            var significant = this._get(inst, 'significant');
            inst._periods = (inst._hold ? inst._periods :
			this._calculatePeriods(inst, inst._show, significant, new Date()));
            // Show all 'asNeeded' after first non-zero value
            var shownNonZero = false;
            var showCount = 0;
            var sigCount = significant;
            var show = $.extend({}, inst._show);
            for (var period = Y; period <= S; period++) {
                shownNonZero |= (inst._show[period] == '?' && inst._periods[period] > 0);
                show[period] = (inst._show[period] == '?' && !shownNonZero ? null : inst._show[period]);
                showCount += (show[period] ? 1 : 0);
                sigCount -= (inst._periods[period] > 0 ? 1 : 0);
            }
            var showSignificant = [false, false, false, false, false, false, false];
            for (var period = S; period >= Y; period--) { // Determine significant periods
                if (inst._show[period]) {
                    if (inst._periods[period]) {
                        showSignificant[period] = true;
                    }
                    else {
                        showSignificant[period] = sigCount > 0;
                        sigCount--;
                    }
                }
            }
            var compact = this._get(inst, 'compact');
            var layout = this._get(inst, 'layout');
            var labels = (compact ? this._get(inst, 'compactLabels') : this._get(inst, 'labels'));
            var whichLabels = this._get(inst, 'whichLabels') || this._normalLabels;
            var timeSeparator = this._get(inst, 'timeSeparator');
            var description = this._get(inst, 'description') || '';
            var showCompact = function(period) {
                var labelsNum = $.countdown._get(inst,
				'compactLabels' + whichLabels(inst._periods[period]));
                return (show[period] ? inst._periods[period] +
				(labelsNum ? labelsNum[period] : labels[period]) + ' ' : '');
            };
            var showFull = function(period) {
                var labelsNum = $.countdown._get(inst, 'labels' + whichLabels(inst._periods[period]));
                return ((!significant && show[period]) || (significant && showSignificant[period]) ?
				'&nbsp;<span class="countdown_section">&nbsp;<span class="countdown_amount">' +
				inst._periods[period] + '</span>&nbsp;' +
				(labelsNum ? labelsNum[period] : labels[period]) + '</span>' : '');
            };
            return (layout ? this._buildLayout(inst, show, layout, compact, significant, showSignificant) :
			((compact ? // Compact version
			'<span class="countdown_row countdown_amount' +
			(inst._hold ? ' countdown_holding' : '') + '">' +
			showCompact(Y) + showCompact(O) + showCompact(W) + showCompact(D) +
			(show[H] ? this._minDigits(inst._periods[H], 2) : '') +
			(show[M] ? (show[H] ? timeSeparator : '') +
			this._minDigits(inst._periods[M], 2) : '') +
			(show[S] ? (show[H] || show[M] ? timeSeparator : '') +
			this._minDigits(inst._periods[S], 2) : '') :
            // Full version
			'<span class="countdown_row countdown_show' + (significant || showCount) +
			(inst._hold ? ' countdown_holding' : '') + '">' + "Time remaining till next sale: " +
			showFull(Y) + showFull(O) + showFull(W) + showFull(D) +
			showFull(H) + showFull(M) + showFull(S)) + '</span>' +
			(description ? '<span class="countdown_row countdown_descr">' + description + '</span>' : '')));
        },

        /* Construct a custom layout.
        @param  inst             (object) the current settings for this instance
        @param  show             (string[7]) flags indicating which periods are requested
        @param  layout           (string) the customised layout
        @param  compact          (boolean) true if using compact labels
        @param  significant      (number) the number of periods with values to show, zero for all
        @param  showSignificant  (boolean[7]) other periods to show for significance
        @return  (string) the custom HTML */
        _buildLayout: function(inst, show, layout, compact, significant, showSignificant) {
            var labels = this._get(inst, (compact ? 'compactLabels' : 'labels'));
            var whichLabels = this._get(inst, 'whichLabels') || this._normalLabels;
            var labelFor = function(index) {
                return ($.countdown._get(inst,
				(compact ? 'compactLabels' : 'labels') + whichLabels(inst._periods[index])) ||
				labels)[index];
            };
            var digit = function(value, position) {
                return Math.floor(value / position) % 10;
            };
            var subs = { desc: this._get(inst, 'description'), sep: this._get(inst, 'timeSeparator'),
                yl: labelFor(Y), yn: inst._periods[Y], ynn: this._minDigits(inst._periods[Y], 2),
                ynnn: this._minDigits(inst._periods[Y], 3), y1: digit(inst._periods[Y], 1),
                y10: digit(inst._periods[Y], 10), y100: digit(inst._periods[Y], 100),
                y1000: digit(inst._periods[Y], 1000),
                ol: labelFor(O), on: inst._periods[O], onn: this._minDigits(inst._periods[O], 2),
                onnn: this._minDigits(inst._periods[O], 3), o1: digit(inst._periods[O], 1),
                o10: digit(inst._periods[O], 10), o100: digit(inst._periods[O], 100),
                o1000: digit(inst._periods[O], 1000),
                wl: labelFor(W), wn: inst._periods[W], wnn: this._minDigits(inst._periods[W], 2),
                wnnn: this._minDigits(inst._periods[W], 3), w1: digit(inst._periods[W], 1),
                w10: digit(inst._periods[W], 10), w100: digit(inst._periods[W], 100),
                w1000: digit(inst._periods[W], 1000),
                dl: labelFor(D), dn: inst._periods[D], dnn: this._minDigits(inst._periods[D], 2),
                dnnn: this._minDigits(inst._periods[D], 3), d1: digit(inst._periods[D], 1),
                d10: digit(inst._periods[D], 10), d100: digit(inst._periods[D], 100),
                d1000: digit(inst._periods[D], 1000),
                hl: labelFor(H), hn: inst._periods[H], hnn: this._minDigits(inst._periods[H], 2),
                hnnn: this._minDigits(inst._periods[H], 3), h1: digit(inst._periods[H], 1),
                h10: digit(inst._periods[H], 10), h100: digit(inst._periods[H], 100),
                h1000: digit(inst._periods[H], 1000),
                ml: labelFor(M), mn: inst._periods[M], mnn: this._minDigits(inst._periods[M], 2),
                mnnn: this._minDigits(inst._periods[M], 3), m1: digit(inst._periods[M], 1),
                m10: digit(inst._periods[M], 10), m100: digit(inst._periods[M], 100),
                m1000: digit(inst._periods[M], 1000),
                sl: labelFor(S), sn: inst._periods[S], snn: this._minDigits(inst._periods[S], 2),
                snnn: this._minDigits(inst._periods[S], 3), s1: digit(inst._periods[S], 1),
                s10: digit(inst._periods[S], 10), s100: digit(inst._periods[S], 100),
                s1000: digit(inst._periods[S], 1000)
            };
            var html = layout;
            // Replace period containers: {p<}...{p>}
            for (var i = Y; i <= S; i++) {
                var period = 'yowdhms'.charAt(i);
                var re = new RegExp('\\{' + period + '<\\}(.*)\\{' + period + '>\\}', 'g');
                html = html.replace(re, ((!significant && show[i]) ||
				(significant && showSignificant[i]) ? '$1' : ''));
            }
            // Replace period values: {pn}
            $.each(subs, function(n, v) {
                var re = new RegExp('\\{' + n + '\\}', 'g');
                html = html.replace(re, v);
            });
            return html;
        },

        /* Ensure a numeric value has at least n digits for display.
        @param  value  (number) the value to display
        @param  len    (number) the minimum length
        @return  (string) the display text */
        _minDigits: function(value, len) {
            value = '' + value;
            if (value.length >= len) {
                return value;
            }
            value = '0000000000' + value;
            return value.substr(value.length - len);
        },

        /* Translate the format into flags for each period.
        @param  inst  (object) the current settings for this instance
        @return  (string[7]) flags indicating which periods are requested (?) or
        required (!) by year, month, week, day, hour, minute, second */
        _determineShow: function(inst) {
            var format = this._get(inst, 'format');
            var show = [];
            show[Y] = (format.match('y') ? '?' : (format.match('Y') ? '!' : null));
            show[O] = (format.match('o') ? '?' : (format.match('O') ? '!' : null));
            show[W] = (format.match('w') ? '?' : (format.match('W') ? '!' : null));
            show[D] = (format.match('d') ? '?' : (format.match('D') ? '!' : null));
            show[H] = (format.match('h') ? '?' : (format.match('H') ? '!' : null));
            show[M] = (format.match('m') ? '?' : (format.match('M') ? '!' : null));
            show[S] = (format.match('s') ? '?' : (format.match('S') ? '!' : null));
            return show;
        },

        /* Calculate the requested periods between now and the target time.
        @param  inst         (object) the current settings for this instance
        @param  show         (string[7]) flags indicating which periods are requested/required
        @param  significant  (number) the number of periods with values to show, zero for all
        @param  now          (Date) the current date and time
        @return  (number[7]) the current time periods (always positive)
        by year, month, week, day, hour, minute, second */
        _calculatePeriods: function(inst, show, significant, now) {
            // Find endpoints
            inst._now = now;
            inst._now.setMilliseconds(0);
            var until = new Date(inst._now.getTime());
            if (inst._since) {
                if (now.getTime() < inst._since.getTime()) {
                    inst._now = now = until;
                }
                else {
                    now = inst._since;
                }
            }
            else {
                until.setTime(inst._until.getTime());
                if (now.getTime() > inst._until.getTime()) {
                    inst._now = now = until;
                }
            }
            // Calculate differences by period
            var periods = [0, 0, 0, 0, 0, 0, 0];
            if (show[Y] || show[O]) {
                // Treat end of months as the same
                var lastNow = $.countdown._getDaysInMonth(now.getFullYear(), now.getMonth());
                var lastUntil = $.countdown._getDaysInMonth(until.getFullYear(), until.getMonth());
                var sameDay = (until.getDate() == now.getDate() ||
				(until.getDate() >= Math.min(lastNow, lastUntil) &&
				now.getDate() >= Math.min(lastNow, lastUntil)));
                var getSecs = function(date) {
                    return (date.getHours() * 60 + date.getMinutes()) * 60 + date.getSeconds();
                };
                var months = Math.max(0,
				(until.getFullYear() - now.getFullYear()) * 12 + until.getMonth() - now.getMonth() +
				((until.getDate() < now.getDate() && !sameDay) ||
				(sameDay && getSecs(until) < getSecs(now)) ? -1 : 0));
                periods[Y] = (show[Y] ? Math.floor(months / 12) : 0);
                periods[O] = (show[O] ? months - periods[Y] * 12 : 0);
                // Adjust for months difference and end of month if necessary
                now = new Date(now.getTime());
                var wasLastDay = (now.getDate() == lastNow);
                var lastDay = $.countdown._getDaysInMonth(now.getFullYear() + periods[Y],
				now.getMonth() + periods[O]);
                if (now.getDate() > lastDay) {
                    now.setDate(lastDay);
                }
                now.setFullYear(now.getFullYear() + periods[Y]);
                now.setMonth(now.getMonth() + periods[O]);
                if (wasLastDay) {
                    now.setDate(lastDay);
                }
            }
            var diff = Math.floor((until.getTime() - now.getTime()) / 1000);
            var extractPeriod = function(period, numSecs) {
                periods[period] = (show[period] ? Math.floor(diff / numSecs) : 0);
                diff -= periods[period] * numSecs;
            };
            extractPeriod(W, 604800);
            extractPeriod(D, 86400);
            extractPeriod(H, 3600);
            extractPeriod(M, 60);
            extractPeriod(S, 1);
            if (diff > 0 && !inst._since) { // Round up if left overs
                var multiplier = [1, 12, 4.3482, 7, 24, 60, 60];
                var lastShown = S;
                var max = 1;
                for (var period = S; period >= Y; period--) {
                    if (show[period]) {
                        if (periods[lastShown] >= max) {
                            periods[lastShown] = 0;
                            diff = 1;
                        }
                        if (diff > 0) {
                            periods[period]++;
                            diff = 0;
                            lastShown = period;
                            max = 1;
                        }
                    }
                    max *= multiplier[period];
                }
            }
            if (significant) { // Zero out insignificant periods
                for (var period = Y; period <= S; period++) {
                    if (significant && periods[period]) {
                        significant--;
                    }
                    else if (!significant) {
                        periods[period] = 0;
                    }
                }
            }
            return periods;
        }
    });

    /* jQuery extend now ignores nulls!
    @param  target  (object) the object to update
    @param  props   (object) the new settings
    @return  (object) the updated object */
    function extendRemove(target, props) {
        $.extend(target, props);
        for (var name in props) {
            if (props[name] == null) {
                target[name] = null;
            }
        }
        return target;
    }

    /* Process the countdown functionality for a jQuery selection.
    @param  command  (string) the command to run (optional, default 'attach')
    @param  options  (object) the new settings to use for these countdown instances
    @return  (jQuery) for chaining further calls */
    $.fn.countdown = function(options) {
        var otherArgs = Array.prototype.slice.call(arguments, 1);
        if (options == 'getTimes' || options == 'settings') {
            return $.countdown['_' + options + 'Countdown'].
			apply($.countdown, [this[0]].concat(otherArgs));
        }
        return this.each(function() {
            if (typeof options == 'string') {
                $.countdown['_' + options + 'Countdown'].apply($.countdown, [this].concat(otherArgs));
            }
            else {
                $.countdown._attachCountdown(this, options);
            }
        });
    };

    /* Initialise the countdown functionality. */
    $.countdown = new Countdown(); // singleton instance

})(jQuery);


