/* FILE: templates/ja_sargas/scripts/ja.script.js*/
var currentFontSize = 4;

function revertStyles(fontsize){
    currentFontSize = fontsize;
    changeFontSize(0);
}

function changeFontSize(sizeDifference){
    //get css font size
    var rule = getRuleByName("body.fs" + (currentFontSize + sizeDifference));
    if (rule){
        document.body.style.fontSize = rule.style.fontSize;
        currentFontSize = currentFontSize + sizeDifference;
        createCookie("FontSize", currentFontSize, 365);
    }
    return;

};

function getRuleByName(ruleName){
    for (i=0; i<document.styleSheets.length; i++){
        var style = document.styleSheets[i];
        var rules = style.cssRules?style.cssRules:style.rules;
        if (rules){
            for (j = 0; j<rules.length; j++){
                if (rules[j].selectorText.trim().toUpperCase() == ruleName.trim().toUpperCase()){
                    return rules[j];
                }
            }
        }
    }
    return null;
}

function setActiveStyleSheet(title) {

    createCookie("ColorCSS", title, 365);
    window.location.reload();
    return;
    /*
    var i, a, main, arr;
    arr = document.getElementsByTagName("link");
    for(i=0; (a = arr[i]); i++) {
    var ltitle = a.getAttribute("title");
    if(a.getAttribute("rel").indexOf("style") != -1 && ltitle) {
    a.disabled = true;
    if(ltitle == title) a.disabled = false;
    }
    }
    createCookie("ColorCSS", title, 365);
    */
}

function createCookie(name,value,days) {
    if (days) {
        var date = new Date();
        date.setTime(date.getTime()+(days*24*60*60*1000));
        var expires = "; expires="+date.toGMTString();
    }
    else expires = "";
    document.cookie = name+"="+value+expires+"; path=/";
}

function setScreenType(screentype){
    /*
    bclass = document.body.className.trim();
    if (bclass.indexOf(' ') > 0){
    bclass = bclass.replace(/^\w+/,screentype);
    }else{
    bclass = screentype + ' ' + bclass;
    }

    document.body.className = bclass;
    */
    createCookie("ScreenType", screentype, 365);
    window.location.reload();
    return;
}

String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ""); };

function changeToolHilite(oldtool, newtool) {
    if (oldtool != newtool) {
        if (oldtool) {
            oldtool.src = oldtool.src.replace(/-hilite/,'');
        }
        newtool.src = newtool.src.replace(/.gif$/,'-hilite.gif');
    }
}

//addEvent - attach a function to an event
function addEvent(obj, evType, fn){
    if (obj.addEventListener){
        obj.addEventListener(evType, fn, false);
        return true;
    } else if (obj.attachEvent){
        var r = obj.attachEvent("on"+evType, fn);
        return r;
    } else {
        return false;
    }
}

/*
Global "swap" holder
Use value, null, if no layer initially visible
*/
var currDivId = "show_the_hotel";

function togLayer(id)
{
    if(currDivId) setDisplay(currDivId, "none");
    if(id)setDisplay(id, "block");
    currDivId = id;
}

function setDisplay(id,value)
{
    var elm = document.getElementById(id);
    elm.style.display = value;
}

function MM_jumpMenu(targ,selObj,restore){ //v3.0
    eval(targ+".location='"+selObj.options[selObj.selectedIndex].value+"'");
    if (restore) selObj.selectedIndex=0;
}

/*
Global "swap" holder
Use value, null, if no layer initially visible
*/
var currDivIdSpecOff = "eastern_cape";

function togLayerSpecOff(id)
{
    if(currDivIdSpecOff) setDisplay(currDivIdSpecOff, "none");
    if(id)setDisplay(id, "block");
    currDivIdSpecOff = id;
}

function setDisplay(id,value)
{
    var elm = document.getElementById(id);
    if(elm) elm.style.display = value;
}


// var iStartTime = new Date().valueOf();
function popup(sURL) {
    var iWidth = 640;
    var iHeight = 480;
    window.open(sURL, 'protea_popup', "left=50px, top=50px, width=" + iWidth + "px,height=" + iHeight + "px, resizable=1, status=0, address=0, scrollbars=1");
}
/* FILE: templates/ja_sargas/scripts/opacity.js*/
// Browser Detect Lite  v2.1
// http://www.dithered.com/javascript/browser_detect/index.html
// modified by Chris Nott (chris@NOSPAMdithered.com - remove NOSPAM)
//
// modified by Michael Lovitt to include OmniWeb and Dreamcast

function BrowserDetectLite() {
	var ua = navigator.userAgent.toLowerCase(); 
	this.ua = ua;

	// browser name
	this.isGecko     = (ua.indexOf('gecko') != -1);
	this.isMozilla   = (this.isGecko && ua.indexOf("gecko/") + 14 == ua.length);
	this.isNS        = ( (this.isGecko) ? (ua.indexOf('netscape') != -1) : ( (ua.indexOf('mozilla') != -1) && (ua.indexOf('spoofer') == -1) && (ua.indexOf('compatible') == -1) && (ua.indexOf('opera') == -1) && (ua.indexOf('webtv') == -1) && (ua.indexOf('hotjava') == -1) ) );
	this.isIE        = ( (ua.indexOf("msie") != -1) && (ua.indexOf("opera") == -1) && (ua.indexOf("webtv") == -1) ); 
	this.isOpera     = (ua.indexOf("opera") != -1); 
	this.isKonqueror = (ua.indexOf("konqueror") != -1); 
	this.isIcab      = (ua.indexOf("icab") != -1); 
	this.isAol       = (ua.indexOf("aol") != -1); 
	this.isWebtv     = (ua.indexOf("webtv") != -1); 
	this.isOmniweb   = (ua.indexOf("omniweb") != -1);
	this.isDreamcast   = (ua.indexOf("dreamcast") != -1);
	
	// spoofing and compatible browsers
	this.isIECompatible = ( (ua.indexOf("msie") != -1) && !this.isIE);
	this.isNSCompatible = ( (ua.indexOf("mozilla") != -1) && !this.isNS && !this.isMozilla);
	
	// browser version
	this.versionMinor = parseFloat(navigator.appVersion); 
	
	// correct version number for NS6+ 
	if (this.isNS && this.isGecko) {
		this.versionMinor = parseFloat( ua.substring( ua.lastIndexOf('/') + 1 ) );
	}
	
	// correct version number for IE4+ 
	else if (this.isIE && this.versionMinor >= 4) {
		this.versionMinor = parseFloat( ua.substring( ua.indexOf('msie ') + 5 ) );
	}
	
	// correct version number for Opera 
	else if (this.isOpera) {
		if (ua.indexOf('opera/') != -1) {
			this.versionMinor = parseFloat( ua.substring( ua.indexOf('opera/') + 6 ) );
		}
		else {
			this.versionMinor = parseFloat( ua.substring( ua.indexOf('opera ') + 6 ) );
		}
	}
	
	// correct version number for Konqueror
	else if (this.isKonqueror) {
		this.versionMinor = parseFloat( ua.substring( ua.indexOf('konqueror/') + 10 ) );
	}
	
	// correct version number for iCab 
	else if (this.isIcab) {
		if (ua.indexOf('icab/') != -1) {
			this.versionMinor = parseFloat( ua.substring( ua.indexOf('icab/') + 6 ) );
		}
		else {
			this.versionMinor = parseFloat( ua.substring( ua.indexOf('icab ') + 6 ) );
		}
	}
	
	// correct version number for WebTV
	else if (this.isWebtv) {
		this.versionMinor = parseFloat( ua.substring( ua.indexOf('webtv/') + 6 ) );
	}
	
	this.versionMajor = parseInt(this.versionMinor); 
	this.geckoVersion = ( (this.isGecko) ? ua.substring( (ua.lastIndexOf('gecko/') + 6), (ua.lastIndexOf('gecko/') + 14) ) : -1 );
	
	// platform
	this.isWin   = (ua.indexOf('win') != -1);
	this.isWin32 = (this.isWin && ( ua.indexOf('95') != -1 || ua.indexOf('98') != -1 || ua.indexOf('nt') != -1 || ua.indexOf('win32') != -1 || ua.indexOf('32bit') != -1) );
	this.isMac   = (ua.indexOf('mac') != -1);
	this.isUnix  = (ua.indexOf('unix') != -1 || ua.indexOf('linux') != -1 || ua.indexOf('sunos') != -1 || ua.indexOf('bsd') != -1 || ua.indexOf('x11') != -1)
	
	// specific browser shortcuts
	this.isNS4x = (this.isNS && this.versionMajor == 4);
	this.isNS40x = (this.isNS4x && this.versionMinor < 4.5);
	this.isNS47x = (this.isNS4x && this.versionMinor >= 4.7);
	this.isNS4up = (this.isNS && this.versionMinor >= 4);
	this.isNS6x = (this.isNS && this.versionMajor == 6);
	this.isNS6up = (this.isNS && this.versionMajor >= 6);
	
	this.isIE4x = (this.isIE && this.versionMajor == 4);
	this.isIE4up = (this.isIE && this.versionMajor >= 4);
	this.isIE5x = (this.isIE && this.versionMajor == 5);
	this.isIE55 = (this.isIE && this.versionMinor == 5.5);
	this.isIE5up = (this.isIE && this.versionMajor >= 5);
	this.isIE6x = (this.isIE && this.versionMajor == 6);
	this.isIE6up = (this.isIE && this.versionMajor >= 6);
	
	this.isIE4xMac = (this.isIE4x && this.isMac);
}
var browser = new BrowserDetectLite();

// if IE5.5+ on Win32, then display PNGs with AlphaImageLoader
if ((browser.isIE55 || browser.isIE6up) && browser.isWin32) {
	var pngAlpha = true;
// else, if the browser can display PNGs normally, then do that
} else if ((browser.isGecko) ||
(browser.isIE5up && browser.isMac) ||
(browser.isOpera && browser.isWin && browser.versionMajor >= 6) ||
(browser.isOpera && browser.isUnix && browser.versionMajor >= 6) ||
(browser.isOpera && browser.isMac && browser.versionMajor >= 5) ||
(browser.isOmniweb && browser.versionMinor >= 3.1) ||
(browser.isIcab && browser.versionMinor >= 1.9) ||
(browser.isWebtv) ||
(browser.isDreamcast)) {
	var pngNormal = true;
}

//---------------------------------------------------------------
// Opacity Displayer, Version 1.0
// Copyright Michael Lovitt, 6/2002.
// Distribute freely, but please leave this notice intact.
//---------------------------------------------------------------

//---------------------------------------------------------------
// OPACITY OBJECT
//
// Instantiates the object, defines the properties and methods.
function OpacityObject(divId, strPath) {
	this.id = divId;
	this.path = strPath;
	if (ns){
		if (browserVersion>=5) {
			this.layerObject = document.getElementById(divId).style;
		} else { 
			this.layerObject = eval("document."+divId);
		}
	} else {
		this.layerObject = document.getElementById(divId).style;
	}
	this.setBackground = od_object_setBackground;
}
// Uses AlphaImageLoader filter, or the css background property,
// as appropriate, to apply a PNG or GIF as the background of the layerObject.
// La til background-repeat
function od_object_setBackground() {	
	if (pngAlpha) {
		this.layerObject.zoom = "1";
		this.layerObject.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled = true, src='"+this.path+".png', sizingMethod='scale')";
		//this.layerObject.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=70)";
	} else if (pngNormal) {
		this.layerObject.backgroundImage = 'url('+this.path+'.png)';
		this.layerObject.backgroundRepeat = 'repeat';
	} else {
		this.layerObject.backgroundImage = 'url('+this.path+'.gif)';
		this.layerObject.backgroundRepeat = 'repeat';
	}
}
//---------------------------------------------------------------

//---------------------------------------------------------------
// OPACITY DISPLAY FUNCTION
// Outputs the image as a div with the AlphaImageLoader, or with
// a standard image tag.
function od_displayImage(strId, strPath, intWidth, intHeight, strClass, strAlt) {	
	if (pngAlpha) {
		document.write('<div style="height:'+intHeight+'px;width:'+intWidth+'px;filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\''+strPath+'.png\', sizingMethod=\'scale\')" id="'+strId+'" class="'+strClass+'"></div>');
	} else if (pngNormal) {
		document.write('<img src="'+strPath+'.png" width="'+intWidth+'" height="'+intHeight+'" name="'+strId+'" border="0" class="'+strClass+'" alt="'+strAlt+'" />');
	} else {
		document.write('<img src="'+strPath+'.gif" width="'+intWidth+'" height="'+intHeight+'" name="'+strId+'" border="0" class="'+strClass+'" alt="'+strAlt+'" />');
	}
}
//---------------------------------------------------------------

//---------------------------------------------------------------
// global variables

// if IE5.5+ on win32, then display PNGs with AlphaImageLoader
if ((browser.isIE55 || browser.isIE6up) && browser.isWin32) {
	var pngAlpha = true;
	var strExt = ".png";
// else, if the browser can display PNGs normally, then do that. that list includes:
	//     -Gecko Engine: Netscape 6 or Mozilla, Mac or PC
	//     -IE5+ Mac (OpacityObject applies the background image at 100% opacity)
	//     -Opera 6+ PC
	//     -Opera 5+ Mac (Doesn't support dynamically-set background images)
	//     -Opera 6+ Linux 
	//     -Omniweb 3.1+ 
	//     -Icab 1.9+ 
	//     -WebTV 
	//     -Sega Dreamcast
} else if ((browser.isGecko) || (browser.isIE5up && browser.isMac) || (browser.isOpera && browser.isWin && browser.versionMajor >= 6) || (browser.isOpera && browser.isUnix && browser.versionMajor >= 6) || (browser.isOpera && browser.isMac && browser.versionMajor >= 5) || (browser.isOmniweb && browser.versionMinor >= 3.1) || (browser.isIcab && browser.versionMinor >= 1.9) || (browser.isWebtv) || (browser.isDreamcast)) {
	var pngNormal = true;
	var strExt = ".png";
	// otherwise, we use plain old GIFs
} else {
	var strExt = ".gif";
}

var ns = (document.all)?false:true;
var browserVersion = parseFloat(navigator.appVersion );
//---------------------------------------------------------------
/* FILE: modules/mod_scripts/new-javascript-general.js*/
function addCheckingAvailabilityToPage(){
	var progressDiv = getElement('progressDiv');
	var msg = "";
	//msg += '<h1>Checking Availability ...</h1>';
    //msg += '    <p>Please be patient, we are searching for the best possible rate per day.</p>';
	//msg += '    <p class="progressDivImg"><img src="/images/loading.gif" width="161" height="36" title="Please be patient, we are searching for the best possible rate per day." alt="Please be patient, we are searching for the best possible rate per day." /></p>';
	
	
	
	msg += '<h1><span id="availCheckHeading">Checking Availability ...</span></h1>';
    msg += '<p><span id="availCheckWording">Please be patient as we search for the BEST AVAILABLE RATE per day.</span></p>';
	
    msg += '<div id="flashcontent">';
    msg += '    <p class="progressDivImg"><img src="/images/loading.gif" width="161" height="36" title="Searching..." alt="Searching..." /></p>';
	msg += '</div>';
    
	progressDiv.innerHTML = msg;
	
   	var so = new SWFObject("/flash_content/bag.swf", "mymovie", "220", "200", "8", "#fff");
	so.write("flashcontent");
    
	
}

function getElement(id) {
	return document.getElementById(id);
}

function show_hide_credit_card(){
	var creditCardTableElem = getElement('credit_card_table');
	var voucherElem = getElement('voucher_table');
	var cvvElem = getElement('cvv_div');
	
	if(creditCardTableElem.style.display != "none"){
		creditCardTableElem.style.display = "none";
		cvvElem.style.visibility = "hidden";
		voucherElem.style.display = "block";
	}else{
		creditCardTableElem.style.display = "block";
		cvvElem.style.visibility = "visible";
		voucherElem.style.display = "none";
	}
	
}

function getElemValue(id){
	var elem;
	var ret_val;
	var not_found_msg = "!!failed!!";
	elem = getElement(id);
	
	if(elem.options){
		ret_val = elem.options[elem.selectedIndex].value;	
	}else{
		ret_val = elem.value;
	}
	return ret_val;
}

function confirmSend(json){
	if (json == null){
		return false;
	}
	else{
		return true;
	}
}

function sendRequest(url, func, append) {
	
	var client = new XmlHttp(func);
	
	var urls = url.split("?");
	
	client.open('POST', urls[0] + "?" + append, true);
	//prompt(urls[0] + "?" + append  + urls[1],urls[0] + "?" + append + urls[1]);
	client.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	client.send(urls[1]);
}

function deActivateButtons(){
	var elems = document.getElementsByName('disabledGroup[]');
	for(var i = 0; i < elems.length; i++) {
		elems[i].style.display = "none";
	}
	
	var elems = document.getElementsByName('replaceDisabledGroup[]');
	for(var i = 0; i < elems.length; i++) {
		elems[i].style.display = "block";
	}
}

function activateButtons(responseObject,responseText){
	var bookingStatus;
	
	
	if(responseText != "" && responseText != "Room Added"){
		alert(responseText);
	}
	
	if(responseText == "Room unavailable"){
		bookingStatus = false;
		reloadSearch();
	}else if(responseText == "Room Added"){
		bookingStatus = true;
		//the 10minute eres counter
		refreshCountdownDisplay(10 * 60 * 1000);
		update_suitcase_count("add");
	}
	
	var elems = document.getElementsByName('disabledGroup[]');
	for(var i = 0; i < elems.length; i++) {
		elems[i].style.display = "inline";
	}

	var elems = document.getElementsByName('replaceDisabledGroup[]');
	for(var i = 0; i < elems.length; i++) {
		elems[i].style.display = "none";
	}

	return bookingStatus;
}

function reloadSearch(){
	showProgressBar();
	
	//get area info
	var country = getElemValue('selectCountries');
	var region = getElemValue('selectRegions');
	var city = getElemValue('selectCities');
	var hotel = getElemValue('selectHotels');
	
	//get dates
	var checkin = getElemValue('checkin_date');
	var checkout = getElemValue('checkout_date');
	var nights = getElemValue('nightsNumber');
	//get num people
	var adults = getElemValue('searchNumAdults');
	var kids = getElemValue('searchNumKids');
	var rooms = getElemValue('searchNumRooms');
	
	
	var url = "search-result.html?useGet=true" + "&selectCountries=" + country + "&selectRegions=" + region + "&selectCities=" + city + "&selectHotels=" + hotel + "&checkin_date=" + checkin + "&checkout_date=" + checkout + "&nightsNumber=" + nights + "&selectAdults=" + adults + "&selectKids=" + kids + "&selectRooms=" + rooms;
//alert("country:"+country+"\nregion:"+region+"\ncity:"+city+"\nhotel:"+hotel+"\nin:"+checkin+"\nout:"+checkout);
	
	//go to the page that
	location = url;
}

function XmlHttp(func) {
	var xmlhttp = null;
	if (window.XMLHttpRequest) {
		xmlhttp = new XMLHttpRequest();
		if ( typeof xmlhttp.overrideMimeType != 'undefined') {
			xmlhttp.overrideMimeType('text/plain');
		}
	} else if (window.ActiveXObject) {
		xmlhttp = new ActiveXObject('Microsoft.XMLHTTP');
	} else {
		alert('Your browser has no JSON support. Please upgrade your browser.');

		return false;
	}

	xmlhttp.onreadystatechange = function() {

		if(xmlhttp.readyState == 4) {
			var response = null;
			if(xmlhttp.status == 200) {
				response = xmlhttp.responseText;
				//alert(response);
			}
			var object = null;
			if(response != null && response != '') {
				try {
					object = eval('(' + response + ')');
				} catch(ex) {
					// object remains null.
				}
			}
			func(object,response);
		}
	}

	return xmlhttp;
}

function hideIfAvailable(id){
	var hide = getElement(id);
	if(hide) hide.style.display = "none";
}

function showIfAvailable(id){
	var show = getElement(id);
	if(show) show.style.display = "block";
}

function showProgressBar(text,heading){
	if(text == null || text == ""){
		text = "Please be patient as we search for the BEST AVAILABLE RATE per day";
	}
	
	if(heading == null || heading == ""){
		heading = "Checking Availability ...";
	}
	
	
	var availWording = getElement('availCheckWording');
	availWording.innerHTML = text;
	
	var availHeading = getElement('availCheckHeading');
	availHeading.innerHTML = heading;
	
	hideIfAvailable('ja-botnavwrap');
	hideIfAvailable('ja-botslwrap');
	hideIfAvailable('ja-contentwrap');
	hideIfAvailable('ja-content');
	hideIfAvailable('ja-footerwrap');			
	hideIfAvailable('ja-leftcol');
	hideIfAvailable('ja-rightcol');
	
	hideIfAvailable('additional_facilities');
	hideIfAvailable('additional_hotel_info');
	hideIfAvailable('bookingEngine');
	hideIfAvailable('bookingEngineVertical');
	hideIfAvailable('div_special_description');
	
	hideIfAvailable('hotel-introText');
	hideIfAvailable('hotel-searchBox');
	hideIfAvailable('hotel-searchImage');
	
	hideIfAvailable('searchAgainHeadingSpan');	
	hideIfAvailable('selectRegions');
	hideIfAvailable('threeBrand');
		
	showIfAvailable('progressDiv');
}

function hideProgressBar(responseObject,responseText){	
	showIfAvailable('ja-botnavwrap');
	showIfAvailable('ja-botslwrap');
	showIfAvailable('ja-contentwrap');
	showIfAvailable('ja-content');
	showIfAvailable('ja-footerwrap');			
	showIfAvailable('ja-leftcol');
	showIfAvailable('ja-rightcol');
	
	showIfAvailable('additional_facilities');
	showIfAvailable('additional_hotel_info');
	showIfAvailable('bookingEngine');
	showIfAvailable('bookingEngineVertical');
	showIfAvailable('div_special_description');
	
	showIfAvailable('hotel-introText');
	showIfAvailable('hotel-searchBox');
	showIfAvailable('hotel-searchImage');
	
	showIfAvailable('searchAgainHeadingSpan');
	showIfAvailable('selectRegions');
	showIfAvailable('threeBrand');
		
	hideIfAvailable('progressDiv');
	
	var bookingStatus;
	
	
	if(responseText != "" && responseText != "Room Added" && responseText != null){
		alert(responseText);
	}
	
	if(responseText == "Room unavailable"){
		bookingStatus = false;
		reloadSearch();
	}else if(responseText == "Room Added"){
		bookingStatus = true;
		//the 10minute eres counter
		refreshCountdownDisplay(10 * 60 * 1000);
		update_suitcase_count("add");
	}
	
	return bookingStatus;
}


/* FILE: modules/mod_scripts/new-javascript-suitcase.js*/
var totalPrice = 0;

//**IN USE**//
function URLEncode (clearString) {
	var output = '';
	var x = 0;
	clearString = clearString.toString();
	var regex = /(^[a-zA-Z0-9_.]*)/;
	while (x < clearString.length) {
		var match = regex.exec(clearString.substr(x));
		if (match != null && match.length > 1 && match[1] != '') {
			output += match[1];
			x += match[1].length;
		} else {
			if (clearString[x] == ' ')
			output += '+';
			else {
				var charCode = clearString.charCodeAt(x);
				var hexVal = charCode.toString(16);
				output += '%' + hexVal.toUpperCase();
			}
			x++;
		}
	}
	return output;
}


//**IN USE**//
function toBooking(responseObject,responseText) {
	//var btn = document.getElementById('btnBookNow');
	var form = document.getElementById('form1');
	if(responseText != "" && responseText != "Room Added"){
		//activateButtons(responseObject,responseText);
		hideProgressBar(responseObject,responseText);
	}else{
		form.submit();
	}
	
}


//**IN USE**//
function suitcase_add(unique_code,checkin,checkout) {
	suitcase_add(unique_code,checkin,checkout, false);
}

//**IN USE**//
function suitcase_add(unique_code,checkin,checkout, book){
	//deActivateButtons();
	if(book){
		showProgressBar("Please be patient whilst we confirm your room(s) and rates","Confirming Availability ...");		
	}else{
		showProgressBar("Adding room(s) and rates to my Travelbag. Due to dynamic pricing we can only hold your reservation for 10 minutes.","Confirming Availability ...");
	}
	
	
	var suitcaseExtraElem = getElement('suitcase_extras');
	if(suitcaseExtraElem) suitcaseExtraElem.style.display = "inline";
	//get the category and hotel code from the unique code passed
	
	var tmp = unique_code.split("_");
	var selectHotelCode = tmp[0];
	var selectRoomCategoryCode = tmp[1];
	
	//get the various handles for the different elements
	var hdnMaxAdultsId = "hdnMaxAdults" + unique_code;
	var hdnMaxChildrenId = "hdnMaxChildren" + unique_code;
	var hdnMaxPaxId = "hdnMaxPax" + unique_code;
	var selectRoomCategoryNameId = "selectRoomCategoryName" + unique_code;
	var selectRoomTypeId = 'selectRoomType' + unique_code;
	var selectMealRatePlanId = 'selectMealRatePlanCode' + unique_code
	var selectNumRoomsId = 'selectNumRooms' + unique_code;
	var selectNumAdultsId =  'selectNumAdults' + unique_code;
	var selectNumKidsId = 'selectNumKids' + unique_code;

	var promoCodePassedId = 'hdnPromoCodePassed';
	var promoCodeElem = getElement(promoCodePassedId);
	var promoCode = promoCodeElem.value;
	//Room Category
	var selectRoomCategoryName = getElement(selectRoomCategoryNameId).value;

	//Room Type
	var selectRoomType = getElemValue(selectRoomTypeId);
	var selectRoomTypeCode = selectRoomType.substr(0,selectRoomType.indexOf("_"));
	var selectRoomTypeDesc = selectRoomType.substr(selectRoomType.indexOf("_")+1);

	//Meal Plan Code / Desc / Rate plan
	var selectMealPlan = getElemValue(selectMealRatePlanId);
	var myArray = selectMealPlan.split("_");
	var selectMealPlanCode = myArray[0];
	var selectMealPlanDesc = myArray[1];
	var selectRatePlanCode = myArray[2];

	if(selectRatePlanCode == "" || selectRatePlanCode == "null"){
		selectRatePlanCode = null;
	}
	var m = selectHotelCode +	selectRoomCategoryCode + selectRoomTypeCode;
	var selectedHotelObj = null;
	var selectedRoomCategoryObj = null;
	var selectedRoomObj = null;
	var selectedRatebreakdownObj = null;
	var selectedRatesObj = null;

	//THIS SECTION GETS THE SPECIFIC ENTRY IN THE JSON OBJECT AND SAVES ALL THE SELECTED OBJECTS
	//AS SOON AS ALL THE OBJECTS ARE FOUND IT BREAKS OUT OF THE LOOP
	for(var a = 0; a < json.length; a++){
		if(json[a].code == selectHotelCode){
			selectedHotelObj = json[a];
			for(var b = 0; b < selectedHotelObj.roomCategories.length; b++){
				if(selectedHotelObj.roomCategories[b].code == selectRoomCategoryCode){
					selectedRoomCategoryObj = selectedHotelObj.roomCategories[b];
					for(var c = 0; c < selectedRoomCategoryObj.rooms.length; c++){
						if(selectedRoomCategoryObj.rooms[c].code == selectRoomTypeCode){
							selectedRoomObj = selectedRoomCategoryObj.rooms[c];
							for(var d = 0; d < selectedRoomObj.rateBreakdowns.length; d++){
								if(selectedRoomObj.rateBreakdowns[d].ratePlanCode == selectRatePlanCode){
									selectedRatebreakdownObj = selectedRoomObj.rateBreakdowns[d];
									break;
								}
							}
							break;
						}
					}
					break;
				}
			}
			break;
		}
	}
		
	var selectedObject = new Array(selectedHotelObj);
	selectedObject[0].roomCategories = new Array(selectedRoomCategoryObj);
	selectedObject[0].roomCategories[0].rooms = new Array(selectedRoomObj);
	selectedObject[0].roomCategories[0].rooms[0].rateBreakdowns = new Array(selectedRatebreakdownObj);

	var solutionStr = selectedObject.toJSONString();
	//prompt("solutionString",encodeURI(solutionStr));
	var cancelByDate = selectedRoomObj.cancelBy;
	var cancelPenalty = selectedRoomObj.cancelPenalty;

	//Num Rooms
	var selectNumRooms = parseInt(getElemValue(selectNumRoomsId),10);

	//Num Adults
	var selectNumAdults = getElemValue(selectNumAdultsId);
	var hdnMaxAdults = getElement(hdnMaxAdultsId).value;

	//Num Kids
	var selectNumKids = getElemValue(selectNumKidsId);
	var hdnMaxChildren = getElement(hdnMaxChildrenId).value;

	//Num People
	//var selectNumPax = getElemValue(selectNumPaxId);
	var hdnMaxPax = parseInt(getElement(hdnMaxPaxId).value,10);

	var selectedNumPeople = parseInt(selectNumAdults,10)+parseInt(selectNumKids,10);
	//if the number of people is more than the allowed don't add
	if(selectedNumPeople > parseInt(hdnMaxPax,10)){
		//     The maximum amount of people is 2 for this room type. You have selected 3.
		alert("The maximum amount of people is "+hdnMaxPax+" for this room type. You have selected "+selectedNumPeople+".");
		//activateButtons();
		hideProgressBar();
	}else{

		//rateBreakdowns
		var hdnRateBreakdownId = "hdnRateBreakdown"+unique_code;
		var hdnRateBreakdown = getElement(hdnRateBreakdownId).value;

		selectMealPlanCode = selectMealPlanCode.replace("+","%2B");
		selectMealPlanDesc = selectMealPlanDesc.replace("+","%2B").replace("&","%26");
		
		var finalSolutionStr = URLEncode(solutionStr);
                finalSolutionStr = finalSolutionStr.replace("%E9","e");
                getstr = "solutionStr="+finalSolutionStr;
		getstr += "&num_rooms=" + encodeURI(selectNumRooms);
		getstr += "&num_adults=" + encodeURI(selectNumAdults);
		getstr += "&num_kids=" + encodeURI(selectNumKids);
		var url = "index.php?"+getstr;
		if(book) {
			sendRequest(url, toBooking, "option=com_booking&task=add&suitcase_task=add");
		} else {
			sendRequest(url, hideProgressBar, "option=com_booking&task=add&suitcase_task=add");
		}	
	}
	json = eval(json_extra);
}


//**IN USE**//
function update_suitcase_count(action){
	var suitcaseCountElem = getElement('div_suitcase_count');
	var strSuitcaseItemsCount = suitcaseCountElem.innerHTML;
	var intSuitcaseItemsCount;

	//var index = strSuitcaseItemsDesc.indexOf(" ")+1;
	//strSuitcaseItemsCount = strSuitcaseItemsDesc.substr(index);
	//index = strSuitcaseItemsCount.indexOf(" ");
	//strSuitcaseItemsCount = strSuitcaseItemsCount.substr(0,index);
	intSuitcaseItemsCount = parseInt(strSuitcaseItemsCount,10);

	if(action == "add"){
		intSuitcaseItemsCount++;
	}else if(action == "remove"){
		intSuitcaseItemsCount--;
	}else if(action == "clear"){
		intSuitcaseItemsCount = 0;
	}else{
		alert("Suitcase count not updated");
	}
	if(suitcaseCountElem)
		suitcaseCountElem.innerHTML = intSuitcaseItemsCount;
}


//**IN USE**//
function suitcase_clear(){
	deActivateButtons();

	var url = "index.php?";
	sendRequest(url, activateButtons, "option=com_booking&task=add&suitcase_task=clear");

	var suitcase_count = getElement('div_suitcase_count');
	if(suitcase_count){
		suitcase_count.innerHTML = "0";
	}
}


//**IN USE**//
function refresh_rows(unique_code,section){
	
	//set the input elements' id's
	var roomTypeId = 'selectRoomType'+unique_code;
	var mealRatePlanId = 'selectMealRatePlanCode'+unique_code;
	var numRoomsId = 'selectNumRooms'+unique_code;
	var numAdultsId = 'selectNumAdults'+unique_code;
	var numKidsId = 'selectNumKids'+unique_code;
	var hdnMaxPaxId = 'hdnMaxPax'+unique_code;

	var numRooms = parseInt(getElemValue(numRoomsId));
	var numAdults = parseInt(getElemValue(numAdultsId));
	var numKids = parseInt(getElemValue(numKidsId));

	var gridContentId = 'gridContent'+unique_code;
	var selectMealPlan = getElemValue(mealRatePlanId);

	var myArray = selectMealPlan.split("_");
	var meal_code = myArray[0];
	var meal_desc = myArray[1];
	var rate_code = myArray[2];

	if(rate_code == "" || rate_code == "null"){
		rate_code = null;
	}
	var m1 = "";
	m1 = "selectMealPlan:"+selectMealPlan;
	m1+= "\nmeal_code:"+meal_code;
	m1+= "\nmeal_desc:"+meal_desc;
	m1+= "\nrate_code:"+rate_code;

	var hotel_code = unique_code.substr(0,unique_code.indexOf("_"));
	var cat_code = unique_code.substr(unique_code.indexOf("_")+1);
	var room_code = getElemValue(roomTypeId).substr(0,getElemValue(roomTypeId).indexOf("_"));
	var grid_content = getElement(gridContentId);

	m1+= "\nhotel_code:"+hotel_code;
	m1+= "\ncat_code:"+cat_code;
	m1+= "\nroom_code:"+room_code;
	var hotel;
	var roomCategory;
	var room;
	var rateBreakdown;
	var rate;

	//get the hotel info
	for (var i = 0; i < json.length; i++) {
		if(json[i].code == hotel_code){
			hotel = json[i];
			m1+= "\nhotel_name:"+hotel.name;
			break;
		}
	}

	//get the category info
	for(var i = 0; i < hotel.roomCategories.length; i++){
		if(hotel.roomCategories[i].code == cat_code){
			roomCategory = hotel.roomCategories[i];
			m1+= "\nroom_category:"+roomCategory.name;
			break;
		}
	}

	m1+="\nroomCategory.rooms.length:"+roomCategory.rooms.length;
	//get the room info
	for(var i = 0; i < roomCategory.rooms.length; i++){
		if(roomCategory.rooms[i].code == room_code){
			room = roomCategory.rooms[i];
			m1+= "\nroom.name:"+room.name;
			break;
		}
	}

	m1+="\nroom.rateBreakdowns.length"+room.rateBreakdowns.length;

	//get the rateBreakdown info
	if(section != 'all'){
		for(var i = 0; i < room.rateBreakdowns.length; i++){
			if(room.rateBreakdowns[i].ratePlanCode == rate_code){
				rateBreakdown = room.rateBreakdowns[i];
				break;
			}
		}

		if(rate_code == "" || rate_code == " " || rate_code == null){
			//get the rateBreakdown info
			for(var i = 0; i < room.rateBreakdowns.length; i++){
				if(room.rateBreakdowns[i].mealPlanCode == meal_code){
					rateBreakdown = room.rateBreakdowns[i];
					break;
				}
			}
		}
	}else{
		//if the room type changes then use the first meal/rateplan code and not the previously 
		//selected meal / rateplan code
		rateBreakdown = room.rateBreakdowns[0];
	}
	
	var m2 = "";
	var roomTypeElem = getElement(roomTypeId);
	var mealPlanElem = getElement(mealRatePlanId);

	//var ratePlanElem = getElement(ratePlanId); //* look at this still
	var numRoomsElem = getElement(numRoomsId);
	var numAdultsElem = getElement(numAdultsId);
	var numKidsElem = getElement(numKidsId);

	var hdnMaxPaxElem = getElement(hdnMaxPaxId);

	var totalPriceId = 'totalPrice'+unique_code;
	var totalPriceElem = getElement(totalPriceId);
	var addStar = "";
	var total_days = diffdays(get_year_month_day(rateBreakdown.rates[0].startDate,"yyyy-mm-dd","date"),get_year_month_day(rateBreakdown.rates[rateBreakdown.rates.length-1].endDate,"yyyy-mm-dd","date"),"");

	if(section == 'all'){
		var mealPlanCodeList = new Array();
		var mealPlanCodeExists;
		//reset the meal plans
		mealPlanElem.options.length = 0;
		mealPlanCodeListCount = 0;
		m2+= "\nroom.rateBreakdowns.length:"+room.rateBreakdowns.length;
		for(var i = 0; i < room.rateBreakdowns.length; i++){
			mealPlanElem.options.add(new Option(room.rateBreakdowns[i].mealPlanCodeDesc, room.rateBreakdowns[i].mealPlanCode+"_"+room.rateBreakdowns[i].mealPlanCodeDesc+"_"+room.rateBreakdowns[i].ratePlanCode));
		}
	}

	//if(room.rateBreakdowns.length > 1){
	//	addStar = "*";
	//}

	//room type or meal type changed
	if(section == "all" || section == "meal"){
		//christoff fix this there is no units that come back so default to 4 //should be room.units
		var numUnits = room.numberOfUnits;
		if(numUnits > 4){
			numUnits = 4;
		}
		//reset the num rooms
		numRoomsElem.options.length = 0;
		for(i = 1; i <= numUnits; i++){
			numRoomsElem.options.add(new Option(i,i));
			if(i == numRooms){
				numRoomsElem.selectedIndex = i-1;
			}
		}

		//reset the num adults
		numAdultsElem.options.length = 0;
		for(i = 1; i <= room.maxAdults; i++){
			numAdultsElem.options.add(new Option(i,i));
			if(i == numAdults){
				numAdultsElem.selectedIndex = i-1;
			}
		}

		//reset the num kids
		numKidsElem.options.length = 0;
		for(i = 0; i <= room.maxChildren; i++){
			numKidsElem.options.add(new Option(i,i));
			if(i == numKids){
				numKidsElem.selectedIndex = i;
			}
		}

		var currentPeople = parseInt(numKidsElem.options[numKidsElem.selectedIndex].value,10) + parseInt(numAdultsElem.options[numAdultsElem.selectedIndex].value,10);
		hdnMaxPaxElem.value = room.maxPax;

		numRooms = parseInt(getElemValue(numRoomsId),10);
		numAdults = parseInt(getElemValue(numAdultsId),10);
		numKids = parseInt(getElemValue(numKidsId),10);

		//totalPriceElem.innerHTML = rateBreakdown.totalCurrency+" "+rateBreakdown.total+"&nbsp;"+addStar;
	}

	totalPrice = 0;
	////////////////////////
	//start with grid view//
	////////////////////////
	var currency = rateBreakdown.totalCurrency;
	var rates = rateBreakdown.rates;
	var price_day_array = new Array();
	var count = 0;
	var first_time = true;
	var begin_at_index = 0;
	var rate_num = 0;
	var txtGridRates = "";
	var rateId;
	var rateElem;
	var toolTip;

	var start;
	var end;

	//start the layout
	var grid = '<tr>';

	//the start date of the booking
	var main_start_date = rateBreakdown.rates[0].startDate;
	//the end date of the booking
	var main_end_date = rateBreakdown.rates[rateBreakdown.rates.length-1].endDate;

	//get the actual index of the day of the week were the grid should start displaying
	begin_at_index = get_day_of_week_index(main_start_date);

	count = begin_at_index;

	for(var i = 0; i < rates.length; i++){
		//set the rates to the hidden textboxes for the add to suitcase to pickup
		txtGridRates = rates[i].toJSONString();

		rate_num++;

		var start = get_year_month_day(rates[i].startDate,"yyyy-mm-dd","date");
		var end = get_year_month_day(rates[i].endDate,"yyyy-mm-dd","date");

		//get the total number of days for the current rate
		var rate_days = diffdays(start,end,"");

		//if one person then use singlePerPerson rate else use sharingPerPerson rate
		if(numAdults == 1){
			adults_price = rates[i].singlePerPerson;
		}else if(numAdults == 2){
			adults_price = rates[i].sharingPerPerson;
		}else if(numAdults > 2){
			adults_price = rates[i].sharingPerPerson + rates[i].extraAdult * (numAdults-2);
		}

		kids_price = numKids * rates[i].child;
		price = numRooms * (adults_price + kids_price);
		price_day_array = build_price_day_array(start,end,price,rate_days,currency);

		if(first_time){
			for(var c = 0; c < begin_at_index; c++){
				grid += '<td align="center">&nbsp;</td>';
			}
		}

		for (c = 0; c < rate_days; c++){
			if(bool_agent_logged_in){
				toolTip = "<h2>Rate for "+price_day_array[c].active_date+"</h2><br /><b>Description:</b> "+rates[i].description+"<br /><b>Sharing:</b> "+currency+" "+(rates[i].sharingPerPerson)+" per room per night<br /><b>Single:</b> "+currency+" "+(rates[i].singlePerPerson)+" per room per night";
				grid += '<td align="center" onmouseover="Tip(\''+toolTip+'\');" bgcolor="#E6F2FF" class="bar">'+price_day_array[c].active_date+'<br /><strong>'+price_day_array[c].price+'</strong><br />'+rates[i].ratePlanCode+'</td>';
			}else{
				grid += '<td align="center" bgcolor="#E6F2FF" class="bar">'+price_day_array[c].active_date+'<br /><strong>'+price_day_array[c].price+'</strong></td>';
			}

			count++;
			if(count > 6){
				count = 0;
				grid += "</tr><tr>";
			}
		}
		first_time = false;
	}
	grid += "</tr>";
	grid_content.innerHTML = '<table width="245" border="0" cellpadding="1" cellspacing="2" class="configureBooking"><tr><td width="35" align="center" bgcolor="#DDDDDD">Sun</td><td width="35" align="center" bgcolor="#DDDDDD">Mon</td><td width="35" align="center" bgcolor="#DDDDDD">Tue</td><td width="35" align="center" bgcolor="#DDDDDD">Wed</td><td width="35" align="center" bgcolor="#DDDDDD">Thur</td><td width="35" align="center" bgcolor="#DDDDDD">Fri</td><td width="35" align="center" bgcolor="#DDDDDD">Sat</td></tr>'+grid+'</table>';

	//reset the total price
	totalPriceElem.innerHTML = rateBreakdown.totalCurrency+" "+totalPrice+"&nbsp;"+addStar;
}


//**IN USE**//
function build_price_day_array(start,end,price,num_days,currency){
	var price_day_array = Array();
	var curr_date = new Date();
	var tmp_month;
	var tmp_day;
	curr_date = start;

	for(i = 0; i < num_days; i++){
		price_day_array[i] = new Array("active_date","price");

		tmp_month = curr_date.getMonth()+1;
		tmp_day = curr_date.getDate();

		if(tmp_month < 10){
			tmp_month = "0" + tmp_month;
		}
		if(tmp_day < 10){
			tmp_day = "0" + tmp_day;
		}

		price_day_array[i].active_date = tmp_day + "/" + tmp_month;
		price_day_array[i].price = currency + price;
		totalPrice += price;
		curr_date.setDate(curr_date.getDate()+1);

	}
	return price_day_array;
}


//**IN USE**//
function get_day_of_week_index(start_date){
	var begin_at_index;

	var year = start_date.substr(0,4);
	var month = start_date.substr(5,2);
	var day = start_date.substr(8,2);

	day = parseInt(day,10);
	month = (parseInt(month,10))-1;
	var tmp_begin_date = new Date();
	//LOOKING FOR PROBLEM IT MIGHT BE THIS
	tmp_begin_date.setDate(1);
	tmp_begin_date.setYear(year);
	tmp_begin_date.setMonth(parseInt(month));
	tmp_begin_date.setDate(parseInt(day));

	//THE MINUS 1 IS BECAUSE OF THE DAY BEING ONE DAY TOO FAR
	begin_at_index = tmp_begin_date.getDay();

	return begin_at_index;
}


//**IN USE**//
function get_year_month_day(date,from_fmt,to_fmt){
	var year;
	var month;
	var day;

	switch (from_fmt){
		case "date":
		year = date.getFullYear();
		month = date.getMonth();
		day = date.getDay();
		break;

		case "yyyy-mm-dd":
		year = date.substr(0,4);
		month = parseInt(date.substr(5,2),10);
		day = date.substr(8,2);
		break;
	}
	//var msg = "date in:"+date+"\nyear:"+year+"\nmonth:"+month+"\nday:"+day;
	switch (to_fmt){
		case "year-month-day":
		year = date.getFullYear();
		month = date.getMonth();
		if(month < 10){
			month = "0"+month;
		}

		day = date.getDay();
		if(day < 10){
			day = "0"+day;
		}

		return year+"-"+month+"-"+day;

		case "date":
		out_date = new Date();
		out_date.setDate(1);
		out_date.setYear(parseInt(year));
		out_date.setMonth(parseInt(month)-1);
		out_date.setDate(parseInt(day,10));
		return out_date;

		case "array":
		date = new Array();
		date['day'] = day;
		date['month'] = month;
		date['year'] = year;
		return date;
	}
}


//**IN USE**//
function suitcase_remove(suitcase_id){
	//disabled the buttons
	var elems = document.getElementsByName('disabledGroup[]');
	deActivateButtons();
	
	var url = "index.php?";
	sendRequest(url, activateButtons, "option=com_booking&task=add&suitcase_task=remove&suitcase_id="+suitcase_id);

	var suitcaseElement = getElement('divSuitcaseItem'+suitcase_id);
	suitcaseElement.innerHTML = "";
	
	var suitcaseCountElem = getElement('suitcaseCount');
	suitcaseCountElem.value = parseInt(suitcaseCountElem.value,10)-1;
	
	if(parseInt(suitcaseCountElem.value,10) == 0){
		var whole = getElement('confirmationcontainer');
		whole.innerHTML = '<table cellpadding="0" cellspacing="0" width="890" class="printwidth"><tr><td colspan="3" height="38" class="confirm-indent noprint" background="images/book_row_bg.gif" style="margin:0px; padding:0px; padding-left:10px;">Empty Travelbag</td></tr></table>';
		
	}

}
/* FILE: modules/mod_scripts/javascript-json.js*/


var default_name = "Select >>";
var default_name_country = "Select Country";
var default_name_region = "Select Region";
var default_name_city = "Select Town";
var default_name_hotel = "Select Hotel";

var default_value = "";

var msg = "";

var load_type = "";

var countryElem;
var regionElem;
var cityElem;
var hotelElem;

var selectedCountryId;
var selectedRegionId;
var selectedCityId;
var selectedHotelId;

var j_countries;
var j_country;
var curr_country;

var j_regions;
var j_region;
var curr_region;

var j_cities;
var j_city;
var curr_city;

var j_hotels;
var j_hotel;

//testing
var j_test_country = 0;
var j_test_region = 0;
var j_test_city = 0;
var j_test_hotel = 0;

function reset_booking_form(){
	var elem = getElement('selectCountries');
	elem.selectedIndex = 0;
	var elem = getElement('selectRegions');
	elem.selectedIndex = 0;
	var elem = getElement('selectCities');
	elem.selectedIndex = 0;
	var elem = getElement('selectHotels');
	elem.selectedIndex = 0;
	var elem = getElement('checkin_date');
	elem.value = "Check In";
	var elem = getElement('checkout_date');
	elem.value = "Check Out";
	var elem = getElement('nightsNumber');
	elem.value = "Number of nights";
	
	
}

function do_area(section){

	j_test_country = 0;
	j_test_region = 0;
	j_test_city = 0;
	j_test_hotel = 0;

	load_type = section;
	countryElem = getElement('selectCountries');
	regionElem = getElement('selectRegions');
	cityElem = getElement('selectCities');
	hotelElem = getElement('selectHotels');

	selectedCountryId = getValue(countryElem);
	selectedRegionId = getValue(regionElem);
	selectedCityId = getValue(cityElem);
	selectedHotelId = getValue(hotelElem);

	if(!isSet(selectedCountryId)){selectedCountryId = null;}
	if(!isSet(selectedRegionId)){selectedRegionId = null;}
	if(!isSet(selectedCityId)){selectedCityId = null;}
	if(!isSet(selectedHotelId)){selectedHotelId = null;}

	j_countries = json_areas;

	switch (load_type){
		case "country":

		selectedRegionId = "";
		selectedCityId = "";
		selectedHotelId = "";

		countryElem.options.length = 0;
		regionElem.options.length = 0;
		cityElem.options.length = 0;
		hotelElem.options.length = 0;

		curr_country = null;
		curr_region = null;
		curr_city = null;

		do_countries(j_countries);

		//if the regions are empty then do not display
		if(regionElem.options.length == 1){
			regionElem.style.visibility = "hidden";
			//if the region is hidden then set it to only contain the default name and value
			selectedRegionId = "";
			regionElem.options.length = 0;
			regionElem.options.add(new Option(default_name_region,default_value));
		}else{
			regionElem.style.visibility = "visible";
		}

		break;

		case "region":
		selectedCityId = "";
		selectedHotelId = "";

		regionElem.options.length = 0;
		cityElem.options.length = 0;
		hotelElem.options.length = 0;

		curr_region = null;
		curr_city = null;

		//if the country is not selected then set the regions to do for all countries
		if(isSet(curr_country)){
			j_regions = curr_country.regions;
		}else{
			j_countries = json_areas;
			for (var h = 0; h < j_countries.length; h++){
				j_country = j_countries[h];
				j_regions = j_country.regions;
				do_regions(j_regions);

			}
		}

		do_regions(j_regions);

		break;

		case "city":
		selectedHotelId = "";

		cityElem.options.length = 0;
		hotelElem.options.length = 0;

		curr_city = null;

		//if no region is selected
		if(!isSet(curr_region)){
			//if no region and country is selected
			if(!isSet(curr_country)){
				for(var g = 0; g < j_countries.length;g++){
					j_country = j_countries[g];
					for(var h = 0; h < j_country.regions.length;h++){
						j_region = j_country.regions[h];
						j_cities = j_region.cities;
						do_cities(j_cities);
					}
				}
			}else{
				//if country is selected but no region selected
				for(var g = 0; g < curr_country.regions.length;g++){
					j_region = curr_country.regions[g];
					j_cities = j_region.cities;
					do_cities(j_cities);
				}

			}
		}
		//if a region is selected
		else{
			//if a no country is selected but region is selected
			if(!isSet(curr_country)){
				//if no region selected and no country selected
				j_cities = curr_region.cities;
				do_cities(j_cities);
			}else{
				//if a region and country is selected
				j_cities = curr_region.cities;
				do_cities(j_cities);
			}

		}

		break;

		case "hotel":
		break;


	}
	sortList(countryElem,selectedCountryId,default_name_country);
	sortList(regionElem,selectedRegionId,default_name_region);
	sortList(cityElem,selectedCityId,default_name_city);
	sortList(hotelElem,selectedHotelId,default_name_hotel);


	//alert("country looped:"+j_test_country+"\nregion looped:"+j_test_region+"\ncity looped:"+j_test_city+"\nhotel looped:"+j_test_hotel+"\nselected items:\ncountry:"+selectedCountryId+"\nregion:"+selectedRegionId+"\ncity:"+selectedCityId+"\nhotel:"+selectedHotelId+"\ncurrent variables:\ncurr_country:"+curr_country+"\ncurr_region:"+curr_region+"\ncurr_city:"+curr_city);

}

function do_countries(j_countries){
	//loop through all the countries
	for(var a = 0; a < j_countries.length; a++){
		j_test_country++;
		j_country = j_countries[a];

		//if the looped country is the selected one
		if(j_country.id == selectedCountryId){
			curr_country = j_country;
			//set selected dropdown item
			add_country(j_country,true);
			//if country has been selected only do the regions for this country
			do_regions(j_country.regions);
		}else{
			//add country to the list
			add_country(j_country);

			if(selectedCountryId == null){
				//if no country is selected do the regions for all countries
				do_regions(j_country.regions);
			}
		}
	}
}

function do_regions(j_regions){
	for(var b = 0; b < j_regions.length; b++){
		j_test_region++;
		j_region = j_regions[b];
		//if the looped region is the selected one
		if(j_region.id == selectedRegionId){
			curr_region = j_region;
			//set selected dropdown item
			add_region(j_region,true);
			//if region has been selected only do the cities for this region
			do_cities(j_region.cities);
		}else{
			//add region to the list
			add_region(j_region);

			if(!isSet(selectedRegionId)){
				//if no region is selected do the cities for all regions
				do_cities(j_region.cities);
			}
		}
	}
}

function do_cities(j_cities){
	for(var c = 0; c < j_cities.length; c++){
		j_test_city++;
		j_city = j_cities[c];

		//if the looped city is the selected one
		if(j_city.id == selectedCityId){
			curr_city = j_city;
			//set selected dropdown item
			add_city(j_city,true);
			//if city has been selected only do the hotels for this city
			do_hotels(j_city.hotels);
		}else{
			//add city to the list
			add_city(j_city);

			if(!isSet(selectedCityId)){
				//if no city is selected do the hotels for all cities
				do_hotels(j_city.hotels);
			}
		}
	}
}

function do_hotels(j_hotels){
	for(var d = 0; d < j_hotels.length; d++){
		j_test_hotel++;
		j_hotel = j_hotels[d];
		add_hotel(j_hotel);
	}
}


function add_country(j_country,selected){
	if(countryElem.options.length == 0){
		countryElem.options.add(new Option(default_name_country,default_value));
	}
	countryElem.options.add(new Option(j_country.name,j_country.id));
	if(selected){
		countryElem.selectedIndex = countryElem.options.length-1;
	}
}

function add_region(j_region,selected){
	if(regionElem.options.length == 0){
		regionElem.options.add(new Option(default_name_region,default_value));
	}

	if(j_region.name != null){
		regionElem.options.add(new Option(j_region.name,j_region.id));
		if(selected){
			regionElem.selectedIndex = regionElem.options.length-1;
		}
	}
}

function add_city(j_city,selected){
	if(cityElem.options.length == 0){
		cityElem.options.add(new Option(default_name_city,default_value));
	}

	cityElem.options.add(new Option(j_city.name,j_city.id));
	if(selected){
		cityElem.selectedIndex = cityElem.options.length-1;
	}
}

function add_hotel(j_hotel){
	if(hotelElem.options.length == 0){
		hotelElem.options.add(new Option(default_name_hotel,default_value));
	}

	hotelElem.options.add(new Option(j_hotel.name,j_hotel.code))
}


function getValue(elem){
	return elem.options[elem.selectedIndex].value;
}


function isSet(val){
	if(val == null || val == "" || val == " "){
		return false;
	}
	return true;
}

function sortHotelNames(hotel_rows){
	var ph_hotel_rows = new Array();
	var other_hotel_rows = new Array();
	var ph_count = 0;
	var other_count = 0;
	for(var i = 0; i < hotel_rows.length; i++){

		//if(strpos($hotel_row->name,"Protea Hotel") === 0){
		if(hotel_rows[i].name.indexOf("Protea Hotel") != -1){

			//$hotel_row->name = str_replace("Protea Hotel","PH",$hotel_row->name);
			hotel_rows[i].name = hotel_rows[i].name.replace("Protea Hotel","PH");
			//$ph_hotels_rows[] = $hotel_row;
			ph_hotel_rows[ph_count] = hotel_rows[i];
			ph_count++;

		}else{
			//$other_hotel_rows[] = $hotel_row;
			other_hotel_rows[other_count] = hotel_rows[i];
			other_count++;
		}
	}

	//add the hotels that have PH as prefix first
	hotel_rows = ph_hotel_rows;
	//add the hotels that doesnt contain PH


	var curr_size = hotel_rows.length;
	for (var i = 0; i < other_hotel_rows.length; i++){
		hotel_rows[curr_size+i] = other_hotel_rows[i];
	}
	return hotel_rows;
}

function sortList(obj,selectedId,default_name) {

	var values = new Array();
	var ph_values = new Array();
	var ph_count = 0;
	var count = 0;

	for(var i = 1; i < obj.options.length; i++) {
		if(obj.options[i].innerHTML.indexOf("Protea Hotel ") != -1){
			ph_values.push(obj.options[i].innerHTML.replace("Protea Hotel ","PH ") + "--xx--" + obj.options[i].value);

		}
		else{
			values.push(obj.options[i].innerHTML + "--xx--" + obj.options[i].value);
		}
	}

	ph_values = ph_values.sort();
	values = values.sort();
	obj.options.length = 0;
	obj.options.add(new Option(default_name,default_value));

	for(var i = 0; i < ph_values.length; i++) {
		valueArray = ph_values[i].split('--xx--');
		obj.options.add(new Option(valueArray[0],valueArray[1]));

		if(selectedId == valueArray[1]){
			obj.selectedIndex = i+1;
		}

		//obj.options[i].innerHTML = valueArray[0];
		//obj.options[i].value = valueArray[1];
	}

	for(var i = 0; i < values.length; i++) {
		valueArray = values[i].split('--xx--');
		obj.options.add(new Option(valueArray[0],valueArray[1]));

		if(selectedId == valueArray[1]){
			obj.selectedIndex = i+1;
		}

		//obj.options[i].innerHTML = valueArray[0];
		//obj.options[i].value = valueArray[1];
	}
}



/* FILE: modules/mod_scripts/json-func.js*/
// Augment the basic prototypes if they have not already been augmented.

if (!Object.prototype.toJSONString) {

    Array.prototype.toJSONString = function () {
        var a = ['['],  // The array holding the text fragments.
            b,          // A boolean indicating that a comma is required.
            i,          // Loop counter.
            l = this.length,
            v;          // The value to be stringified.

        function p(s) {

// p accumulates text fragments in an array. It inserts a comma before all
// except the first fragment.

            if (b) {
                a.push(',');
            }
            a.push(s);
            b = true;
        }

// For each value in this array...

        for (i = 0; i < l; i += 1) {
            v = this[i];
            switch (typeof v) {

// Serialize a JavaScript object value. Ignore objects thats lack the
// toJSONString method. Due to a specification error in ECMAScript,
// typeof null is 'object', so watch out for that case.

            case 'object':
                if (v) {
                    if (typeof v.toJSONString === 'function') {
                        p(v.toJSONString());
                    }
                } else {
                    p("null");
                }
                break;

// Otherwise, serialize the value.

            case 'string':
            case 'number':
            case 'boolean':
                p(v.toJSONString());

// Values without a JSON representation are ignored.

            }
        }

// Join all of the fragments together and return.

        a.push(']');
        return a.join('');
    };


    Boolean.prototype.toJSONString = function () {
        return String(this);
    };


    Date.prototype.toJSONString = function () {

// Ultimately, this method will be equivalent to the date.toISOString method.

        function f(n) {

// Format integers to have at least two digits.

            return n < 10 ? '0' + n : n;
        }

        return '"' + this.getFullYear() + '-' +
                f(this.getMonth() + 1) + '-' +
                f(this.getDate()) + 'T' +
                f(this.getHours()) + ':' +
                f(this.getMinutes()) + ':' +
                f(this.getSeconds()) + '"';
    };


    Number.prototype.toJSONString = function () {

// JSON numbers must be finite. Encode non-finite numbers as null.

        return isFinite(this) ? String(this) : "null";
    };


    Object.prototype.toJSONString = function () {
        var a = ['{'],  // The array holding the text fragments.
            b,          // A boolean indicating that a comma is required.
            k,          // The current key.
            v;          // The current value.

        function p(s) {

// p accumulates text fragment pairs in an array. It inserts a comma before all
// except the first fragment pair.

            if (b) {
                a.push(',');
            }
            a.push(k.toJSONString(), ':', s);
            b = true;
        }

// Iterate through all of the keys in the object, ignoring the proto chain.

        for (k in this) {
            if (this.hasOwnProperty(k)) {
                v = this[k];
                switch (typeof v) {

// Serialize a JavaScript object value. Ignore objects that lack the
// toJSONString method. Due to a specification error in ECMAScript,
// typeof null is 'object', so watch out for that case.

                case 'object':
                    if (v) {
                        if (typeof v.toJSONString === 'function') {
                            p(v.toJSONString());
                        }
                    } else {
                        p("null");
                    }
                    break;

            case 'string':
            case 'number':
            case 'boolean':
                    p(v.toJSONString());

// Values without a JSON representation are ignored.

                }
            }
        }

// Join all of the fragments together and return.

        a.push('}');
        return a.join('');
    };


    (function (s) {

// Augment String.prototype. We do this in an immediate anonymous function to
// avoid defining global variables.

// m is a table of character substitutions.

        var m = {
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        };


        s.parseJSON = function (filter) {

// Parsing happens in three stages. In the first stage, we run the text against
// a regular expression which looks for non-JSON characters. We are especially
// concerned with '()' and 'new' because they can cause invocation, and '='
// because it can cause mutation. But just to be safe, we will reject all
// unexpected characters.

            try {
                if (/^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/.
                        test(this)) {

// In the second stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

                    var j = eval('(' + this + ')');

// In the optional third stage, we recursively walk the new structure, passing
// each name/value pair to a filter function for possible transformation.

                    if (typeof filter === 'function') {

                        function walk(k, v) {
                            if (v && typeof v === 'object') {
                                for (var i in v) {
                                    if (v.hasOwnProperty(i)) {
                                        v[i] = walk(i, v[i]);
                                    }
                                }
                            }
                            return filter(k, v);
                        }

                        j = walk('', j);
                    }
                    return j;
                }
            } catch (e) {

// Fall through if the regexp test fails.

            }
            throw new SyntaxError("parseJSON");
        };


        s.toJSONString = function () {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can simply slap some quotes around it.
// Otherwise we must also replace the offending characters with safe
// sequences.

            if (/["\\\x00-\x1f]/.test(this)) {
                return '"' + this.replace(/([\x00-\x1f\\"])/g, function(a, b) {
                    var c = m[b];
                    if (c) {
                        return c;
                    }
                    c = b.charCodeAt();
                    return '\\u00' +
                        Math.floor(c / 16).toString(16) +
                        (c % 16).toString(16);
                }) + '"';
            }
            return '"' + this + '"';
        };
    })(String.prototype);
}
/* FILE: modules/mod_scripts/calender.js*/
/*  Copyright Mihai Bazon, 2002-2005  |  www.bazon.net/mishoo
* -----------------------------------------------------------
*
* The DHTML Calendar, version 1.0 "It is happening again"
*
* Details and latest version at:
* www.dynarch.com/projects/calendar
*
* This script is developed by Dynarch.com.  Visit us at www.dynarch.com.
*
* This script is distributed under the GNU Lesser General Public License.
* Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
*/

// $Id: calender.js,v 1.4 2007-09-12 14:57:24 andrewg Exp $

/** The Calendar object constructor. */
Calendar = function (firstDayOfWeek, dateStr, onSelected, onClose) {
	// member variables
	this.activeDiv = null;
	this.currentDateEl = null;
	this.getDateStatus = null;
	this.getDateToolTip = null;
	this.getDateText = null;
	this.timeout = null;
	this.onSelected = onSelected || null;
	this.onClose = onClose || null;
	this.dragging = false;
	this.hidden = false;
	this.minYear = 1970;
	this.maxYear = 2050;
	this.dateFormat = Calendar._TT["DEF_DATE_FORMAT"];
	this.ttDateFormat = Calendar._TT["TT_DATE_FORMAT"];
	this.isPopup = true;
	this.weekNumbers = false;
	this.firstDayOfWeek = typeof firstDayOfWeek == "number" ? firstDayOfWeek : Calendar._FD; // 0 for Sunday, 1 for Monday, etc.
	this.showsOtherMonths = false;
	this.dateStr = dateStr;
	this.ar_days = null;
	this.showsTime = false;
	this.time24 = true;
	this.yearStep = 1;
	this.hiliteToday = true;
	this.multiple = null;
	// HTML elements
	this.table = null;
	this.element = null;
	this.tbody = null;
	this.firstdayname = null;
	// Combo boxes
	this.monthsCombo = null;
	this.yearsCombo = null;
	this.hilitedMonth = null;
	this.activeMonth = null;
	this.hilitedYear = null;
	this.activeYear = null;
	// Information
	this.dateClicked = false;

	// one-time initializations
	if (typeof Calendar._SDN == "undefined") {
		// table of short day names
		if (typeof Calendar._SDN_len == "undefined")
		Calendar._SDN_len = 3;
		var ar = new Array();
		for (var i = 8; i > 0;) {
			ar[--i] = Calendar._DN[i].substr(0, Calendar._SDN_len);
		}
		Calendar._SDN = ar;
		// table of short month names
		if (typeof Calendar._SMN_len == "undefined")
		Calendar._SMN_len = 3;
		ar = new Array();
		for (var i = 12; i > 0;) {
			ar[--i] = Calendar._MN[i].substr(0, Calendar._SMN_len);
		}
		Calendar._SMN = ar;
	}
};

// ** constants

/// "static", needed for event handlers.
Calendar._C = null;

/// detect a special case of "web browser"
Calendar.is_ie = ( /msie/i.test(navigator.userAgent) &&
!/opera/i.test(navigator.userAgent) );

Calendar.is_ie5 = ( Calendar.is_ie && /msie 5\.0/i.test(navigator.userAgent) );

/// detect Opera browser
Calendar.is_opera = /opera/i.test(navigator.userAgent);

/// detect KHTML-based browsers
Calendar.is_khtml = /Konqueror|Safari|KHTML/i.test(navigator.userAgent);

// BEGIN: UTILITY FUNCTIONS; beware that these might be moved into a separate
//        library, at some point.

Calendar.getAbsolutePos = function(el) {
	var SL = 0, ST = 0;
	var is_div = /^div$/i.test(el.tagName);
	if (is_div && el.scrollLeft)
	SL = el.scrollLeft;
	if (is_div && el.scrollTop)
	ST = el.scrollTop;
	var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST };
	if (el.offsetParent) {
		var tmp = this.getAbsolutePos(el.offsetParent);
		r.x += tmp.x;
		r.y += tmp.y;
	}
	return r;
};

Calendar.isRelated = function (el, evt) {
	var related = evt.relatedTarget;
	if (!related) {
		var type = evt.type;
		if (type == "mouseover") {
			related = evt.fromElement;
		} else if (type == "mouseout") {
			related = evt.toElement;
		}
	}
	while (related) {
		if (related == el) {
			return true;
		}
		related = related.parentNode;
	}
	return false;
};

Calendar.removeClass = function(el, className) {
	if (!(el && el.className)) {
		return;
	}
	var cls = el.className.split(" ");
	var ar = new Array();
	for (var i = cls.length; i > 0;) {
		if (cls[--i] != className) {
			ar[ar.length] = cls[i];
		}
	}
	el.className = ar.join(" ");
};

Calendar.addClass = function(el, className) {
	Calendar.removeClass(el, className);
	el.className += " " + className;
};

// FIXME: the following 2 functions totally suck, are useless and should be replaced immediately.
Calendar.getElement = function(ev) {
	var f = Calendar.is_ie ? window.event.srcElement : ev.currentTarget;
	while (f.nodeType != 1 || /^div$/i.test(f.tagName))
	f = f.parentNode;
	return f;
};

Calendar.getTargetElement = function(ev) {
	var f = Calendar.is_ie ? window.event.srcElement : ev.target;
	while (f.nodeType != 1)
	f = f.parentNode;
	return f;
};

Calendar.stopEvent = function(ev) {
	ev || (ev = window.event);
	if (Calendar.is_ie) {
		ev.cancelBubble = true;
		ev.returnValue = false;
	} else {
		ev.preventDefault();
		ev.stopPropagation();
	}
	return false;
};

Calendar.addEvent = function(el, evname, func) {
	if (el.attachEvent) { // IE
		el.attachEvent("on" + evname, func);
	} else if (el.addEventListener) { // Gecko / W3C
		el.addEventListener(evname, func, true);
	} else {
		el["on" + evname] = func;
	}
};

Calendar.removeEvent = function(el, evname, func) {
	if (el.detachEvent) { // IE
		el.detachEvent("on" + evname, func);
	} else if (el.removeEventListener) { // Gecko / W3C
		el.removeEventListener(evname, func, true);
	} else {
		el["on" + evname] = null;
	}
};

Calendar.createElement = function(type, parent) {
	var el = null;
	if (document.createElementNS) {
		// use the XHTML namespace; IE won't normally get here unless
		// _they_ "fix" the DOM2 implementation.
		el = document.createElementNS("http://www.w3.org/1999/xhtml", type);
	} else {
		el = document.createElement(type);
	}
	if (typeof parent != "undefined") {
		parent.appendChild(el);
	}
	return el;
};

// END: UTILITY FUNCTIONS

// BEGIN: CALENDAR STATIC FUNCTIONS

/** Internal -- adds a set of events to make some element behave like a button. */
Calendar._add_evs = function(el) {
	with (Calendar) {
		addEvent(el, "mouseover", dayMouseOver);
		addEvent(el, "mousedown", dayMouseDown);
		addEvent(el, "mouseout", dayMouseOut);
		if (is_ie) {
			addEvent(el, "dblclick", dayMouseDblClick);
			el.setAttribute("unselectable", true);
		}
	}
};

Calendar.findMonth = function(el) {
	if (typeof el.month != "undefined") {
		return el;
	} else if (typeof el.parentNode.month != "undefined") {
		return el.parentNode;
	}
	return null;
};

Calendar.findYear = function(el) {
	if (typeof el.year != "undefined") {
		return el;
	} else if (typeof el.parentNode.year != "undefined") {
		return el.parentNode;
	}
	return null;
};

Calendar.showMonthsCombo = function () {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	var cal = cal;
	var cd = cal.activeDiv;
	var mc = cal.monthsCombo;
	if (cal.hilitedMonth) {
		Calendar.removeClass(cal.hilitedMonth, "hilite");
	}
	if (cal.activeMonth) {
		Calendar.removeClass(cal.activeMonth, "active");
	}
	var mon = cal.monthsCombo.getElementsByTagName("div")[cal.date.getMonth()];
	Calendar.addClass(mon, "active");
	cal.activeMonth = mon;
	var s = mc.style;
	s.display = "block";
	if (cd.navtype < 0)
	s.left = cd.offsetLeft + "px";
	else {
		var mcw = mc.offsetWidth;
		if (typeof mcw == "undefined")
		// Konqueror brain-dead techniques
		mcw = 50;
		s.left = (cd.offsetLeft + cd.offsetWidth - mcw) + "px";
	}
	s.top = (cd.offsetTop + cd.offsetHeight) + "px";
};

Calendar.showYearsCombo = function (fwd) {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	var cal = cal;
	var cd = cal.activeDiv;
	var yc = cal.yearsCombo;
	if (cal.hilitedYear) {
		Calendar.removeClass(cal.hilitedYear, "hilite");
	}
	if (cal.activeYear) {
		Calendar.removeClass(cal.activeYear, "active");
	}
	cal.activeYear = null;
	var Y = cal.date.getFullYear() + (fwd ? 1 : -1);
	var yr = yc.firstChild;
	var show = false;
	for (var i = 12; i > 0; --i) {
		if (Y >= cal.minYear && Y <= cal.maxYear) {
			yr.innerHTML = Y;
			yr.year = Y;

			yr.style.display = "block";
			show = true;
		} else {
			yr.style.display = "none";
		}
		yr = yr.nextSibling;
		Y += fwd ? cal.yearStep : -cal.yearStep;
	}
	if (show) {
		var s = yc.style;
		s.display = "block";
		if (cd.navtype < 0)
		s.left = cd.offsetLeft + "px";
		else {
			var ycw = yc.offsetWidth;
			if (typeof ycw == "undefined")
			// Konqueror brain-dead techniques
			ycw = 50;
			s.left = (cd.offsetLeft + cd.offsetWidth - ycw) + "px";
		}
		s.top = (cd.offsetTop + cd.offsetHeight) + "px";
	}
};

// event handlers

Calendar.tableMouseUp = function(ev) {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	if (cal.timeout) {
		clearTimeout(cal.timeout);
	}
	var el = cal.activeDiv;
	if (!el) {
		return false;
	}
	var target = Calendar.getTargetElement(ev);
	ev || (ev = window.event);
	Calendar.removeClass(el, "active");
	if (target == el || target.parentNode == el) {
		Calendar.cellClick(el, ev);
	}
	var mon = Calendar.findMonth(target);
	var date = null;
	if (mon) {
		date = new Date(cal.date);
		if (mon.month != date.getMonth()) {
			date.setMonth(mon.month);
			cal.setDate(date);
			cal.dateClicked = false;
			cal.callHandler();
		}
	} else {
		var year = Calendar.findYear(target);
		if (year) {
			date = new Date(cal.date);
			if (year.year != date.getFullYear()) {
				date.setFullYear(year.year);
				cal.setDate(date);
				cal.dateClicked = false;
				cal.callHandler();
			}
		}
	}
	with (Calendar) {
		removeEvent(document, "mouseup", tableMouseUp);
		removeEvent(document, "mouseover", tableMouseOver);
		removeEvent(document, "mousemove", tableMouseOver);
		cal._hideCombos();
		_C = null;
		return stopEvent(ev);
	}
};

Calendar.tableMouseOver = function (ev) {
	var cal = Calendar._C;
	if (!cal) {
		return;
	}
	var el = cal.activeDiv;
	var target = Calendar.getTargetElement(ev);
	if (target == el || target.parentNode == el) {
		Calendar.addClass(el, "hilite active");
		Calendar.addClass(el.parentNode, "rowhilite");
	} else {
		if (typeof el.navtype == "undefined" || (el.navtype != 50 && (el.navtype == 0 || Math.abs(el.navtype) > 2)))
		Calendar.removeClass(el, "active");
		Calendar.removeClass(el, "hilite");
		Calendar.removeClass(el.parentNode, "rowhilite");
	}
	ev || (ev = window.event);
	if (el.navtype == 50 && target != el) {
		var pos = Calendar.getAbsolutePos(el);
		var w = el.offsetWidth;
		var x = ev.clientX;
		var dx;
		var decrease = true;
		if (x > pos.x + w) {
			dx = x - pos.x - w;
			decrease = false;
		} else
		dx = pos.x - x;

		if (dx < 0) dx = 0;
		var range = el._range;
		var current = el._current;
		var count = Math.floor(dx / 10) % range.length;
		for (var i = range.length; --i >= 0;)
		if (range[i] == current)
		break;
		while (count-- > 0)
		if (decrease) {
			if (--i < 0)
			i = range.length - 1;
		} else if ( ++i >= range.length )
		i = 0;
		var newval = range[i];
		el.innerHTML = newval;

		cal.onUpdateTime();
	}
	var mon = Calendar.findMonth(target);
	if (mon) {
		if (mon.month != cal.date.getMonth()) {
			if (cal.hilitedMonth) {
				Calendar.removeClass(cal.hilitedMonth, "hilite");
			}
			Calendar.addClass(mon, "hilite");
			cal.hilitedMonth = mon;
		} else if (cal.hilitedMonth) {
			Calendar.removeClass(cal.hilitedMonth, "hilite");
		}
	} else {
		if (cal.hilitedMonth) {
			Calendar.removeClass(cal.hilitedMonth, "hilite");
		}
		var year = Calendar.findYear(target);
		if (year) {
			if (year.year != cal.date.getFullYear()) {
				if (cal.hilitedYear) {
					Calendar.removeClass(cal.hilitedYear, "hilite");
				}
				Calendar.addClass(year, "hilite");
				cal.hilitedYear = year;
			} else if (cal.hilitedYear) {
				Calendar.removeClass(cal.hilitedYear, "hilite");
			}
		} else if (cal.hilitedYear) {
			Calendar.removeClass(cal.hilitedYear, "hilite");
		}
	}
	return Calendar.stopEvent(ev);
};

Calendar.tableMouseDown = function (ev) {
	if (Calendar.getTargetElement(ev) == Calendar.getElement(ev)) {
		return Calendar.stopEvent(ev);
	}
};

Calendar.calDragIt = function (ev) {
	var cal = Calendar._C;
	if (!(cal && cal.dragging)) {
		return false;
	}
	var posX;
	var posY;
	if (Calendar.is_ie) {
		posY = window.event.clientY + document.body.scrollTop;
		posX = window.event.clientX + document.body.scrollLeft;
	} else {
		posX = ev.pageX;
		posY = ev.pageY;
	}
	cal.hideShowCovered();
	var st = cal.element.style;
	st.left = (posX - cal.xOffs) + "px";
	st.top = (posY - cal.yOffs) + "px";
	return Calendar.stopEvent(ev);
};

Calendar.calDragEnd = function (ev) {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	cal.dragging = false;
	with (Calendar) {
		removeEvent(document, "mousemove", calDragIt);
		removeEvent(document, "mouseup", calDragEnd);
		tableMouseUp(ev);
	}
	cal.hideShowCovered();
};

Calendar.dayMouseDown = function(ev) {
	var el = Calendar.getElement(ev);
	if (el.disabled) {
		return false;
	}
	var cal = el.calendar;
	cal.activeDiv = el;
	Calendar._C = cal;
	if (el.navtype != 300) with (Calendar) {
		if (el.navtype == 50) {
			el._current = el.innerHTML;
			addEvent(document, "mousemove", tableMouseOver);
		} else
		addEvent(document, Calendar.is_ie5 ? "mousemove" : "mouseover", tableMouseOver);
		addClass(el, "hilite active");
		addEvent(document, "mouseup", tableMouseUp);
	} else if (cal.isPopup) {
		cal._dragStart(ev);
	}
	if (el.navtype == -1 || el.navtype == 1) {
		if (cal.timeout) clearTimeout(cal.timeout);
		cal.timeout = setTimeout("Calendar.showMonthsCombo()", 250);
	} else if (el.navtype == -2 || el.navtype == 2) {
		if (cal.timeout) clearTimeout(cal.timeout);
		cal.timeout = setTimeout((el.navtype > 0) ? "Calendar.showYearsCombo(true)" : "Calendar.showYearsCombo(false)", 250);
	} else {
		cal.timeout = null;
	}
	return Calendar.stopEvent(ev);
};

Calendar.dayMouseDblClick = function(ev) {
	Calendar.cellClick(Calendar.getElement(ev), ev || window.event);
	if (Calendar.is_ie) {
		document.selection.empty();
	}
};

Calendar.dayMouseOver = function(ev) {
	var el = Calendar.getElement(ev);
	if (Calendar.isRelated(el, ev) || Calendar._C || el.disabled) {
		return false;
	}
	if (el.ttip) {
		if (el.ttip.substr(0, 1) == "_") {
			el.ttip = el.caldate.print(el.calendar.ttDateFormat) + el.ttip.substr(1);
		}
		el.calendar.tooltips.innerHTML = el.ttip;
	}
	if (el.navtype != 300) {
		Calendar.addClass(el, "hilite");
		if (el.caldate) {
			Calendar.addClass(el.parentNode, "rowhilite");
		}
	}
	return Calendar.stopEvent(ev);
};

Calendar.dayMouseOut = function(ev) {
	with (Calendar) {
		var el = getElement(ev);
		if (isRelated(el, ev) || _C || el.disabled)
		return false;
		removeClass(el, "hilite");
		if (el.caldate)
		removeClass(el.parentNode, "rowhilite");
		if (el.calendar)
		el.calendar.tooltips.innerHTML = _TT["SEL_DATE"];
		return stopEvent(ev);
	}
};

/**
*  A generic "click" handler :) handles all types of buttons defined in this
*  calendar.
*/
Calendar.cellClick = function(el, ev) {
	var cal = el.calendar;
	var closing = false;
	var newdate = false;
	var date = null;
	if (typeof el.navtype == "undefined") {
		if (cal.currentDateEl) {
			Calendar.removeClass(cal.currentDateEl, "selected");
			Calendar.addClass(el, "selected");
			closing = (cal.currentDateEl == el);
			if (!closing) {
				cal.currentDateEl = el;
			}
		}
		cal.date.setDateOnly(el.caldate);
		date = cal.date;
		var other_month = !(cal.dateClicked = !el.otherMonth);
		if (!other_month && !cal.currentDateEl)
		cal._toggleMultipleDate(new Date(date));
		else
		newdate = !el.disabled;
		// a date was clicked
		if (other_month)
		cal._init(cal.firstDayOfWeek, date);
	} else {
		if (el.navtype == 200) {
			Calendar.removeClass(el, "hilite");
			cal.callCloseHandler();
			return;
		}
		date = new Date(cal.date);
		if (el.navtype == 0)
		date.setDateOnly(new Date()); // TODAY
		// unless "today" was clicked, we assume no date was clicked so
		// the selected handler will know not to close the calenar when
		// in single-click mode.
		// cal.dateClicked = (el.navtype == 0);
		cal.dateClicked = false;
		var year = date.getFullYear();
		var mon = date.getMonth();
		function setMonth(m) {
			var day = date.getDate();
			var max = date.getMonthDays(m);
			if (day > max) {
				date.setDate(max);
			}
			date.setMonth(m);
		};
		switch (el.navtype) {
			case 400:
			Calendar.removeClass(el, "hilite");
			var text = Calendar._TT["ABOUT"];
			if (typeof text != "undefined") {
				text += cal.showsTime ? Calendar._TT["ABOUT_TIME"] : "";
			} else {
				// FIXME: this should be removed as soon as lang files get updated!
				text = "Help and about box text is not translated into this language.\n" +
				"If you know this language and you feel generous please update\n" +
				"the corresponding file in \"lang\" subdir to match calendar-en.js\n" +
				"and send it back to <mihai_bazon@yahoo.com> to get it into the distribution  ;-)\n\n" +
				"Thank you!\n" +
				"http://dynarch.com/mishoo/calendar.epl\n";
			}
			alert(text);
			return;
			case -2:
			if (year > cal.minYear) {
				date.setFullYear(year - 1);
			}
			break;
			case -1:
			if (mon > 0) {
				setMonth(mon - 1);
			} else if (year-- > cal.minYear) {
				date.setFullYear(year);
				setMonth(11);
			}
			break;
			case 1:
			if (mon < 11) {
				setMonth(mon + 1);
			} else if (year < cal.maxYear) {
				date.setFullYear(year + 1);
				setMonth(0);
			}
			break;
			case 2:
			if (year < cal.maxYear) {
				date.setFullYear(year + 1);
			}
			break;
			case 100:
			cal.setFirstDayOfWeek(el.fdow);
			return;
			case 50:
			var range = el._range;
			var current = el.innerHTML;
			for (var i = range.length; --i >= 0;)
			if (range[i] == current)
			break;
			if (ev && ev.shiftKey) {
				if (--i < 0)
				i = range.length - 1;
			} else if ( ++i >= range.length )
			i = 0;
			var newval = range[i];
			el.innerHTML = newval;
			cal.onUpdateTime();
			return;
			case 0:
			// TODAY will bring us here
			if ((typeof cal.getDateStatus == "function") &&
			cal.getDateStatus(date, date.getFullYear(), date.getMonth(), date.getDate())) {
				return false;
			}
			break;
		}
		if (!date.equalsTo(cal.date)) {
			cal.setDate(date);
			newdate = true;
		} else if (el.navtype == 0)
		newdate = closing = true;
	}
	if (newdate) {
		ev && cal.callHandler();
	}
	if (closing) {
		Calendar.removeClass(el, "hilite");
		ev && cal.callCloseHandler();
	}
};

// END: CALENDAR STATIC FUNCTIONS

// BEGIN: CALENDAR OBJECT FUNCTIONS

/**
*  This function creates the calendar inside the given parent.  If _par is
*  null than it creates a popup calendar inside the BODY element.  If _par is
*  an element, be it BODY, then it creates a non-popup calendar (still
*  hidden).  Some properties need to be set before calling this function.
*/
Calendar.prototype.create = function (_par) {
	var parent = null;
	if (! _par) {
		// default parent is the document body, in which case we create
		// a popup calendar.
		parent = document.getElementsByTagName("body")[0];
		this.isPopup = true;
	} else {
		parent = _par;
		this.isPopup = false;
	}
	this.date = this.dateStr ? new Date(this.dateStr) : new Date();

	var table = Calendar.createElement("table");
	this.table = table;
	table.cellSpacing = 0;
	table.cellPadding = 0;
	table.calendar = this;
	Calendar.addEvent(table, "mousedown", Calendar.tableMouseDown);

	var div = Calendar.createElement("div");
	this.element = div;
	div.className = "calendar";
	if (this.isPopup) {
		div.style.position = "absolute";
		div.style.display = "none";
	}
	div.appendChild(table);

	var thead = Calendar.createElement("thead", table);
	var cell = null;
	var row = null;

	var cal = this;
	var hh = function (text, cs, navtype) {
		cell = Calendar.createElement("td", row);
		cell.colSpan = cs;
		cell.className = "button";
		if (navtype != 0 && Math.abs(navtype) <= 2)
		cell.className += " nav";

		Calendar._add_evs(cell);
		cell.calendar = cal;
		cell.navtype = navtype;
		cell.innerHTML = "<div unselectable='on'>" + text + "</div>";
		return cell;
	};

	row = Calendar.createElement("tr", thead);
	var title_length = 5;
	(this.isPopup) && --title_length;
	(this.weekNumbers) && ++title_length;

	//hh("?", 1, 400).ttip = Calendar._TT["INFO"];
	
	this._nav_pm = hh("&#x2039;", 1, -1);
	this._nav_pm.ttip = Calendar._TT["PREV_MONTH"];
	
	this.title = hh("", title_length, 300);
	this.title.className = "title";
	
	this._nav_nm = hh("&#x203a;", 1, 1);
	this._nav_nm.ttip = Calendar._TT["NEXT_MONTH"];
	
	if (this.isPopup) {
		this.title.ttip = Calendar._TT["DRAG_TO_MOVE"];
		this.title.style.cursor = "move";
		hh("&#x00d7;", 1, 200).ttip = Calendar._TT["CLOSE"];
	}
	
	row = Calendar.createElement("tr", thead);
	row.className = "headrow";
														this._nav_nm = hh("&nbsp;", 1, 1);
	//this._nav_py = hh("&#x00ab;", 1, -2);
	//this._nav_py.ttip = Calendar._TT["PREV_YEAR"];

//	this._nav_pm = hh("&#x2039;", 1, -1);
//	this._nav_pm.ttip = Calendar._TT["PREV_MONTH"];

	this._nav_now = hh(Calendar._TT["TODAY"], this.weekNumbers ? 4 : 5, 0);
	this._nav_now.ttip = Calendar._TT["GO_TODAY"];
//
//	this._nav_nm = hh("&#x203a;", 1, 1);
//	this._nav_nm.ttip = Calendar._TT["NEXT_MONTH"];

	//this._nav_ny = hh("&#x00bb;", 1, 2);
	//this._nav_ny.ttip = Calendar._TT["NEXT_YEAR"];

	// day names
	row = Calendar.createElement("tr", thead);
	row.className = "daynames";
	if (this.weekNumbers) {
		cell = Calendar.createElement("td", row);
		cell.className = "name wn";
		cell.innerHTML = Calendar._TT["WK"];
	}
	for (var i = 7; i > 0; --i) {
		cell = Calendar.createElement("td", row);
		if (!i) {
			cell.navtype = 100;
			cell.calendar = this;
			Calendar._add_evs(cell);
		}
	}
	this.firstdayname = (this.weekNumbers) ? row.firstChild.nextSibling : row.firstChild;
	this._displayWeekdays();

	var tbody = Calendar.createElement("tbody", table);
	this.tbody = tbody;

	for (i = 6; i > 0; --i) {
		row = Calendar.createElement("tr", tbody);
		if (this.weekNumbers) {
			cell = Calendar.createElement("td", row);
		}
		for (var j = 7; j > 0; --j) {
			cell = Calendar.createElement("td", row);
			cell.calendar = this;
			Calendar._add_evs(cell);
		}
	}

	if (this.showsTime) {
		row = Calendar.createElement("tr", tbody);
		row.className = "time";

		cell = Calendar.createElement("td", row);
		cell.className = "time";
		cell.colSpan = 2;
		cell.innerHTML = Calendar._TT["TIME"] || "&nbsp;";

		cell = Calendar.createElement("td", row);
		cell.className = "time";
		cell.colSpan = this.weekNumbers ? 4 : 3;

		(function(){
			function makeTimePart(className, init, range_start, range_end) {
				var part = Calendar.createElement("span", cell);
				part.className = className;
				part.innerHTML = init;
				part.calendar = cal;
				part.ttip = Calendar._TT["TIME_PART"];
				part.navtype = 50;
				part._range = [];
				if (typeof range_start != "number")
				part._range = range_start;
				else {
					for (var i = range_start; i <= range_end; ++i) {
						var txt;
						if (i < 10 && range_end >= 10) txt = '0' + i;
						else txt = '' + i;
						part._range[part._range.length] = txt;
					}
				}
				Calendar._add_evs(part);
				return part;
			};
			var hrs = cal.date.getHours();
			var mins = cal.date.getMinutes();
			var t12 = !cal.time24;
			var pm = (hrs > 12);
			if (t12 && pm) hrs -= 12;
			var H = makeTimePart("hour", hrs, t12 ? 1 : 0, t12 ? 12 : 23);
			var span = Calendar.createElement("span", cell);
			span.innerHTML = ":";
			span.className = "colon";
			var M = makeTimePart("minute", mins, 0, 59);
			var AP = null;
			cell = Calendar.createElement("td", row);
			cell.className = "time";
			cell.colSpan = 2;
			if (t12)
			AP = makeTimePart("ampm", pm ? "pm" : "am", ["am", "pm"]);
			else
			cell.innerHTML = "&nbsp;";

			cal.onSetTime = function() {
				var pm, hrs = this.date.getHours(),
				mins = this.date.getMinutes();
				if (t12) {
					pm = (hrs >= 12);
					if (pm) hrs -= 12;
					if (hrs == 0) hrs = 12;
					AP.innerHTML = pm ? "pm" : "am";
				}
				H.innerHTML = (hrs < 10) ? ("0" + hrs) : hrs;
				M.innerHTML = (mins < 10) ? ("0" + mins) : mins;
			};

			cal.onUpdateTime = function() {
				var date = this.date;
				var h = parseInt(H.innerHTML, 10);
				if (t12) {
					if (/pm/i.test(AP.innerHTML) && h < 12)
					h += 12;
					else if (/am/i.test(AP.innerHTML) && h == 12)
					h = 0;
				}
				var d = date.getDate();
				var m = date.getMonth();
				var y = date.getFullYear();
				date.setHours(h);
				date.setMinutes(parseInt(M.innerHTML, 10));
				date.setFullYear(y);
				date.setMonth(m);
				date.setDate(d);
				this.dateClicked = false;
				this.callHandler();
			};
		})();
	} else {
		this.onSetTime = this.onUpdateTime = function() {};
	}

	var tfoot = Calendar.createElement("tfoot", table);

	row = Calendar.createElement("tr", tfoot);
	row.className = "footrow";

	cell = hh(Calendar._TT["SEL_DATE"], this.weekNumbers ? 8 : 7, 300);
	cell.className = "ttip";
	if (this.isPopup) {
		cell.ttip = Calendar._TT["DRAG_TO_MOVE"];
		cell.style.cursor = "move";
	}
	this.tooltips = cell;

	div = Calendar.createElement("div", this.element);
	this.monthsCombo = div;
	div.className = "combo";
	for (i = 0; i < Calendar._MN.length; ++i) {
		var mn = Calendar.createElement("div");
		mn.className = Calendar.is_ie ? "label-IEfix" : "label";
		mn.month = i;
		mn.innerHTML = Calendar._SMN[i];
		div.appendChild(mn);
	}

	div = Calendar.createElement("div", this.element);
	this.yearsCombo = div;
	div.className = "combo";
	for (i = 12; i > 0; --i) {
		var yr = Calendar.createElement("div");
		yr.className = Calendar.is_ie ? "label-IEfix" : "label";
		div.appendChild(yr);
	}

	this._init(this.firstDayOfWeek, this.date);
	parent.appendChild(this.element);
};

/** keyboard navigation, only for popup calendars */
Calendar._keyEvent = function(ev) {
	var cal = window._dynarch_popupCalendar;
	if (!cal || cal.multiple)
	return false;
	(Calendar.is_ie) && (ev = window.event);
	var act = (Calendar.is_ie || ev.type == "keypress"),
	K = ev.keyCode;
	if (ev.ctrlKey) {
		switch (K) {
			case 37: // KEY left
			act && Calendar.cellClick(cal._nav_pm);
			break;
			case 38: // KEY up
			act && Calendar.cellClick(cal._nav_py);
			break;
			case 39: // KEY right
			act && Calendar.cellClick(cal._nav_nm);
			break;
			case 40: // KEY down
			act && Calendar.cellClick(cal._nav_ny);
			break;
			default:
			return false;
		}
	} else switch (K) {
		case 32: // KEY space (now)
		Calendar.cellClick(cal._nav_now);
		break;
		case 27: // KEY esc
		act && cal.callCloseHandler();
		break;
		case 37: // KEY left
		case 38: // KEY up
		case 39: // KEY right
		case 40: // KEY down
		if (act) {
			var prev, x, y, ne, el, step;
			prev = K == 37 || K == 38;
			step = (K == 37 || K == 39) ? 1 : 7;
			function setVars() {
				el = cal.currentDateEl;
				var p = el.pos;
				x = p & 15;
				y = p >> 4;
				ne = cal.ar_days[y][x];
			};setVars();
			function prevMonth() {
				var date = new Date(cal.date);
				date.setDate(date.getDate() - step);
				cal.setDate(date);
			};
			function nextMonth() {
				var date = new Date(cal.date);
				date.setDate(date.getDate() + step);
				cal.setDate(date);
			};
			while (1) {
				switch (K) {
					case 37: // KEY left
					if (--x >= 0)
					ne = cal.ar_days[y][x];
					else {
						x = 6;
						K = 38;
						continue;
					}
					break;
					case 38: // KEY up
					if (--y >= 0)
					ne = cal.ar_days[y][x];
					else {
						prevMonth();
						setVars();
					}
					break;
					case 39: // KEY right
					if (++x < 7)
					ne = cal.ar_days[y][x];
					else {
						x = 0;
						K = 40;
						continue;
					}
					break;
					case 40: // KEY down
					if (++y < cal.ar_days.length)
					ne = cal.ar_days[y][x];
					else {
						nextMonth();
						setVars();
					}
					break;
				}
				break;
			}
			if (ne) {
				if (!ne.disabled)
				Calendar.cellClick(ne);
				else if (prev)
				prevMonth();
				else
				nextMonth();
			}
		}
		break;
		case 13: // KEY enter
		if (act)
		Calendar.cellClick(cal.currentDateEl, ev);
		break;
		default:
		return false;
	}
	return Calendar.stopEvent(ev);
};

/**
*  (RE)Initializes the calendar to the given date and firstDayOfWeek
*/
Calendar.prototype._init = function (firstDayOfWeek, date) {
	var today = new Date(),
	TY = today.getFullYear(),
	TM = today.getMonth(),
	TD = today.getDate();
	this.table.style.visibility = "hidden";
	var year = date.getFullYear();
	if (year < this.minYear) {
		year = this.minYear;
		date.setFullYear(year);
	} else if (year > this.maxYear) {
		year = this.maxYear;
		date.setFullYear(year);
	}
	this.firstDayOfWeek = firstDayOfWeek;
	this.date = new Date(date);
	var month = date.getMonth();
	var mday = date.getDate();
	var no_days = date.getMonthDays();

	// calendar voodoo for computing the first day that would actually be
	// displayed in the calendar, even if it's from the previous month.
	// WARNING: this is magic. ;-)
	date.setDate(1);
	var day1 = (date.getDay() - this.firstDayOfWeek) % 7;
	if (day1 < 0)
	day1 += 7;
	date.setDate(-day1);
	date.setDate(date.getDate() + 1);

	var row = this.tbody.firstChild;
	var MN = Calendar._SMN[month];
	var ar_days = this.ar_days = new Array();
	var weekend = Calendar._TT["WEEKEND"];
	var dates = this.multiple ? (this.datesCells = {}) : null;
	for (var i = 0; i < 6; ++i, row = row.nextSibling) {
		var cell = row.firstChild;
		if (this.weekNumbers) {
			cell.className = "day wn";
			cell.innerHTML = date.getWeekNumber();
			cell = cell.nextSibling;
		}
		row.className = "daysrow";
		var hasdays = false, iday, dpos = ar_days[i] = [];
		for (var j = 0; j < 7; ++j, cell = cell.nextSibling, date.setDate(iday + 1)) {
			iday = date.getDate();
			var wday = date.getDay();
			cell.className = "day";
			cell.pos = i << 4 | j;
			dpos[j] = cell;
			var current_month = (date.getMonth() == month);
			if (!current_month) {
				if (this.showsOtherMonths) {
					cell.className += " othermonth";
					cell.otherMonth = true;
				} else {
					cell.className = "emptycell";
					cell.innerHTML = "&nbsp;";
					cell.disabled = true;
					continue;
				}
			} else {
				cell.otherMonth = false;
				hasdays = true;
			}
			cell.disabled = false;
			cell.innerHTML = this.getDateText ? this.getDateText(date, iday) : iday;
			if (dates)
			dates[date.print("%Y%m%d")] = cell;
			if (this.getDateStatus) {
				var status = this.getDateStatus(date, year, month, iday);
				if (this.getDateToolTip) {
					var toolTip = this.getDateToolTip(date, year, month, iday);
					if (toolTip)
					cell.title = toolTip;
				}
				if (status === true) {
					cell.className += " disabled";
					cell.disabled = true;
				} else {
					if (/disabled/i.test(status))
					cell.disabled = true;
					cell.className += " " + status;
				}
			}
			if (!cell.disabled) {
				cell.caldate = new Date(date);
				cell.ttip = "_";
				if (!this.multiple && current_month
				&& iday == mday && this.hiliteToday) {
					cell.className += " selected";
					this.currentDateEl = cell;
				}
				if (date.getFullYear() == TY &&
				date.getMonth() == TM &&
				iday == TD) {
					cell.className += " today";
					cell.ttip += Calendar._TT["PART_TODAY"];
				}
				if (weekend.indexOf(wday.toString()) != -1)
				cell.className += cell.otherMonth ? " oweekend" : " weekend";
			}
		}
		if (!(hasdays || this.showsOtherMonths))
		row.className = "emptyrow";
	}
	this.title.innerHTML = Calendar._MN[month] + ", " + year;
	this.onSetTime();
	this.table.style.visibility = "visible";
	this._initMultipleDates();
	// PROFILE
	// this.tooltips.innerHTML = "Generated in " + ((new Date()) - today) + " ms";
};

Calendar.prototype._initMultipleDates = function() {
	if (this.multiple) {
		for (var i in this.multiple) {
			var cell = this.datesCells[i];
			var d = this.multiple[i];
			if (!d)
			continue;
			if (cell)
			cell.className += " selected";
		}
	}
};

Calendar.prototype._toggleMultipleDate = function(date) {
	if (this.multiple) {
		var ds = date.print("%Y%m%d");
		var cell = this.datesCells[ds];
		if (cell) {
			var d = this.multiple[ds];
			if (!d) {
				Calendar.addClass(cell, "selected");
				this.multiple[ds] = date;
			} else {
				Calendar.removeClass(cell, "selected");
				delete this.multiple[ds];
			}
		}
	}
};

Calendar.prototype.setDateToolTipHandler = function (unaryFunction) {
	this.getDateToolTip = unaryFunction;
};

/**
*  Calls _init function above for going to a certain date (but only if the
*  date is different than the currently selected one).
*/
Calendar.prototype.setDate = function (date) {
	if (!date.equalsTo(this.date)) {
		this._init(this.firstDayOfWeek, date);
	}
};

/**
*  Refreshes the calendar.  Useful if the "disabledHandler" function is
*  dynamic, meaning that the list of disabled date can change at runtime.
*  Just * call this function if you think that the list of disabled dates
*  should * change.
*/
Calendar.prototype.refresh = function () {
	this._init(this.firstDayOfWeek, this.date);
};

/** Modifies the "firstDayOfWeek" parameter (pass 0 for Synday, 1 for Monday, etc.). */
Calendar.prototype.setFirstDayOfWeek = function (firstDayOfWeek) {
	/** disabled - confused users ;-)
	this._init(firstDayOfWeek, this.date);
	this._displayWeekdays();
	*/
};

/**
*  Allows customization of what dates are enabled.  The "unaryFunction"
*  parameter must be a function object that receives the date (as a JS Date
*  object) and returns a boolean value.  If the returned value is true then
*  the passed date will be marked as disabled.
*/
Calendar.prototype.setDateStatusHandler = Calendar.prototype.setDisabledHandler = function (unaryFunction) {
	this.getDateStatus = unaryFunction;
};

/** Customization of allowed year range for the calendar. */
Calendar.prototype.setRange = function (a, z) {
	this.minYear = a;
	this.maxYear = z;
};

/** Calls the first user handler (selectedHandler). */
Calendar.prototype.callHandler = function () {
	if (this.onSelected) {
		this.onSelected(this, this.date.print(this.dateFormat));
	}
};

/** Calls the second user handler (closeHandler). */
Calendar.prototype.callCloseHandler = function () {
	if (this.onClose) {
		this.onClose(this);
	}
	this.hideShowCovered();
};

/** Removes the calendar object from the DOM tree and destroys it. */
Calendar.prototype.destroy = function () {
	var el = this.element.parentNode;
	el.removeChild(this.element);
	Calendar._C = null;
	window._dynarch_popupCalendar = null;
};

/**
*  Moves the calendar element to a different section in the DOM tree (changes
*  its parent).
*/
Calendar.prototype.reparent = function (new_parent) {
	var el = this.element;
	el.parentNode.removeChild(el);
	new_parent.appendChild(el);
};

// This gets called when the user presses a mouse button anywhere in the
// document, if the calendar is shown.  If the click was outside the open
// calendar this function closes it.
Calendar._checkCalendar = function(ev) {
	var calendar = window._dynarch_popupCalendar;
	if (!calendar) {
		return false;
	}
	var el = Calendar.is_ie ? Calendar.getElement(ev) : Calendar.getTargetElement(ev);
	for (; el != null && el != calendar.element; el = el.parentNode);
	if (el == null) {
		// calls closeHandler which should hide the calendar.
		window._dynarch_popupCalendar.callCloseHandler();
		return Calendar.stopEvent(ev);
	}
};

/** Shows the calendar. */
Calendar.prototype.show = function () {
	var rows = this.table.getElementsByTagName("tr");
	for (var i = rows.length; i > 0;) {
		var row = rows[--i];
		Calendar.removeClass(row, "rowhilite");
		var cells = row.getElementsByTagName("td");
		for (var j = cells.length; j > 0;) {
			var cell = cells[--j];
			Calendar.removeClass(cell, "hilite");
			Calendar.removeClass(cell, "active");
		}
	}
	this.element.style.display = "block";
	this.hidden = false;
	if (this.isPopup) {
		window._dynarch_popupCalendar = this;
		Calendar.addEvent(document, "keydown", Calendar._keyEvent);
		Calendar.addEvent(document, "keypress", Calendar._keyEvent);
		Calendar.addEvent(document, "mousedown", Calendar._checkCalendar);
	}
	this.hideShowCovered();
};

/**
*  Hides the calendar.  Also removes any "hilite" from the class of any TD
*  element.
*/
Calendar.prototype.hide = function () {
	if (this.isPopup) {
		Calendar.removeEvent(document, "keydown", Calendar._keyEvent);
		Calendar.removeEvent(document, "keypress", Calendar._keyEvent);
		Calendar.removeEvent(document, "mousedown", Calendar._checkCalendar);
	}
	this.element.style.display = "none";
	this.hidden = true;
	this.hideShowCovered();
};

/**
*  Shows the calendar at a given absolute position (beware that, depending on
*  the calendar element style -- position property -- this might be relative
*  to the parent's containing rectangle).
*/
Calendar.prototype.showAt = function (x, y) {
	var s = this.element.style;
	s.left = x + "px";
	s.top = y + "px";
	this.show();
};

/** Shows the calendar near a given element. */
Calendar.prototype.showAtElement = function (el, opts) {
	var self = this;
	var p = Calendar.getAbsolutePos(el);
	if (!opts || typeof opts != "string") {
		this.showAt(p.x, p.y + el.offsetHeight);
		return true;
	}
	function fixPosition(box) {
		if (box.x < 0)
		box.x = 0;
		if (box.y < 0)
		box.y = 0;
		var cp = document.createElement("div");
		var s = cp.style;
		s.position = "absolute";
		s.right = s.bottom = s.width = s.height = "0px";
		document.body.appendChild(cp);
		var br = Calendar.getAbsolutePos(cp);
		document.body.removeChild(cp);
		if (Calendar.is_ie) {
			br.y += document.body.scrollTop;
			br.x += document.body.scrollLeft;
		} else {
			br.y += window.scrollY;
			br.x += window.scrollX;
		}
		var tmp = box.x + box.width - br.x;
		if (tmp > 0) box.x -= tmp;
		tmp = box.y + box.height - br.y;
		if (tmp > 0) box.y -= tmp;
	};
	this.element.style.display = "block";
	Calendar.continuation_for_the_fucking_khtml_browser = function() {
		var w = self.element.offsetWidth;
		var h = self.element.offsetHeight;
		self.element.style.display = "none";
		var valign = opts.substr(0, 1);
		var halign = "l";
		if (opts.length > 1) {
			halign = opts.substr(1, 1);
		}
		// vertical alignment
		switch (valign) {
			case "T": p.y -= h; break;
			case "B": p.y += el.offsetHeight; break;
			case "C": p.y += (el.offsetHeight - h) / 2; break;
			case "t": p.y += el.offsetHeight - h; break;
			case "b": break; // already there
		}
		// horizontal alignment
		switch (halign) {
			case "L": p.x -= w; break;
			case "R": p.x += el.offsetWidth; break;
			case "C": p.x += (el.offsetWidth - w) / 2; break;
			case "l": p.x += el.offsetWidth - w; break;
			case "r": break; // already there
		}
		p.width = w;
		p.height = h + 40;
		self.monthsCombo.style.display = "none";
		fixPosition(p);
		self.showAt(p.x, p.y);
	};
	if (Calendar.is_khtml)
	setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()", 10);
	else
	Calendar.continuation_for_the_fucking_khtml_browser();
};

/** Customizes the date format. */
Calendar.prototype.setDateFormat = function (str) {
	this.dateFormat = str;
};

/** Customizes the tooltip date format. */
Calendar.prototype.setTtDateFormat = function (str) {
	this.ttDateFormat = str;
};

/**
*  Tries to identify the date represented in a string.  If successful it also
*  calls this.setDate which moves the calendar to the given date.
*/
Calendar.prototype.parseDate = function(str, fmt) {
	if (!fmt)
	fmt = this.dateFormat;
	this.setDate(Date.parseDate(str, fmt));
};

Calendar.prototype.hideShowCovered = function () {
	if (!Calendar.is_ie && !Calendar.is_opera)
	return;
	function getVisib(obj){
		var value = obj.style.visibility;
		if (!value) {
			if (document.defaultView && typeof (document.defaultView.getComputedStyle) == "function") { // Gecko, W3C
				if (!Calendar.is_khtml)
				value = document.defaultView.
				getComputedStyle(obj, "").getPropertyValue("visibility");
				else
				value = '';
			} else if (obj.currentStyle) { // IE
				value = obj.currentStyle.visibility;
			} else
			value = '';
		}
		return value;
	};

	var tags = new Array("applet", "iframe", "select");
	var el = this.element;

	var p = Calendar.getAbsolutePos(el);
	var EX1 = p.x;
	var EX2 = el.offsetWidth + EX1;
	var EY1 = p.y;
	var EY2 = el.offsetHeight + EY1;

	for (var k = tags.length; k > 0; ) {
		var ar = document.getElementsByTagName(tags[--k]);
		var cc = null;

		for (var i = ar.length; i > 0;) {
			cc = ar[--i];

			p = Calendar.getAbsolutePos(cc);
			var CX1 = p.x;
			var CX2 = cc.offsetWidth + CX1;
			var CY1 = p.y;
			var CY2 = cc.offsetHeight + CY1;

			if (this.hidden || (CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) {
				if (!cc.__msh_save_visibility) {
					cc.__msh_save_visibility = getVisib(cc);
				}
				cc.style.visibility = cc.__msh_save_visibility;
			} else {
				if (!cc.__msh_save_visibility) {
					cc.__msh_save_visibility = getVisib(cc);
				}
				cc.style.visibility = "hidden";
			}
		}
	}
};

/** Internal function; it displays the bar with the names of the weekday. */
Calendar.prototype._displayWeekdays = function () {
	var fdow = this.firstDayOfWeek;
	var cell = this.firstdayname;
	var weekend = Calendar._TT["WEEKEND"];
	for (var i = 0; i < 7; ++i) {
		cell.className = "day name";
		var realday = (i + fdow) % 7;
		if (i) {
			cell.ttip = Calendar._TT["DAY_FIRST"].replace("%s", Calendar._DN[realday]);
			cell.navtype = 100;
			cell.calendar = this;
			cell.fdow = realday;
			//Calendar._add_evs(cell);
		}
		if (weekend.indexOf(realday.toString()) != -1) {
			Calendar.addClass(cell, "weekend");
		}
		cell.innerHTML = Calendar._SDN[(i + fdow) % 7];
		cell = cell.nextSibling;
	}
};

/** Internal function.  Hides all combo boxes that might be displayed. */
Calendar.prototype._hideCombos = function () {
	this.monthsCombo.style.display = "none";
	this.yearsCombo.style.display = "none";
};

/** Internal function.  Starts dragging the element. */
Calendar.prototype._dragStart = function (ev) {
	if (this.dragging) {
		return;
	}
	this.dragging = true;
	var posX;
	var posY;
	if (Calendar.is_ie) {
		posY = window.event.clientY + document.body.scrollTop;
		posX = window.event.clientX + document.body.scrollLeft;
	} else {
		posY = ev.clientY + window.scrollY;
		posX = ev.clientX + window.scrollX;
	}
	var st = this.element.style;
	this.xOffs = posX - parseInt(st.left);
	this.yOffs = posY - parseInt(st.top);
	with (Calendar) {
		addEvent(document, "mousemove", calDragIt);
		addEvent(document, "mouseup", calDragEnd);
	}
};

// BEGIN: DATE OBJECT PATCHES

/** Adds the number of days array to the Date object. */
Date._MD = new Array(31,28,31,30,31,30,31,31,30,31,30,31);

/** Constants used for time computations */
Date.SECOND = 1000 /* milliseconds */;
Date.MINUTE = 60 * Date.SECOND;
Date.HOUR   = 60 * Date.MINUTE;
Date.DAY    = 24 * Date.HOUR;
Date.WEEK   =  7 * Date.DAY;

Date.parseDate = function(str, fmt) {
	var today = new Date();
	var y = 0;
	var m = -1;
	var d = 0;
	var a = str.split(/\W+/);
	var b = fmt.match(/%./g);
	var i = 0, j = 0;
	var hr = 0;
	var min = 0;
	for (i = 0; i < a.length; ++i) {
		if (!a[i])
		continue;
		switch (b[i]) {
			case "%d":
			case "%e":
			d = parseInt(a[i], 10);
			break;

			case "%m":
			m = parseInt(a[i], 10) - 1;
			break;

			case "%Y":
			case "%y":
			y = parseInt(a[i], 10);
			(y < 100) && (y += (y > 29) ? 1900 : 2000);
			break;

			case "%b":
			case "%B":
			for (j = 0; j < 12; ++j) {
				if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; }
			}
			break;

			case "%H":
			case "%I":
			case "%k":
			case "%l":
			hr = parseInt(a[i], 10);
			break;

			case "%P":
			case "%p":
			if (/pm/i.test(a[i]) && hr < 12)
			hr += 12;
			else if (/am/i.test(a[i]) && hr >= 12)
			hr -= 12;
			break;

			case "%M":
			min = parseInt(a[i], 10);
			break;
		}
	}
	if (isNaN(y)) y = today.getFullYear();
	if (isNaN(m)) m = today.getMonth();
	if (isNaN(d)) d = today.getDate();
	if (isNaN(hr)) hr = today.getHours();
	if (isNaN(min)) min = today.getMinutes();
	if (y != 0 && m != -1 && d != 0)
	return new Date(y, m, d, hr, min, 0);
	y = 0; m = -1; d = 0;
	for (i = 0; i < a.length; ++i) {
		if (a[i].search(/[a-zA-Z]+/) != -1) {
			var t = -1;
			for (j = 0; j < 12; ++j) {
				if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; }
			}
			if (t != -1) {
				if (m != -1) {
					d = m+1;
				}
				m = t;
			}
		} else if (parseInt(a[i], 10) <= 12 && m == -1) {
			m = a[i]-1;
		} else if (parseInt(a[i], 10) > 31 && y == 0) {
			y = parseInt(a[i], 10);
			(y < 100) && (y += (y > 29) ? 1900 : 2000);
		} else if (d == 0) {
			d = a[i];
		}
	}
	if (y == 0)
	y = today.getFullYear();
	if (m != -1 && d != 0)
	return new Date(y, m, d, hr, min, 0);
	return today;
};

/** Returns the number of days in the current month */
Date.prototype.getMonthDays = function(month) {
	var year = this.getFullYear();
	if (typeof month == "undefined") {
		month = this.getMonth();
	}
	if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) {
		return 29;
	} else {
		return Date._MD[month];
	}
};

/** Returns the number of day in the year. */
Date.prototype.getDayOfYear = function() {
	var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
	var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
	var time = now - then;
	return Math.floor(time / Date.DAY);
};

/** Returns the number of the week in year, as defined in ISO 8601. */
Date.prototype.getWeekNumber = function() {
	var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
	var DoW = d.getDay();
	d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu
	var ms = d.valueOf(); // GMT
	d.setMonth(0);
	d.setDate(4); // Thu in Week 1
	return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
};

/** Checks date and time equality */
Date.prototype.equalsTo = function(date) {
	return ((this.getFullYear() == date.getFullYear()) &&
	(this.getMonth() == date.getMonth()) &&
	(this.getDate() == date.getDate()) &&
	(this.getHours() == date.getHours()) &&
	(this.getMinutes() == date.getMinutes()));
};

/** Set only the year, month, date parts (keep existing time) */
Date.prototype.setDateOnly = function(date) {
	var tmp = new Date(date);
	this.setDate(1);
	this.setFullYear(tmp.getFullYear());
	this.setMonth(tmp.getMonth());
	this.setDate(tmp.getDate());
};

/** Prints the date in a string according to the given format. */
Date.prototype.print = function (str) {
	var m = this.getMonth();
	var d = this.getDate();
	var y = this.getFullYear();
	var wn = this.getWeekNumber();
	var w = this.getDay();
	var s = {};
	var hr = this.getHours();
	var pm = (hr >= 12);
	var ir = (pm) ? (hr - 12) : hr;
	var dy = this.getDayOfYear();
	if (ir == 0)
	ir = 12;
	var min = this.getMinutes();
	var sec = this.getSeconds();
	s["%a"] = Calendar._SDN[w]; // abbreviated weekday name [FIXME: I18N]
	s["%A"] = Calendar._DN[w]; // full weekday name
	s["%b"] = Calendar._SMN[m]; // abbreviated month name [FIXME: I18N]
	s["%B"] = Calendar._MN[m]; // full month name
	// FIXME: %c : preferred date and time representation for the current locale
	s["%C"] = 1 + Math.floor(y / 100); // the century number
	s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31)
	s["%e"] = d; // the day of the month (range 1 to 31)
	// FIXME: %D : american date style: %m/%d/%y
	// FIXME: %E, %F, %G, %g, %h (man strftime)
	s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format)
	s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format)
	s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366)
	s["%k"] = hr;		// hour, range 0 to 23 (24h format)
	s["%l"] = ir;		// hour, range 1 to 12 (12h format)
	s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12
	s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59
	s["%n"] = "\n";		// a newline character
	s["%p"] = pm ? "PM" : "AM";
	s["%P"] = pm ? "pm" : "am";
	// FIXME: %r : the time in am/pm notation %I:%M:%S %p
	// FIXME: %R : the time in 24-hour notation %H:%M
	s["%s"] = Math.floor(this.getTime() / 1000);
	s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59
	s["%t"] = "\t";		// a tab character
	// FIXME: %T : the time in 24-hour notation (%H:%M:%S)
	s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn;
	s["%u"] = w + 1;	// the day of the week (range 1 to 7, 1 = MON)
	s["%w"] = w;		// the day of the week (range 0 to 6, 0 = SUN)
	// FIXME: %x : preferred date representation for the current locale without the time
	// FIXME: %X : preferred time representation for the current locale without the date
	s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99)
	s["%Y"] = y;		// year with the century
	s["%%"] = "%";		// a literal '%' character

	var re = /%./g;
	if (!Calendar.is_ie5 && !Calendar.is_khtml)
	return str.replace(re, function (par) { return s[par] || par; });

	var a = str.match(re);
	for (var i = 0; i < a.length; i++) {
		var tmp = s[a[i]];
		if (tmp) {
			re = new RegExp(a[i], 'g');
			str = str.replace(re, tmp);
		}
	}

	return str;
};

if ( !Date.prototype.__msh_oldSetFullYear ) {
	Date.prototype.__msh_oldSetFullYear = Date.prototype.setFullYear;
	Date.prototype.setFullYear = function(y) {
		var d = new Date(this);
		d.__msh_oldSetFullYear(y);
		if (d.getMonth() != this.getMonth())
		this.setDate(28);
		this.__msh_oldSetFullYear(y);
	}
}

// END: DATE OBJECT PATCHES


// global object that remembers the calendar
window._dynarch_popupCalendar = null;


/* FILE: modules/mod_scripts/calender-en.js*/
// ** I18N

// Calendar EN language
// Author: Mihai Bazon, <mihai_bazon@yahoo.com>
// Encoding: any
// Distributed under the same terms as the calendar itself.

// For translators: please use UTF-8 if possible.  We strongly believe that
// Unicode is the answer to a real internationalized world.  Also please
// include your contact information in the header, as can be seen above.

// full day names
Calendar._DN = new Array
("Sunday",
 "Monday",
 "Tuesday",
 "Wednesday",
 "Thursday",
 "Friday",
 "Saturday",
 "Sunday");

// Please note that the following array of short day names (and the same goes
// for short month names, _SMN) isn't absolutely necessary.  We give it here
// for exemplification on how one can customize the short day names, but if
// they are simply the first N letters of the full name you can simply say:
//
//   Calendar._SDN_len = N; // short day name length
//   Calendar._SMN_len = N; // short month name length
//
// If N = 3 then this is not needed either since we assume a value of 3 if not
// present, to be compatible with translation files that were written before
// this feature.

// short day names
Calendar._SDN = new Array
("Sun",
 "Mon",
 "Tue",
 "Wed",
 "Thu",
 "Fri",
 "Sat",
 "Sun");

// First day of the week. "0" means display Sunday first, "1" means display
// Monday first, etc.
Calendar._FD = 0;

// full month names
Calendar._MN = new Array
("January",
 "February",
 "March",
 "April",
 "May",
 "June",
 "July",
 "August",
 "September",
 "October",
 "November",
 "December");

// short month names
Calendar._SMN = new Array
("Jan",
 "Feb",
 "Mar",
 "Apr",
 "May",
 "Jun",
 "Jul",
 "Aug",
 "Sep",
 "Oct",
 "Nov",
 "Dec");

// tooltips
Calendar._TT = {};
Calendar._TT["INFO"] = "About the calendar";

Calendar._TT["ABOUT"] =
"DHTML Date/Time Selector\n" +
"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-)
"For latest version visit: http://www.dynarch.com/projects/calendar/\n" +
"Distributed under GNU LGPL.  See http://gnu.org/licenses/lgpl.html for details." +
"\n\n" +
"Date selection:\n" +
"- Use the \xab, \xbb buttons to select year\n" +
"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" +
"- Hold mouse button on any of the above buttons for faster selection.";
Calendar._TT["ABOUT_TIME"] = "\n\n" +
"Time selection:\n" +
"- Click on any of the time parts to increase it\n" +
"- or Shift-click to decrease it\n" +
"- or click and drag for faster selection.";

Calendar._TT["PREV_YEAR"] = "Prev. year";
Calendar._TT["PREV_MONTH"] = "Prev. month";
Calendar._TT["GO_TODAY"] = "Go Today";
Calendar._TT["NEXT_MONTH"] = "Next month";
Calendar._TT["NEXT_YEAR"] = "Next year";
Calendar._TT["SEL_DATE"] = "&nbsp;";
Calendar._TT["DRAG_TO_MOVE"] = "Drag to move";
Calendar._TT["PART_TODAY"] = " (today)";

// the following is to inform that "%s" is to be the first day of week
// %s will be replaced with the day name.
Calendar._TT["DAY_FIRST"] = "Display %s first";

// This may be locale-dependent.  It specifies the week-end days, as an array
// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1
// means Monday, etc.
Calendar._TT["WEEKEND"] = "0,6";

Calendar._TT["CLOSE"] = "Close";
Calendar._TT["TODAY"] = "Today";
Calendar._TT["TIME_PART"] = "(Shift-)Click or drag to change value";

// date formats
Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d";
Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e";

Calendar._TT["WK"] = "wk";
Calendar._TT["TIME"] = "Time:";


/* FILE: modules/mod_scripts/calender-setup.js*/
/*  Copyright Mihai Bazon, 2002, 2003  |  http://dynarch.com/mishoo/
 * ---------------------------------------------------------------------------
 *
 * The DHTML Calendar
 *
 * Details and latest version at:
 * http://dynarch.com/mishoo/calendar.epl
 *
 * This script is distributed under the GNU Lesser General Public License.
 * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
 *
 * This file defines helper functions for setting up the calendar.  They are
 * intended to help non-programmers get a working calendar on their site
 * quickly.  This script should not be seen as part of the calendar.  It just
 * shows you what one can do with the calendar, while in the same time
 * providing a quick and simple method for setting it up.  If you need
 * exhaustive customization of the calendar creation process feel free to
 * modify this code to suit your needs (this is recommended and much better
 * than modifying calendar.js itself).
 */

// $Id: calender-setup.js,v 1.2 2007-07-10 09:05:52 chogori Exp $

/**
 *  This function "patches" an input field (or other element) to use a calendar
 *  widget for date selection.
 *
 *  The "params" is a single object that can have the following properties:
 *
 *    prop. name   | description
 *  -------------------------------------------------------------------------------------------------
 *   inputField    | the ID of an input field to store the date
 *   displayArea   | the ID of a DIV or other element to show the date
 *   button        | ID of a button or other element that will trigger the calendar
 *   eventName     | event that will trigger the calendar, without the "on" prefix (default: "click")
 *   ifFormat      | date format that will be stored in the input field
 *   daFormat      | the date format that will be used to display the date in displayArea
 *   singleClick   | (true/false) wether the calendar is in single click mode or not (default: true)
 *   firstDay      | numeric: 0 to 6.  "0" means display Sunday first, "1" means display Monday first, etc.
 *   align         | alignment (default: "Br"); if you don't know what's this see the calendar documentation
 *   range         | array with 2 elements.  Default: [1900, 2999] -- the range of years available
 *   weekNumbers   | (true/false) if it's true (default) the calendar will display week numbers
 *   flat          | null or element ID; if not null the calendar will be a flat calendar having the parent with the given ID
 *   flatCallback  | function that receives a JS Date object and returns an URL to point the browser to (for flat calendar)
 *   disableFunc   | function that receives a JS Date object and should return true if that date has to be disabled in the calendar
 *   onSelect      | function that gets called when a date is selected.  You don't _have_ to supply this (the default is generally okay)
 *   onClose       | function that gets called when the calendar is closed.  [default]
 *   onUpdate      | function that gets called after the date is updated in the input field.  Receives a reference to the calendar.
 *   date          | the date that the calendar will be initially displayed to
 *   showsTime     | default: false; if true the calendar will include a time selector
 *   timeFormat    | the time format; can be "12" or "24", default is "12"
 *   electric      | if true (default) then given fields/date areas are updated for each move; otherwise they're updated only on close
 *   step          | configures the step of the years in drop-down boxes; default: 2
 *   position      | configures the calendar absolute position; default: null
 *   cache         | if "true" (but default: "false") it will reuse the same calendar object, where possible
 *   showOthers    | if "true" (but default: "false") it will show days from other months too
 *
 *  None of them is required, they all have default values.  However, if you
 *  pass none of "inputField", "displayArea" or "button" you'll get a warning
 *  saying "nothing to setup".
 */
Calendar.setup = function (params) {
	function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };

	param_default("inputField",     null);
	param_default("displayArea",    null);
	param_default("button",         null);
	param_default("eventName",      "click");
	param_default("ifFormat",       "%Y/%m/%d");
	param_default("daFormat",       "%Y/%m/%d");
	param_default("singleClick",    true);
	param_default("disableFunc",    null);
	param_default("dateStatusFunc", params["disableFunc"]);	// takes precedence if both are defined
	param_default("dateText",       null);
	param_default("firstDay",       null);
	param_default("align",          "Br");
	param_default("range",          [1900, 2999]);
	param_default("weekNumbers",    true);
	param_default("flat",           null);
	param_default("flatCallback",   null);
	param_default("onSelect",       null);
	param_default("onClose",        null);
	param_default("onUpdate",       null);
	param_default("date",           null);
	param_default("showsTime",      false);
	param_default("timeFormat",     "24");
	param_default("electric",       true);
	param_default("step",           2);
	param_default("position",       null);
	param_default("cache",          false);
	param_default("showOthers",     false);
	param_default("multiple",       null);

	var tmp = ["inputField", "displayArea", "button"];
	for (var i in tmp) {
		if (typeof params[tmp[i]] == "string") {
			params[tmp[i]] = document.getElementById(params[tmp[i]]);
		}
	}
	if (!(params.flat || params.multiple || params.inputField || params.displayArea || params.button)) {
		alert("Calendar.setup:\n  Nothing to setup (no fields found).  Please check your code");
		return false;
	}

	function onSelect(cal) {
		var p = cal.params;
		var update = (cal.dateClicked || p.electric);
		if (update && p.inputField) {
			p.inputField.value = cal.date.print(p.ifFormat);
			if (typeof p.inputField.onchange == "function")
				p.inputField.onchange();
		}
		if (update && p.displayArea)
			p.displayArea.innerHTML = cal.date.print(p.daFormat);
		if (update && typeof p.onUpdate == "function")
			p.onUpdate(cal);
		if (update && p.flat) {
			if (typeof p.flatCallback == "function")
				p.flatCallback(cal);
		}
		if (update && p.singleClick && cal.dateClicked)
			cal.callCloseHandler();
	};

	if (params.flat != null) {
		if (typeof params.flat == "string")
			params.flat = document.getElementById(params.flat);
		if (!params.flat) {
			alert("Calendar.setup:\n  Flat specified but can't find parent.");
			return false;
		}
		var cal = new Calendar(params.firstDay, params.date, params.onSelect || onSelect);
		cal.showsOtherMonths = params.showOthers;
		cal.showsTime = params.showsTime;
		cal.time24 = (params.timeFormat == "24");
		cal.params = params;
		cal.weekNumbers = params.weekNumbers;
		cal.setRange(params.range[0], params.range[1]);
		cal.setDateStatusHandler(params.dateStatusFunc);
		cal.getDateText = params.dateText;
		if (params.ifFormat) {
			cal.setDateFormat(params.ifFormat);
		}
		if (params.inputField && typeof params.inputField.value == "string") {
			cal.parseDate(params.inputField.value);
		}
		cal.create(params.flat);
		cal.show();
		return false;
	}

	var triggerEl = params.button || params.displayArea || params.inputField;
	triggerEl["on" + params.eventName] = function() {
		var dateEl = params.inputField || params.displayArea;
		var dateFmt = params.inputField ? params.ifFormat : params.daFormat;
		var mustCreate = false;
		var cal = window.calendar;
		if (dateEl)
			params.date = Date.parseDate(dateEl.value || dateEl.innerHTML, dateFmt);
		if (!(cal && params.cache)) {
			window.calendar = cal = new Calendar(params.firstDay,
							     params.date,
							     params.onSelect || onSelect,
							     params.onClose || function(cal) { cal.hide(); });
			cal.showsTime = params.showsTime;
			cal.time24 = (params.timeFormat == "24");
			cal.weekNumbers = params.weekNumbers;
			mustCreate = true;
		} else {
			if (params.date)
				cal.setDate(params.date);
			cal.hide();
		}
		if (params.multiple) {
			cal.multiple = {};
			for (var i = params.multiple.length; --i >= 0;) {
				var d = params.multiple[i];
				var ds = d.print("%Y%m%d");
				cal.multiple[ds] = d;
			}
		}
		cal.showsOtherMonths = params.showOthers;
		cal.yearStep = params.step;
		cal.setRange(params.range[0], params.range[1]);
		cal.params = params;
		cal.setDateStatusHandler(params.dateStatusFunc);
		cal.getDateText = params.dateText;
		cal.setDateFormat(dateFmt);
		if (mustCreate)
			cal.create();
		cal.refresh();
		if (!params.position)
			cal.showAtElement(params.button || params.displayArea || params.inputField, params.align);
		else
			cal.showAt(params.position[0], params.position[1]);
		return false;
	};

	return cal;
};


/* FILE: modules/mod_scripts/calender-load.js*/
/* Callback function for on-select of a date in the calendar */
function selectHandler(calendar, date) {
   if(calendar == null || !calendar.dateClicked) {
       return;
   }

   calendar.sel.value = date;
   if(calendar.sel.onchange) {
       calendar.sel.onchange();
   }
	var productElement = document.getElementById("hide_on_calendar_click");
	if (productElement != null)
	{
		setDisplay('hide_on_calendar_click','block');
	}  
   calendar.hide();

   if ((document.getElementById("pickup_time")) && (document.getElementById("dropoff_time")))
       calcDaysDifference();
}

/* Callback function for on-close of the calendar */
function closeHandler(calendar) {
	
   if(calendar == null) {
       return;
   }
	var productElement = document.getElementById("hide_on_calendar_click");
	if (productElement != null)
	{
		setDisplay('hide_on_calendar_click','block');
	}
   calendar.destroy();
   calendar == null;
}

function showCalendarById(id) {
   var elem = document.getElementById(id + "_date");
   var button = document.getElementById(id + "_button");   
   showCalendar(elem, button);
}

function showCalendar(elem, button) {
   if(calendar != null) {
       calendar.destroy();
       calendar = null;
   }

   if(elem == null) {
       alert("The supplied input field cannot be found");
       return;
   }
   if(elem == null) {
       alert("The supplied button cannot be found");
       return;
   }

   var calendar = new Calendar(true, null, selectHandler, closeHandler);
   calendar.setDateFormat("%d-%m-%Y");
   calendar.sel = elem;
   calendar.create();
   calendar.setDate(getDateFromElement(elem));

   calendar.showAtElement(button, "BR");
}

function getDateFromElement(elem) {
   var date = new Date();
   if(elem.value != null) {
       var pieces = elem.value.split("-");
       if(pieces != null && pieces.length == 3) {
        	date.setDate(1);   
       		date.setFullYear(pieces[2]);
           	date.setMonth(parseInt(pieces[1],10) - 1);
           	date.setDate(pieces[0]);   
       }
   }
   return date;
}


var dayMs = 1000 * 60 * 60 * 24;

//calculate the difference in the pickup & dropoff dates on the step_location view
function calcDaysDifference() {
      //extract the values from the date objects

   //**pickup datetime section
       var pickUpDate = document.getElementById("pickup_date");           var pickUpTime = document.getElementById("pickup_time");

       //extract the date contents off the format dd-mm-yyyy
   var yearElem = pickUpDate.value.substring(pickUpDate.value.lastIndexOf("-") + 1);
   var monthElem = (pickUpDate.value.substring(pickUpDate.value.indexOf("-") + 1, pickUpDate.value.indexOf("-", pickUpDate.value.indexOf("-") + 1))) - 1;
   var dayElem = pickUpDate.value.substring(0, pickUpDate.value.indexOf("-"));
   var hourElem = pickUpTime.value.substring(0, pickUpTime.value.indexOf(":"));
   var minElem = pickUpTime.value.substring(pickUpTime.value.lastIndexOf(":") + 1);

       //create a new date off the extracted date values
       var startdate = new Date(0);
   startdate.setFullYear(yearElem);
   startdate.setMonth(monthElem);
   startdate.setDate(dayElem);
   startdate.setHours(hourElem);
   startdate.setMinutes(minElem);

   //**drop off datetime section
   var dropOffDate = document.getElementById("dropoff_date");
       var dropOffTime = document.getElementById("dropoff_time");
          //extract the date contents off the format dd-mm-yyyy
   yearElem = dropOffDate.value.substring(dropOffDate.value.lastIndexOf("-") + 1);
   monthElem = (dropOffDate.value.substring(dropOffDate.value.indexOf("-") + 1, dropOffDate.value.indexOf("-", dropOffDate.value.indexOf("-") + 1))) - 1;
   dayElem = dropOffDate.value.substring(0, dropOffDate.value.indexOf("-"));
   hourElem = dropOffTime.value.substring(0, dropOffTime.value.indexOf(":"));
   minElem = dropOffTime.value.substring(dropOffTime.value.lastIndexOf(":") + 1);

   //create a new date off the extracted date values
       var enddate = new Date(0);
       enddate.setFullYear(yearElem);
   enddate.setMonth(monthElem);
   enddate.setDate(dayElem);
   enddate.setHours(hourElem);
   enddate.setMinutes(minElem);

   //get the difference in days between the two dates
       var diff = calcdays(startdate, enddate);

       //if negative days are returned, set the dropoff date = pickupdate + 7days
       if(diff < 0) {

           var timeDiff = 1000 * 60 * 60 * 24 * 7;

           enddate.setTime(startdate.getTime() + timeDiff);

           var strEndDate = enddate.getDate() +"-"+ (enddate.getMonth() + 1) +"-"+ enddate.getFullYear();

           dropOffDate.value = strEndDate;

           //set the number of days
       document.getElementById("numberOfDays").value = calcdays(startdate, enddate);                      }

   else {
           //set the number of days
           document.getElementById("numberOfDays").value = diff;
   }
}

//calculate the difference between the two dates
function calcdays(start, end) {
       var diff = end.getTime() - start.getTime();
       var msPday = 1000 * 60 * 60 * 24;
       diff = (diff / msPday) + (diff % msPday > 0 ? 1 : 0);

       return Math.floor(diff);
}







/* FILE: modules/mod_scripts/validation.js*/
// If no SAST date was set, default to the clients date. This prevents things from breaking
if(!sastDate) {
    var sastDate = new Date();
}
var msPday = 1000 * 60 * 60 * 24;
var initialDaysDiff = 3;

//////////////////////////
//CREDIT CARD VALIDATION//
//////////////////////////
//**IN USE**//
function CreditCardValidation(card_number,return_field){
    var validator = new MOD10Validator();
    var type = validator.getCardInfo(card_number);
    if(type == null) {
        return "invalid";
    } else {

        var cardTypeElem = getElement('selectCardType');

        var cardType = new Array();
        cardType[0] = new Array("MC","MASTERCARD","Mastercard");
        cardType[1] = new Array("VI","VISA","Visa");
        cardType[2] = new Array("AX","AMEX","American Express");
        cardType[3] = new Array("DN","DINERS","Diners Club");

        return_field.value
        for(var i = 0; i < cardType.length; i ++){
            if (cardType[i][0] == return_field.value){
                if(type.type == cardType[i][1]){
                    return "valid";
                }
            }
        }
        return "invalid_type";
    }
}

//**IN USE**//
function MOD10Validator() {
    // Card type class used to store card info
    function CardType(prefix, length, type) {
        this.prefix = prefix;
        this.length = length;
        this.type = type;
    }

    this.cardTypes = new Array();

    this.register = function(type, prefix, length) {
        this.cardTypes.push(new CardType(prefix, length, type));
    }

    // register known card types
    this.register('MASTERCARD', '51', 16);
    this.register('MASTERCARD', '52', 16);
    this.register('MASTERCARD', '53', 16);
    this.register('MASTERCARD', '54', 16);
    this.register('MASTERCARD', '55', 16);
    this.register('VISA', '4', 13);
    this.register('VISA', '4', 16);
    this.register('AMEX', '34', 15);
    this.register('AMEX', '37', 15);
    this.register('DINERS', '300', 14);
    this.register('DINERS', '301', 14);
    this.register('DINERS', '302', 14);
    this.register('DINERS', '303', 14);
    this.register('DINERS', '304', 14);
    this.register('DINERS', '305', 14);
    this.register('DINERS', '36', 14);
    this.register('DINERS', '38', 14);
    this.register('DISCOVERY', '6011', 16);

    // Check LUHN formula against number
    this.isMOD10 = function(number) {
        number = new String(number);
        var total = 0;

        var even = false;
        for(var i = number.length - 1; i >= 0; i--) {
            var n = parseInt(number.charAt(i),10);

            if(even) {
                var d = n * 2;
                total += (d % 10) + Math.floor(d / 10);
            } else {
                total += n;
            }

            even = !even;
        }

        return total % 10 == 0;
    }

    // Loops registered types, doing comparisons. Returns null on an invalid number.
    this.getCardInfo = function(number) {
        number = new String(number);

        var info = null;
        var check = /^\d+$/;
        if(check.test(number)) {
            for(var i = 0; i < this.cardTypes.length; i++) {
                var type = this.cardTypes[i];
                if(type.length != number.length) {
                    continue;
                }

                if(number.indexOf(type.prefix) != 0) {
                    continue;
                }

                if(this.isMOD10(number)) {
                    info = type;
                    break;
                }
            }

        }

        return info;
    }
}


//////////////////////
//GENERAL VALIDATION//
//////////////////////
//**IN USE**//
function regexMatch(string, regex) {
    var match = string.match(regex);
    if(match == null) {
        return false;
    }
    return match == null ? false : match[0] == string;
}
//**IN USE**//
function trim(string) {
    return string.replace(/^\s*(.*?)\s*$/, '$1');
}
//**IN USE**//
function charTrap(regex, evt) {
    if(evt){
        var ch = evt.which ? evt.which : (window.event == null ? 13 : window.event.keyCode);
        if(ch == 8 || ch == 13) { // 8: bspace, 13: enter
            return true;
        }

        var char = String.fromCharCode(ch);

        return regexMatch(char, new RegExp(regex));
    }else{
        return;
    }

}

//**IN USE**//
function validateUserInfo(elements){
    var msgs = new Array();

    //if using direct bill then no need to check for credit card details

    if(!elements['chkDirectBill'] || !elements['chkDirectBill'].checked){

        if(CreditCardValidation(elements['txtCardNumber'].value,elements['selectCardType']) == "invalid_type"){
            msgs.push("Invalid credit card type");
        }

        if(CreditCardValidation(elements['txtCardNumber'].value,elements['selectCardType']) == "invalid"){
            msgs.push("Invalid credit card number");
        }

        if (elements['txtCardCVV'].value.length != 4 && elements['selectCardType'].value == "AX"){
            msgs.push("CVV for American Express should be 4 characters");
        }

        if (elements['txtCardCVV'].value.length != 3 && elements['selectCardType'].value != "AX"){
            msgs.push("Invalid CVV");
        }

        /*			GILHAMS DATE CHECKER			*/

        var curdate = getSASTDate();
        var year = curdate.getFullYear() - 2000;
        var mnth = curdate.getMonth();
  
        if (parseInt(elements['txtCardExpiryYear'].value,10) == parseInt(year,10) && parseInt(elements['txtCardExpiryMonth'].value,10) < (parseInt(mnth,10)+1)){
            msgs.push("Your credit card has expired");
        }
    }

    if (elements['txtFirstName'].value == ""){
        msgs.push("No first name entered");
    }else if(elements['txtFirstName'].value.length > 64){
        msgs.push("Your first name is too long");
    }

    if (elements['txtSurname'].value == ""){
        msgs.push("No surname entered");
    }else if(elements['txtSurname'].value.length > 64){
        msgs.push("Your surname is too long");
    }

    if (elements['txtTelephone'].value == "" && elements['txtCellphone'].value == ""){
        msgs.push("Contact number blank");
    }else if(elements['txtTelephone'].value.length > 32){
        msgs.push("Telephone number is too long");
    }else if(elements['txtCellphone'].value.length > 32){
        msgs.push("Cellphone number is too long");
    }

    if (elements['txtEmail'].value == ""){
        msgs.push("E-mail address blank");
    }else if (!(/[^@]+@[^.]+\..*/.test(elements['txtEmail'].value))){
    	msgs.push("Invalid e-mail address");
	}

	
	if (elements['txtAddressLine1'].value == ""){
	    msgs.push("Invalid address line 1");
	}else if(elements['txtAddressLine1'].value.length > 64){
	    msgs.push("Address 1 is too long");
	}
	
	if(elements['txtAddressLine2'].value.length > 64){
	    msgs.push("Address 2 is too long");
	}
	
	if (elements['txtAddressCity'].value == ""){
	    msgs.push("Invalid address city");
	}else if(elements['txtAddressCity'].value.length > 64){
	    msgs.push("Address City is too long");
	}
	
	if (elements['txtAddressCountry'].value == ""){
	    msgs.push("Blank country");
	}
	
	if (elements['txtAddressPostalCode'].value == ""){
	    msgs.push("Invalid postal code");
	}else if(elements['txtAddressPostalCode'].value.length >= 17){
	    msgs.push("Postal code is too long");
	}
	
	if (elements['txtIdNumber'].value == ""){
	    msgs.push("Please enter a passport / id number");
	}else if(elements['txtIdNumber'].value.length > 32){
	    msgs.push("ID number is too long");
	}


	if (elements['chkTermsConditions'].checked == false){
	    msgs.push("You may only continue if you agree to the T&amp;C's");
	}
	
	return showMessages("Please enter the following values:", msgs);
}

//**IN USE**//
function is_valid_date_format(dateString,fmt){
    var match;

    switch(fmt){
        case "dd-mm-yyyy":
        match = dateString.toString().match(/^((3[0-1])|(0?[1-9])|([1-2][0-9]))-((0?[1-9])|(1[0-2]))-(20[0-9]{2})$/);
        break;
    }
    if(match != null){
        return true;
    }else{
        return false;
    }

}

//**IN USE**//
function validateProteaSearch(elements,feature){
    var msgs = new Array();

    //make sure there's no search excuted for more than 15 hotels seeing that this takes too long and times out
    if(elements['selectHotels']) {
        if(elements['selectHotels'].length > 15 && elements['selectHotels'].value == ""){
            msgs.push("Please refine your search");
        }
    }

    //if checkin date is selected
    if(elements['checkin_date'].value == "Check In" || elements['checkin_date'].value == ""){
        msgs.push("Please select a valid checkin date");
    }else if(!is_valid_date_format(elements['checkin_date'].value,'dd-mm-yyyy')){
        msgs.push("Checkin date format is invalid, should be 'dd-mm-yyyy'");
    }
    else{
        var check_in = createDate(elements['checkin_date'].value);
        if(check_in == null){
            msgs.push("Invalid checkin date");
        }
    }

    if(elements['checkout_date'].value == "Check Out" || elements['checkout_date'].value == ""){
        msgs.push("Please select a checkout date");
    }else if(!is_valid_date_format(elements['checkout_date'].value,'dd-mm-yyyy')){
        msgs.push("Checkout date format is invalid, should be 'dd-mm-yyyy'");
    }
    else{
        var check_out = createDate(elements['checkout_date'].value);
        if(check_out == null){
            msgs.push("Invalid checkout date");
        }
    }

    //if both dates are correct then
    if(check_in != null && check_out != null){
        var checkInBeforeOut = true;
        if(!dateMatch(elements['checkin_date'].value)){
            msgs.push("Invalid checkin date");
            checkInBeforeOut = false;
            alert("inv in date");
        }

        if(!dateMatch(elements['checkout_date'].value)){
            msgs.push("Invalid checkout date");
            checkInBeforeOut = false;
            alert("inv out date");
        }

        if(checkInBeforeOut){
            if(!isDateBefore(check_out, check_in)){
                msgs.push("Checkout date can not be before checkin date");
            }
            var tmp_days = diffdays(elements['checkin_date'].value,elements['checkout_date'].value,"convert");
            if(tmp_days == 0){
                msgs.push("Checkin and checkout date cannot be the same");
            }else if(tmp_days == null){
                msgs.push("something");
            }
        }
    }

    if(elements['selectRooms'].value < 1 || trim(elements['selectRooms'].value) == "Rooms"){
        msgs.push("Amount of rooms cannot be zero");
    }else if(elements['selectRooms'].value > 4){
        msgs.push("Amount of rooms cannot exceed 4");
    }else if(isNaN(elements['selectRooms'].value)){
        msgs.push("Amount of rooms needs to be a valid number from 1 to 4");
    }

    if(elements['selectAdults'].value < 1 || trim(elements['selectAdults'].value) == "Adults"){
        msgs.push("Must have at least one adult");
    }else if(elements['selectAdults'].value > 20){
        msgs.push("Amount of adults cannot exceed 20");
    }else if(isNaN(elements['selectAdults'].value)){
        msgs.push("Amount of adults needs to be a valid number from 1 to 20");
    }

    if(elements['selectKids'].value == ""){
        elements['selectKids'].value = 0;
    }else if(elements['selectKids'].value > 20){
        msgs.push("Amount of children cannot exceed 20");
    }else if(isNaN(elements['selectKids'].value)){
        msgs.push("Amount of children needs to be a valid number from 0 to 20");
    }

    var submitting = showMessages("Please enter the following values:", msgs);
    if(submitting){
        showProgressBar();
        return true;
    }
    return false;
}

//**IN USE**//
function showMessages(title, msgs) {
    if(msgs.length > 0) {
        var msg = title;
        for(var i = 0; i < msgs.length; i++) {
            msg += "\n  * " + msgs[i];
        }
        alert(msg);
        return false;
    }

    return true;
}

//////////////////
//DATE FUNCTIONS//
//////////////////
//**IN USE**//
function checkValidCheckin(check_in,check_out,number_nights){
    var msg1 = "Checkout date must be after checkin date";
    var msg2 = "You cannot book in past ";
    var msg3 = "Warning: Please note that Check In date was after the Check Out date and that the Check Out date has been pushed forward.";

    var todayDate = getSASTDate();

    var checkinDate = createDate(check_in.value);
    var checkoutDate = createDate(check_out.value);

    if(checkinDate == null) {
        return;
    }

    if(todayDate.getTime() > checkinDate.getTime()) {
        alert(msg2);

        check_in.value = 'Check In';

        updateDaysDiff(check_in.value, check_out.value, number_nights);

        return;
    }

    if(checkoutDate == null) {
        checkoutDate = dateAddDays(checkinDate, initialDaysDiff);
        check_out.value = createDateString(checkoutDate);
    }

    if(checkoutDate.getTime() <= checkinDate.getTime()) {
        alert(msg3);

        check_out.value = createDateString(dateAddDays(checkinDate, initialDaysDiff));
    }

    updateDaysDiff(check_in.value, check_out.value, number_nights);
}


//**IN USE**//
function checkValidCheckout(check_in,check_out,number_nights){
    var msg = 'Your checkout date must be after your checkin date';

    var checkinDate = createDate(check_in.value);
    var checkoutDate = createDate(check_out.value);

    if(checkinDate == null) {
        updateDaysDiff(check_in.value, check_out.value, number_nights);
        return;
    }

    if(checkoutDate.getTime() <= checkinDate.getTime()) {
        alert(msg);

        check_out.value = 'Check Out';

        updateDaysDiff(check_in.value, check_out.value, number_nights);

        return;
    }

    updateDaysDiff(check_in.value, check_out.value, number_nights);

}

//**IN USE**//
function createDate(dateString) {
    var date = dateString;
    if(dateString.indexOf("-") == -1){
        dateString = date[0]+date[1]+"-"+date[2]+date[3]+"-"+date[4]+date[5]+date[6]+date[7];
    }

    var match = dateString.match(/^((3[0-1])|(0?[1-9])|([1-2][0-9]))-((0?[1-9])|(1[0-2]))-(20[0-9]{2})$/);

    if(match == null) {
        return null;
    }

    var year = new Number(match[8]);
    var month = new Number(match[5]) - 1;
    var day = new Number(match[1]);

    var date = new Date();
    date.setDate(1); // needed to prevent the rolling of months towards the end of some months...
    date.setFullYear(year);
    date.setMonth(month);
    date.setDate(day);
    date.setHours(0);
    date.setMinutes(0);
    date.setSeconds(0);

    // Make sure input string is actually valid... i.e. not entering 31 days in feb, causing rollover months.
    if(date.getFullYear() != year || date.getMonth() != month || date.getDate() != day) {
        return null;
    }

    return date;
}


//**IN USE**//
function isDateBefore(check_in, check_out) {
    return (check_in.getTime() - check_out.getTime()) > 0;
}


//**IN USE**//
function dateMatch(date) {
    return createDate(date) != null;
}

//**IN USE**//
function diffdays(in_date, out_date, modify) {
    //calculate the difference between the two dates
	var check_in;
    var check_out;
    if(modify == "convert"){
        //must be in format dd-mm-yyyy
        check_in = createDate(in_date);
        check_out = createDate(out_date);
    }else{
        check_in = in_date;
        check_out = out_date;
    }

    if(check_in == null || check_out == null){
        return null;
    }
    var diff = check_out.getTime() - check_in.getTime();

    diff = (diff / msPday);

    return Math.floor(diff);
}

//**IN USE**//
function calcDaysDiff(from, to) {
    var fromDate = createDate(from);
    var toDate = createDate(to);

    if(fromDate == null || toDate == null) return null;

    return Math.floor((toDate.getTime() - fromDate.getTime()) / msPday);
}

//**IN USE**//
function updateDaysDiff(from, to, daysElem) {
    var diff = calcDaysDiff(from, to);
    if(diff == null) diff = -1;

    if(diff <= 0) {
        daysElem.value = 'Number of Nights';
    } else if (diff == 1) {
        daysElem.value = '1 Night';
    } else {
        daysElem.value = diff + ' Nights';
    }
}

//**IN USE**//
function dateAddDays(date, days) {
    var newDate = new Date();
    newDate.setTime(date.getTime());
    newDate.setDate(newDate.getDate() + days);

    return newDate;
}


//**IN USE**//
function createDateString(date) {
    return padLeft(date.getDate(), 2, '0') + '-' + padLeft(date.getMonth() + 1, 2, '0') + '-' + date.getFullYear();
}


//**IN USE**//
function padLeft(str, amount, ch) {
    str = new String(str);

    while(str.length < amount) {
        str = ch + str;
    }

    return str;
}


//**IN USE**//
function getSASTDate() {
    var date = new Date();
    date.setTime(sastDate.getTime());

    return date;
}

function confirm_entry(){
	alert("TERMS AND CONDITIONS: \n\nYour credit card number serves as a guarantee for this reservation. You will be required to complete a credit card authorization form - the hotel will contact you in this regard. Should you not arrive and not cancel within 24 hours, one nights accommodation will be charged to your credit card. \n\nDuring periods of high demand some hotels may require full pre-payment. This would be non-refundable in the event of a cancellation. The hotel will contact you should this be a requirement for your reservation\n\nRates exclude 1 % Tourism Levy");
	
}


/* FILE: templates/ja_sargas/ja_transmenu/ja-transmenu.js*/
/* =================================================================================================
 * TransMenu 
 * March, 2003
 *
 * Customizable multi-level animated DHTML menus with transparency.
 *
 * Copyright 2003-2004, Aaron Boodman (www.youngpup.net)
 * =================================================================================================
 * "Can I use this?"
 * 
 * Use of this library is governed by the Creative Commons Attribution 2.0 License. You can check it 
 * out at: http://creativecommons.org/licenses/by/2.0/
 *
 * Basically: You may copy, distribute, and eat this code as you wish. But you must give me credit 
 * for writing it. You may not misrepresent yourself as the author of this code.
 * =================================================================================================
 * "It's kinda hard to read, though"
 *
 * The uncompressed, commented version of this script can be found at: 
 * http://youngpup.net/projects/transMenus
 * =================================================================================================
 * updates:
 * 04.19.04 fixed cascade problem with menus nested greater than two levels.
 * 12.23.03 added hideCurrent for menu actuators with no menus. renamed to TransMenu.
 * 04.18.03	fixed render bug in IE 5.0 Mac by removing that browser from compatibility table ;)
 *			also made gecko check a little more strict by specifying build no.
 * ============================================================================================== */



//==================================================================================================
// Configuration properties
//==================================================================================================
//==================================================================================================
TransMenu.spacerGif = "img/x.gif";                     // path to a transparent spacer gif
TransMenu.dingbatOn = "img/arrowchild-on.gif";            // path to the active sub menu dingbat
TransMenu.dingbatOff = "img/arrowchild-off.gif";          // path to the inactive sub menu dingbat
TransMenu.dingbatSize = 8;                            // size of the dingbat (square shape assumed)
TransMenu.menuPadding = 0;                             // padding between menu border and items grid
TransMenu.itemPadding = 5;                             // additional padding around each item
TransMenu.shadowSize = 2;                              // size of shadow under menu
TransMenu.shadowOffset = 3;                            // distance shadow should be offset from leading edge
TransMenu.shadowColor = "#333333";                        // color of shadow (transparency is set in CSS)
TransMenu.shadowPng = "img/grey-40.png";               // a PNG graphic to serve as the shadow for mac IE5
TransMenu.backgroundColor = "#2B98B7";                   // color of the background (transparency set in CSS)
TransMenu.backgroundPng = "img/white-90.png";          // a PNG graphic to server as the background for mac IE5
TransMenu.hideDelay = 1500;                            // number of milliseconds to wait before hiding a menu
TransMenu.slideTime = 200;                             // number of milliseconds it takes to open and close a menu
TransMenu.subpad_x = 0;								   // Horizontal Padding between top right corner of item menu and its submenu (level > 2)
TransMenu.subpad_y = -2;							   // Vertical Padding between top right corner of item menu and its submenu (level > 2)

//==================================================================================================
// Internal use properties
//==================================================================================================
TransMenu.reference = {topLeft:1,topRight:2,bottomLeft:3,bottomRight:4};
TransMenu.direction = {down:1,right:2};
TransMenu.registry = [];
TransMenu._maxZ = 100;

TransMenu.updateImgPath = function (imgPath){
	TransMenu.spacerGif = imgPath + TransMenu.spacerGif;
	TransMenu.dingbatOn = imgPath + TransMenu.dingbatOn;
	TransMenu.dingbatOff = imgPath + TransMenu.dingbatOff;
	TransMenu.shadowPng = imgPath + TransMenu.shadowPng;
	TransMenu.backgroundPng = imgPath + TransMenu.backgroundPng;
}

//==================================================================================================
// Static methods
//==================================================================================================
// supporting win ie5+, mac ie5.1+ and gecko >= mozilla 1.0
TransMenu.isSupported = function() {
        var ua = navigator.userAgent.toLowerCase();
		var pf = navigator.platform.toLowerCase();
        var an = navigator.appName;
        var r = false;

        if (ua.indexOf("gecko") > -1 && navigator.productSub >= 20020605) r = true; // gecko >= moz 1.0
        else if (an == "Microsoft Internet Explorer") {
                if (document.getElementById) { // ie5.1+ mac,win
                        if (pf.indexOf("mac") == 0) {
							r = /msie (\d(.\d*)?)/.test(ua) && Number(RegExp.$1) >= 5.1;
						}
						else r = true;
                }
        }

        return r;
}

// call this in onload once menus have been created
TransMenu.initialize = function() {
        for (var i = 0, menu = null; menu = this.registry[i]; i++) {
                menu.initialize();
        }
}

// call this in document body to write out menu html
TransMenu.renderAll = function() {
        var aMenuHtml = [];
        for (var i = 0, menu = null; menu = this.registry[i]; i++) {
                aMenuHtml[i] = menu.toString();
        }
        document.write(aMenuHtml.join(""));
}

//==================================================================================================
// TransMenu constructor (only called internally)
//==================================================================================================
// oActuator            : The thing that causes the menu to be shown when it is mousedover. Either a
//                        reference to an HTML element, or a TransMenuItem from an existing menu.
// iDirection           : The direction to slide out. One of TransMenu.direction.
// iLeft                : Left pixel offset of menu from actuator
// iTop                 : Top pixel offset of menu from actuator
// iReferencePoint      : Corner of actuator to measure from. One of TransMenu.referencePoint.
// parentMenuSet        : Menuset this menu will be added to.
//==================================================================================================
function TransMenu(oActuator, iDirection, iLeft, iTop, iReferencePoint, parentMenuSet) {
        // public methods
        this.addItem = addItem;
        this.addMenu = addMenu;
        this.toString = toString;
        this.initialize = initialize;
        this.isOpen = false;
        this.show = show;
        this.hide = hide;
        this.items = [];

        // events
        this.onactivate = new Function();       // when the menu starts to slide open
        this.ondeactivate = new Function();     // when the menu finishes sliding closed
        this.onmouseover = new Function();      // when the menu has been moused over
        this.onqueue = new Function();          // hack .. when the menu sets a timer to be closed a little while in the future
		this.ondequeue = new Function();

        // initialization
        this.index = TransMenu.registry.length;
        TransMenu.registry[this.index] = this;

        var id = "TransMenu" + this.index;
        var contentHeight = null;
        var contentWidth = null;
        var childMenuSet = null;
        var animating = false;
        var childMenus = [];
        var slideAccel = -1;
        var elmCache = null;
        var ready = false;
        var _this = this;
        var a = null;

        var pos = iDirection == TransMenu.direction.down ? "top" : "left";
        var dim = null;

        // private and public method implimentations
        function addItem(sText, sUrl, browserNav, active) {
                var item = new TransMenuItem(sText, sUrl, this, browserNav, active);
                item._index = this.items.length;
                this.items[item._index] = item;
        }

        function addMenu(oMenuItem) {
                if (!oMenuItem.parentMenu == this) throw new Error("Cannot add a menu here");

                if (childMenuSet == null) childMenuSet = new TransMenuSet(TransMenu.direction.right, TransMenu.subpad_x, TransMenu.subpad_y, TransMenu.reference.topRight);

                var m = childMenuSet.addMenu(oMenuItem);

                childMenus[oMenuItem._index] = m;
                m.onmouseover = child_mouseover;
                m.ondeactivate = child_deactivate;
                m.onqueue = child_queue;
				m.ondequeue = child_dequeue;

                return m;
        }

        function initialize() {
                initCache();
                initEvents();
                initSize();
                ready = true;
        }

        function show() {
                //dbg_dump("show");
                if (ready) {
                        _this.isOpen = true;
                        animating = true;
                        setContainerPos();
                        elmCache["clip"].style.visibility = "visible";
                        elmCache["clip"].style.zIndex = TransMenu._maxZ++;
                        //dbg_dump("maxZ: " + TransMenu._maxZ);
                        slideStart();
                        _this.onactivate();
                }
        }

        function hide() {
                if (ready) {
                        _this.isOpen = false;
                        animating = true;

                        for (var i = 0, item = null; item = elmCache.item[i]; i++) 
                                dehighlight(item);

                        if (childMenuSet) childMenuSet.hide();

                        slideStart();
                        _this.ondeactivate();
                        
                        if (!oActuator.parentMenu) {
                        	oActuator.className = oActuator.className.replace(/ jahover-active/, '');
                        	oActuator.className = oActuator.className.replace(/ jahover/, '');
                        }
                }
        }

        function setContainerPos() {
                var sub = oActuator.constructor == TransMenuItem; 
                var act = sub ? oActuator.parentMenu.elmCache["item"][oActuator._index] : oActuator; 
                var el = act;
                
                var x = 0;
                var y = 0;

                
                var minX = 0;
                var maxX = (window.innerWidth ? window.innerWidth : document.body.clientWidth) - parseInt(elmCache["clip"].style.width);
                var minY = 0;
                var maxY = (window.innerHeight ? window.innerHeight : document.body.clientHeight) - parseInt(elmCache["clip"].style.height);
				maxX = 10000;
				maxY = 10000;

                // add up all offsets... subtract any scroll offset
                while (sub ? el.parentNode.className.indexOf("transMenu") == -1 : el.offsetParent) {
                        x += el.offsetLeft;
                        y += el.offsetTop;

                        if (el.scrollLeft) x -= el.scrollLeft;
                        if (el.scrollTop) y -= el.scrollTop;
                        
                        el = el.offsetParent;
                }

                if (oActuator.constructor == TransMenuItem) {
                        x += parseInt(el.parentNode.style.left);
                        y += parseInt(el.parentNode.style.top);
                }

                switch (iReferencePoint) {
                        case TransMenu.reference.topLeft:
                                break;
                        case TransMenu.reference.topRight:
                                x += act.offsetWidth;
                                break;
                        case TransMenu.reference.bottomLeft:
                                y += act.offsetHeight;
                                break;
                        case TransMenu.reference.bottomRight:
                                x += act.offsetWidth;
                                y += act.offsetHeight;
                                break;
                }

                x += iLeft;
                y += iTop;

                x = Math.max(Math.min(x, maxX), minX);
                y = Math.max(Math.min(y, maxY), minY);

                elmCache["clip"].style.left = x + "px";
                elmCache["clip"].style.top = y + "px";
        }

        function slideStart() {
                var x0 = parseInt(elmCache["content"].style[pos]);
                var x1 = _this.isOpen ? 0 : -dim;

                if (a != null) a.stop();
                a = new Accelimation(x0, x1, TransMenu.slideTime, slideAccel);

                a.onframe = slideFrame;
                a.onend = slideEnd;

                a.start();
        }

        function slideFrame(x) {
                elmCache["content"].style[pos] = x + "px";
        }

        function slideEnd() {
                if (!_this.isOpen) elmCache["clip"].style.visibility = "hidden";
                animating = false;
        }

        function initSize() {
                // everything is based off the size of the items table...
                var ow = elmCache["items"].offsetWidth;
                var oh = elmCache["items"].offsetHeight;
                var ua = navigator.userAgent.toLowerCase();

                // clipping container should be ow/oh + the size of the shadow
                elmCache["clip"].style.width = ow + TransMenu.shadowSize +  2 + "px";
                elmCache["clip"].style.height = oh + TransMenu.shadowSize + 2 + "px";

                // same with content...
                elmCache["content"].style.width = ow + TransMenu.shadowSize + "px";
                elmCache["content"].style.height = oh + TransMenu.shadowSize + "px";

                contentHeight = oh + TransMenu.shadowSize;
                contentWidth = ow + TransMenu.shadowSize;
                
                dim = iDirection == TransMenu.direction.down ? contentHeight : contentWidth;

                // set initially closed
                elmCache["content"].style[pos] = -dim - TransMenu.shadowSize + "px";
                elmCache["clip"].style.visibility = "hidden";

                // if *not* mac/ie 5
                if (ua.indexOf("mac") == -1 || ua.indexOf("gecko") > -1) {
                        // set background div to offset size
                        elmCache["background"].style.width = ow + "px";
                        elmCache["background"].style.height = oh + "px";
                        elmCache["background"].style.backgroundColor = TransMenu.backgroundColor;

                        // shadow left starts at offset left and is offsetHeight pixels high
                        elmCache["shadowRight"].style.left = ow + "px";
                        elmCache["shadowRight"].style.height = oh - (TransMenu.shadowOffset - TransMenu.shadowSize) + "px";
                        elmCache["shadowRight"].style.backgroundColor = TransMenu.shadowColor;

                        // shadow bottom starts at offset height and is offsetWidth - shadowOffset 
                        // pixels wide (we don't want the bottom and right shadows to overlap or we 
                        // get an extra bright bottom-right corner)
                        elmCache["shadowBottom"].style.top = oh + "px";
                        elmCache["shadowBottom"].style.width = ow - TransMenu.shadowOffset + "px";
                        elmCache["shadowBottom"].style.backgroundColor = TransMenu.shadowColor;
                }
                // mac ie is a little different because we use a PNG for the transparency
                else {
                        // set background div to offset size
                        elmCache["background"].firstChild.src = TransMenu.backgroundPng;
                        elmCache["background"].firstChild.width = ow;
                        elmCache["background"].firstChild.height = oh;

                        // shadow left starts at offset left and is offsetHeight pixels high
                        elmCache["shadowRight"].firstChild.src = TransMenu.shadowPng;
                        elmCache["shadowRight"].style.left = ow + "px";
                        elmCache["shadowRight"].firstChild.width = TransMenu.shadowSize;
                        elmCache["shadowRight"].firstChild.height = oh - (TransMenu.shadowOffset - TransMenu.shadowSize);

                        // shadow bottom starts at offset height and is offsetWidth - shadowOffset 
                        // pixels wide (we don't want the bottom and right shadows to overlap or we 
                        // get an extra bright bottom-right corner)
                        elmCache["shadowBottom"].firstChild.src = TransMenu.shadowPng;
                        elmCache["shadowBottom"].style.top = oh + "px";
                        elmCache["shadowBottom"].firstChild.height = TransMenu.shadowSize;
                        elmCache["shadowBottom"].firstChild.width = ow - TransMenu.shadowOffset;
                }
        }
        
        function initCache() {
                var menu = document.getElementById(id);
                var all = menu.all ? menu.all : menu.getElementsByTagName("*"); // IE/win doesn't support * syntax, but does have the document.all thing

                elmCache = {};
                elmCache["clip"] = menu;
                elmCache["item"] = [];
                
                for (var i = 0, elm = null; elm = all[i]; i++) {
                        switch (elm.className) {
                                case "items":
                                case "content":
                                case "background":
                                case "shadowRight":
                                case "shadowBottom":
                                        elmCache[elm.className] = elm;
                                        break;
                                case "item":
                                        elm._index = elmCache["item"].length;
                                        elmCache["item"][elm._index] = elm;
                                        break;
                        }
                }

                // hack!
                _this.elmCache = elmCache;
        }

        function initEvents() {
                // hook item mouseover
                for (var i = 0, item = null; item = elmCache.item[i]; i++) {
                        item.onmouseover = item_mouseover;
                        item.onmouseout = item_mouseout;
                        item.onclick = item_click;
                }

                // hook actuation
                if (typeof oActuator.tagName != "undefined") {
                        oActuator.onmouseover = actuator_mouseover;
                        oActuator.onmouseout = actuator_mouseout;
                }

                // hook menu mouseover
                elmCache["content"].onmouseover = content_mouseover;
                elmCache["content"].onmouseout = content_mouseout;
        }

        function highlight(oRow) {
                oRow.className = "item hover";
                if (childMenus[oRow._index]) 
                        oRow.lastChild.firstChild.src = TransMenu.dingbatOn;
        }

        function dehighlight(oRow) {
                oRow.className = "item";
                if (childMenus[oRow._index]) 
                        oRow.lastChild.firstChild.src = TransMenu.dingbatOff;
        }

        function item_mouseover() {
                if (!animating) {
                        highlight(this);

                        if (childMenus[this._index]) 
                                childMenuSet.showMenu(childMenus[this._index]);
                        else if (childMenuSet) childMenuSet.hide();
                }
        }

        function item_mouseout() {
                if (!animating) {
                        if (childMenus[this._index])
                                childMenuSet.hideMenu(childMenus[this._index]);
                        else    // otherwise child_deactivate will do this
                                dehighlight(this);
                }
        }

        function item_click() {
                if (!animating) {
                        if (_this.items[this._index].url) {
							switch (_this.items[this._index].browserNav) {
								// cases are slightly different
								case 1:
								// open in a new window
								window.open(_this.items[this._index].url, '', '');;
									
								break;

								case 2:
								// open in a popup window
								window.open(_this.items[this._index].url, '', 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=780,height=550');;
								break;

								case 3:
								// don't link it
								break;

								default:	// formerly case 2
								// open in parent window
								location.href = _this.items[this._index].url;
								break;
							}
						}
                }
        }

        function actuator_mouseover() {
                parentMenuSet.showMenu(_this);
                if (!oActuator.parentMenu) {
                	if (oActuator.className.indexOf(' jahover') < 0){
                		if (oActuator.className.indexOf('-active') < 0)
                			oActuator.className += ' jahover';
                		else
                			oActuator.className += ' jahover-active';              			
                	}
                }
        }

        function actuator_mouseout() {
                parentMenuSet.hideMenu(_this);
        }

        function content_mouseover() {
                if (!animating) {
                        parentMenuSet.showMenu(_this);
                        _this.onmouseover();
                }
        }

        function content_mouseout() {
                if (!animating) {
                        parentMenuSet.hideMenu(_this);
                }
        }

        function child_mouseover() {
                if (!animating) {
                        parentMenuSet.showMenu(_this);
                }
        }

        function child_deactivate() {
                for (var i = 0; i < childMenus.length; i++) {
                        if (childMenus[i] == this) {
                                dehighlight(elmCache["item"][i]);
                                break;
                        }
                }
        }

        function child_queue() {
                parentMenuSet.hideMenu(_this);
        }

		function child_dequeue() {
				parentMenuSet.showMenu(_this);
		}

        function toString() {
                var aHtml = [];
                var sClassName = "transMenu" + (oActuator.constructor != TransMenuItem ? " top" : "");

                for (var i = 0, item = null; item = this.items[i]; i++) {
                        aHtml[i] = item.toString(childMenus[i]);
                }

                return '<div id="' + id + '" class="' + sClassName + '">' + 
                        '<div class="content"><table summary="." class="items" cellpadding="0" cellspacing="0" border="0">' + 
                        '<tr><td colspan="2"><img src="' + TransMenu.spacerGif + '" width="1" height="' + TransMenu.menuPadding + '"></td></tr>' + 
                        aHtml.join('') + 
                        '<tr><td colspan="2"><img src="' + TransMenu.spacerGif + '" width="1" height="' + TransMenu.menuPadding + '"></td></tr></table>' + 
                        '<div class="shadowBottom"><img src="' + TransMenu.spacerGif + '" width="1" height="1"></div>' + 
                        '<div class="shadowRight"><img src="' + TransMenu.spacerGif + '" width="1" height="1"></div>' + 
		        '<div class="background"><img src="' + TransMenu.spacerGif + '" width="1" height="1"></div>' + 
	                '</div></div>';
        }
}


//==================================================================================================
// TransMenuSet
//==================================================================================================
// iDirection           : The direction to slide out. One of TransMenu.direction.
// iLeft                : Left pixel offset of menus from actuator
// iTop                 : Top pixel offset of menus from actuator
// iReferencePoint      : Corner of actuator to measure from. One of TransMenu.referencePoint.
//==================================================================================================
TransMenuSet.registry = [];

function TransMenuSet(iDirection, iLeft, iTop, iReferencePoint) {
        // public methods
        this.addMenu = addMenu;
        this.showMenu = showMenu;
        this.hideMenu = hideMenu;
        this.hide = hide;
        this.hideCurrent = hideCurrent;

        // initialization
        var menus = [];
        var _this = this;
        var current = null;

        this.index = TransMenuSet.registry.length;
        TransMenuSet.registry[this.index] = this;

        // method implimentations...
        function addMenu(oActuator) {
                var m = new TransMenu(oActuator, iDirection, iLeft, iTop, iReferencePoint, this);
                menus[menus.length] = m;
                return m;
        }

        function showMenu(oMenu) {
                if (oMenu != current) {
                        // close currently open menu
                        if (current != null) hide(current);        

                        // set current menu to this one
                        current = oMenu;

                        // if this menu is closed, open it
                        oMenu.show();
                }
                else {
                        // hide pending calls to close this menu
                        cancelHide(oMenu);
                }
        }

        function hideMenu(oMenu) {
                //dbg_dump("hideMenu a " + oMenu.index);
                if (current == oMenu && oMenu.isOpen) {
                        //dbg_dump("hideMenu b " + oMenu.index);
                        if (!oMenu.hideTimer) scheduleHide(oMenu);
                }
        }

        function scheduleHide(oMenu) {
                //dbg_dump("scheduleHide " + oMenu.index);
                oMenu.onqueue();
                oMenu.hideTimer = window.setTimeout("TransMenuSet.registry[" + _this.index + "].hide(TransMenu.registry[" + oMenu.index + "])", TransMenu.hideDelay);
        }

        function cancelHide(oMenu) {
                //dbg_dump("cancelHide " + oMenu.index);
                if (oMenu.hideTimer) {
						oMenu.ondequeue();
                        window.clearTimeout(oMenu.hideTimer);
                        oMenu.hideTimer = null;
                }
        }

        function hide(oMenu) {   
                if (!oMenu && current) oMenu = current;

                if (oMenu && current == oMenu && oMenu.isOpen) {
                        hideCurrent();
                }
        }

        function hideCurrent() {
				if (null != current) {
					cancelHide(current);
					current.hideTimer = null;
					current.hide();
					current = null;
				}
        }
}

//==================================================================================================
// TransMenuItem (internal)
// represents an item in a dropdown
//==================================================================================================
// sText        : The item display text
// sUrl         : URL to load when the item is clicked
// oParent      : Menu this item is a part of
//==================================================================================================
function TransMenuItem(sText, sUrl, oParent, browserNav, active) {
        this.toString = toString;
        this.text = sText;
        this.url = sUrl;
		this.browserNav = browserNav;
        this.parentMenu = oParent;
		this.active = active;

        function toString(bDingbat) {
                var sDingbat = bDingbat ? TransMenu.dingbatOff : TransMenu.spacerGif;
                var iEdgePadding = TransMenu.itemPadding + TransMenu.menuPadding;
                var sPaddingLeft = "padding:" + TransMenu.itemPadding + "px; padding-left:" + iEdgePadding + "px;"
                var sPaddingRight = "padding:" + TransMenu.itemPadding + "px; padding-right:" + iEdgePadding + "px;"
				var id = active?' id="active" ':'';
					/*return '<tr class="item"'+id+'><td nowrap style="' + sPaddingLeft + sPaddingRight + '"><div style="background: url(' + sDingbat + ') right no-repeat;">' + 
                        sText + '</div></td></tr>';*/
                return '<tr class="item"'+id+'><td nowrap style="' + sPaddingLeft + '">' + 
                        sText + '</td><td width="10" style="' + sPaddingRight + '">' + 
                        '<img src="' + sDingbat + '" width="8" height="8"></td></tr>';
        }
}

//=====================================================================
// Accel[erated] [an]imation object
// change a property of an object over time in an accelerated fashion
//=====================================================================
// obj  : reference to the object whose property you'd like to animate
// prop : property you would like to change eg: "left"
// to   : final value of prop
// time : time the animation should take to run
// zip	: optional. specify the zippiness of the acceleration. pick a 
//		  number between -1 and 1 where -1 is full decelerated, 1 is 
//		  full accelerated, and 0 is linear (no acceleration). default
//		  is 0.
// unit	: optional. specify the units for use with prop. default is 
//		  "px".
//=====================================================================
// bezier functions lifted from the lib_animation.js file in the 
// 13th Parallel API. www.13thparallel.org
//=====================================================================

function Accelimation(from, to, time, zip) {
	if (typeof zip  == "undefined") zip  = 0;
	if (typeof unit == "undefined") unit = "px";

        this.x0         = from;
        this.x1		= to;
	this.dt		= time;
	this.zip	= -zip;
	this.unit	= unit;
	this.timer	= null;
	this.onend	= new Function();
        this.onframe    = new Function();
}



//=====================================================================
// public methods
//=====================================================================

// after you create an accelimation, you call this to start it-a runnin'
Accelimation.prototype.start = function() {
	this.t0 = new Date().getTime();
	this.t1 = this.t0 + this.dt;
	var dx	= this.x1 - this.x0;
	this.c1 = this.x0 + ((1 + this.zip) * dx / 3);
	this.c2 = this.x0 + ((2 + this.zip) * dx / 3);
	Accelimation._add(this);
}

// and if you need to stop it early for some reason...
Accelimation.prototype.stop = function() {
	Accelimation._remove(this);
}



//=====================================================================
// private methods
//=====================================================================

// paints one frame. gets called by Accelimation._paintAll.
Accelimation.prototype._paint = function(time) {
	if (time < this.t1) {
		var elapsed = time - this.t0;
	        this.onframe(Accelimation._getBezier(elapsed/this.dt,this.x0,this.x1,this.c1,this.c2));
        }
	else this._end();
}

// ends the animation
Accelimation.prototype._end = function() {
	Accelimation._remove(this);
        this.onframe(this.x1);
	this.onend();
}




//=====================================================================
// static methods (all private)
//=====================================================================

// add a function to the list of ones to call periodically
Accelimation._add = function(o) {
	var index = this.instances.length;
	this.instances[index] = o;
	// if this is the first one, start the engine
	if (this.instances.length == 1) {
		this.timerID = window.setInterval("Accelimation._paintAll()", this.targetRes);
	}
}

// remove a function from the list
Accelimation._remove = function(o) {
	for (var i = 0; i < this.instances.length; i++) {
		if (o == this.instances[i]) {
			this.instances = this.instances.slice(0,i).concat( this.instances.slice(i+1) );
			break;
		}
	}
	// if that was the last one, stop the engine
	if (this.instances.length == 0) {
		window.clearInterval(this.timerID);
		this.timerID = null;
	}
}

// "engine" - call each function in the list every so often
Accelimation._paintAll = function() {
	var now = new Date().getTime();
	for (var i = 0; i < this.instances.length; i++) {
		this.instances[i]._paint(now);
	}
}


// Bezier functions:
Accelimation._B1 = function(t) { return t*t*t }
Accelimation._B2 = function(t) { return 3*t*t*(1-t) }
Accelimation._B3 = function(t) { return 3*t*(1-t)*(1-t) }
Accelimation._B4 = function(t) { return (1-t)*(1-t)*(1-t) }


//Finds the coordinates of a point at a certain stage through a bezier curve
Accelimation._getBezier = function(percent,startPos,endPos,control1,control2) {
	return endPos * this._B1(percent) + control2 * this._B2(percent) + control1 * this._B3(percent) + startPos * this._B4(percent);
}


//=====================================================================
// static properties
//=====================================================================

Accelimation.instances = [];
Accelimation.targetRes = 10;
Accelimation.timerID = null;


//=====================================================================
// IE win memory cleanup
//=====================================================================

if (window.attachEvent) {
	var cearElementProps = [
		'data',
		'onmouseover',
		'onmouseout',
		'onmousedown',
		'onmouseup',
		'ondblclick',
		'onclick',
		'onselectstart',
		'oncontextmenu'
	];

	window.attachEvent("onunload", function() {
        var el;
        for(var d = document.all.length;d--;){
            el = document.all[d];
            for(var c = cearElementProps.length;c--;){
                el[cearElementProps[c]] = null;
            }
        }
	});
}

