var imagelang = 'en' ; var currlang = 'en' ; var prefixpath = 'http://static.asiawebdirect.com/awd/' ; hasShortType = 'true';	
var httphrefShort = location.href;
httphrefShort = httphrefShort.replace("http://", "");
var arrhttphrefShort = httphrefShort.split("/");
httphrefShort = "http://" + arrhttphrefShort[0];

var pathwebcheckavailabilityShort = httphrefShort + '/smartreserve/indexShort.php';
var ckAvailStartTdyShort = new Date();
//remove time from Date
var dateCutOffdays = 2;
var dateAddNight = 3;
ckAvailStartTdyShort = new Date(ckAvailStartTdyShort.getFullYear(),  ckAvailStartTdyShort.getMonth(), ckAvailStartTdyShort.getDate());
var ckAvailStartDateShort = new Date(ckAvailStartTdyShort.getFullYear(),  ckAvailStartTdyShort.getMonth(), ckAvailStartTdyShort.getDate() + dateCutOffdays);
var ckAvailEndDateShort = new Date(ckAvailStartDateShort.getFullYear(),  ckAvailStartDateShort.getMonth(), ckAvailStartDateShort.getDate() + dateAddNight);

function sm_getForm() {
	var formname = (arguments[0]) ? arguments[0] : "checkAvailShort";
	return document.forms[formname];
}

function sm_getEl(tmpname) {
	var formuse = (arguments[1]) ? arguments[1] : sm_getForm();
	
	if (formuse == undefined) return false;;
	
	return formuse.elements[tmpname];
}

//->this section may be same javascript other file
function padZero(num) {
	return (num< 10) ? '0' + num : num ;
}

function IsIE() {
	return navigator.appVersion.match(/\bMSIE\b/);
}

function ChDatetoStr(cDate) {
	return padZero(cDate.getDate()) + '/' + padZero(cDate.getMonth() + 1) + '/' + cDate.getFullYear();
}

function ChStrtoDate(cDate) {
	var arrcDate = cDate.split("/");
	return new Date(arrcDate[2], Number(arrcDate[1])-1, Number(arrcDate[0]));
}

function setValue(arrElement, values) {
	var formuse = (arguments[2]) ? arguments[2] : sm_getForm();
	var i;
	var j = arrElement.length;
	var tmpInput;
	for(i=0;i<j;i++) {
		tmpInput = sm_getEl(arrElement[i], formuse);
		if((tmpInput!=null) && (tmpInput!=false))
		{
			if(tmpInput.type.indexOf("select")==0) setElement(tmpInput, values);
			else tmpInput.value = values;
		}
	}
}

function setElement(cElement,cValue) {
	for(var i=0;i<cElement.length;i++) {
		if(cElement.options[i].value==cValue) {
			cElement.selectedIndex = i;
			cElement.options[i].setAttribute('selected', true);
			break;
		}
	}
}
//<-this section may be same javascript other file

function startapp(formuse, TypeSet) {
	var m;
	//create date option
	var days = new Array("checkHotel[sDay2]", "checkHotel[eDay2]");
	var tmpdate;
	for(m=0;m<2;m++) {
		obj = sm_getEl(days[m], formuse);
		
		if (!obj) return;
		
		obj.length = 0;
		for(i=0;i<31;i++) {
			tmpdate = padZero(i+1);
			obj.options[i]=new Option(tmpdate, tmpdate);
		}	
	}

	//create month option
	var months = new Array("checkHotel[sMonth2]", "checkHotel[eMonth2]");
	var tmpmonth;
	if(sm_getEl('checkHotel[LanguageCode]', formuse).value=="ja") 
		tmpmonth = new Array("1ï¿½ï¿½","2ï¿½ï¿½","3ï¿½ï¿½","4ï¿½ï¿½","5ï¿½ï¿½","6ï¿½ï¿½","7ï¿½ï¿½","8ï¿½ï¿½","9ï¿½ï¿½","10ï¿½ï¿½","11ï¿½ï¿½","12ï¿½ï¿½");
	else 
		tmpmonth = new Array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");

	for(m=0;m<2;m++) {
		obj = sm_getEl(months[m], formuse);
		obj.length = 0;
		for(i=0;i<12;i++) {
			obj.options[i]=new Option(tmpmonth[i], padZero(i+1));
		}
	}

	//create year option
	var years = new Array("checkHotel[sYear2]", "checkHotel[eYear2]");
	var m;
	var tmpyear;

	var tnow = new Date();
	var sMonth = tnow.getMonth() + 1;
	var sYear = tnow.getFullYear();
	var sYearOld = sYear;
	var i;
	for(i=0;i<=17;i++) {
		sMonth = sMonth + 1;
		if(sMonth>=13) {
			sMonth = 1;
			sYear = sYear + 1;
		}
	}
	prefixyearAddOn = sYear - sYearOld;

	for(m=0;m<2;m++) {
		obj = sm_getEl(years[m], formuse);
		obj.length = 0;
		tmpyear = ckAvailStartTdyShort.getFullYear();
		for(i=0;i<=prefixyearAddOn;i++) {
			obj.options[i]=new Option(tmpyear, tmpyear);
			tmpyear++;
		}
	}

	sm_setAllDate(ChDatetoStr(ckAvailStartDateShort), "sDate");
	sm_setAllDate(ChDatetoStr(ckAvailEndDateShort), "eDate");
	sm_getEl('checkHotel[Nights]', formuse).value = dateAddNight;
	if(sm_getEl('checkHotel[pDestinationID]', formuse)) showshortDestination(TypeSet, formuse);
	else setSubmitButtonShort(true);
}

//dates is string date = 31/01/2007
function sm_setAllDate(dates, caseset) {
	var arrtmpdate = dates.split("/");

	if(caseset=="sDate") {
		var a = new Array("checkHotel[sDay]", "checkHotel[sDay2]");
		var b = new Array("checkHotel[sMonth]", "checkHotel[sMonth2]");
		var c = new Array("checkHotel[sYear]", "checkHotel[sYear2]");
		var d = new Array("txtCheck_InShort");
	} else

	if(caseset=="eDate") {
		var a = new Array("checkHotel[eDay]", "checkHotel[eDay2]");
		var b = new Array("checkHotel[eMonth]", "checkHotel[eMonth2]");
		var c = new Array("checkHotel[eYear]", "checkHotel[eYear2]");
		var d = new Array("txtCheck_OutShort");
	}

	setValue(a, arrtmpdate[0]);
	setValue(b, arrtmpdate[1]);
	setValue(c, arrtmpdate[2]);
	setValue(d, dates);
}

function showshortDestination(fCountry, formuse) {
	var a = sm_getEl("pDestinationID", formuse).value;
	var b = sm_getEl("DestinationID", formuse).value;
	en_disListShort(true, formuse);
	var lang = sm_getEl('checkHotel[LanguageCode]', formuse).value;
	var x = pathwebcheckavailabilityShort + '?action=dest&deF='+a+'&deF2='+b+'&lang='+lang;
	if(fCountry!="") x = x + "&TypeSet=" + fCountry;
	runXmlReturnJavascript(x);
}

function changelistShort(aarr, barr, obj, indexSelected) {
	var i;
	obj = sm_getEl(obj);
	obj.length = 0;
	for(i=0;i<aarr.length;i++) {
		obj.options[i]=new Option(aarr[i],barr[i]);
	}
	obj.selectedIndex = indexSelected;
	en_disListShort(false);
}

function sm_search(formuse) {
	if(sm_getEl("checkHotel[pDestinationID]", formuse)) {
		if(sm_getEl("checkHotel[pDestinationID]", formuse).value=="0") {
			alert("Please select a country");
			return false;
		}
		
		sm_getEl("pDestinationID", formuse).value = sm_getEl("checkHotel[pDestinationID]", formuse).value;
		
		if(sm_getEl("checkHotel[DestinationID]", formuse).options[0].selected) {
			sm_getEl("checkHotel[DestinationID]", formuse).options[0].value = sm_getEl("pDestinationID", formuse).value;
		}
		sm_getEl("DestinationID", formuse).value = sm_getEl("checkHotel[DestinationID]", formuse).value;
	}

	formuse.submit();
}

function changeDestinationShort() {
	var obj = sm_getEl('checkHotel[pDestinationID]');
	if(obj.value=="0") {
		var a = sm_getEl("checkHotel[DestinationID]");
		a.length = 0;
		a.options[0]=new Option("Select a city/area", 0);
		return false;
	}

	en_disListShort(true);
	var b = sm_getEl("pDestinationID").value;
	var lang = sm_getEl('checkHotel[LanguageCode]').value;
	var x = pathwebcheckavailabilityShort + '?action=hotel&hotel='+obj.value+'&deF='+b+'&lang='+lang;
	runXmlReturnJavascript(x);
}

function setSubmitButtonShort(flag) {
	var formuse = (arguments[1]) ? arguments[1] : sm_getForm();
	var cElement = formuse.getElementsByTagName('input')
	var i;
	var j = cElement.length;
	var k = null;
	for(i=0;i<j;i++) {
		if(cElement[i].name=="Submit") k = cElement[i];
	}
	if(k!=null) k.style.display = (flag) ? "" : "none";
}

function en_disListShort(flag) {
	var cForm = (arguments[1]) ? arguments[1] : sm_getForm();
	var cElement = cForm.elements['checkHotel[pDestinationID]'];
	cElement.disabled=flag;
	var cElement = cForm.elements['checkHotel[DestinationID]'];
	cElement.disabled=flag;
	setSubmitButtonShort(false, cForm);
}

function ValidateDate(tmpdate) {
	var defRtn = (arguments[1]) ? arguments[1] : 99;
	var chkdate = ChDatetoStr(ChStrtoDate(tmpdate));
	if(defRtn==99) return (chkdate==tmpdate);
	else return (chkdate==tmpdate) ? tmpdate : defRtn;
}

function updateCheckAvailAllShort(column) {
	var obj = (arguments[1]) ? arguments[1] : null;
	var defDate;
	var dateSel;
	var tmpselmonth;
	if(column=="sDate") {
		defDate = ChDatetoStr(ckAvailStartTdyShort);
		tmpselmonth = sm_getEl("checkHotel[sMonth2]").value;
		dateSel = sm_getEl("checkHotel[sDay2]").value + '/' + tmpselmonth + '/' + sm_getEl("checkHotel[sYear2]").value;
	} else 
	
	if(column=="eDate") {
		defDate = ChDatetoStr(ckAvailStartDateShort);
		tmpselmonth = sm_getEl("checkHotel[eMonth2]").value;
		dateSel = sm_getEl("checkHotel[eDay2]").value + '/' + tmpselmonth + '/' + sm_getEl("checkHotel[eYear2]").value;
	}

	dateSel = ValidateDate(dateSel, defDate);
	var tmpdateSel = ChStrtoDate(dateSel);
	if(
		(tmpdateSel.getTime()<ckAvailStartTdyShort.getTime()) &&
		(tmpselmonth-1==ckAvailStartTdyShort.getMonth())
		) {
		var tmpnewmonth = new Date(tmpdateSel.getFullYear(),  Number(tmpselmonth), tmpdateSel.getDate());
		dateSel = ChDatetoStr(tmpnewmonth);
	}

	sm_setAllDate(dateSel, column);

	var ckIn = ChStrtoDate(sm_getEl("txtCheck_InShort").value);
	var ckOut = ChStrtoDate(sm_getEl("txtCheck_OutShort").value);

	if(ckIn.getTime()<ckAvailStartTdyShort.getTime()) {
		sm_setAllDate(ChDatetoStr(ckAvailStartTdyShort), "sDate");
	}

	if(ckOut.getTime()<=ckIn.getTime()) {
		var tmpaddday = ChStrtoDate(sm_getEl("txtCheck_InShort").value);
		tmpaddday = new Date(tmpaddday.getFullYear(), tmpaddday.getMonth(), tmpaddday.getDate() + 1);
		sm_setAllDate(ChDatetoStr(tmpaddday), "eDate");
	}

	try {
		var ckIn = ChStrtoDate(sm_getEl("txtCheck_InShort").value);
		var ckOut = ChStrtoDate(sm_getEl("txtCheck_OutShort").value);
		var cTime  = ckOut.getTime() - ckIn.getTime();
		var nDate  = new Date(cTime);
		var cValue = Number(nDate.getDate()) - 1;
		cValue = Math.floor(cTime / (1000 * 60 * 60 * 24));
		sm_getEl("checkHotel[Nights]").value = cValue;
	} catch(e) 	{}
}

function showChangeDateShort(values) {
	if(values=='in') {
		sm_setAllDate(sm_getEl('txtCheck_InShort').value, "sDate");
		updateCheckAvailAllShort('sDate');
	} else 

	if(values=='out') {
		sm_setAllDate(sm_getEl('txtCheck_OutShort').value, "eDate");
		updateCheckAvailAllShort('eDate');
	}
}

function updateMtxDate(type) {
	if (type=="in") {
		setDateSelect("in");
		updateMtxDate("nights");
	} else if (type == "nights") {
		var chk_in = strToDateObj($('mtx_check_in').value);
		var nights = parseInt($('num_nights').value, 10);
		var chk_out = chk_in;
		chk_out.setDate(chk_out.getDate()+nights);
		$('mtx_check_out').value = padZero(chk_out.getDate()) + "/" + padZero(chk_out.getMonth()+1) + "/" + chk_out.getFullYear();
		updateMtxDate("out");
	} else if (type == "out") {
		setDateSelect("out");
		
		// update Nights select
		var chk_in = strToDateObj($('mtx_check_in').value);
		var chk_out = strToDateObj($('mtx_check_out').value);
		var diff = chk_out.getTime()-chk_in.getTime();
		var nights = diff/(24*3600*1000);
		//$('num_nights').value = nights;
		updateNightsSelected(nights);
	} 
	
}

function updateNightsSelected(nights) {
	var n = $('num_nights');
	var max_val = parseInt(n.options[n.options.length-1].value,10);
	if (max_val >= nights) {
		n.value = nights;
	} else {
		// we don't have this number yet
		for (var i=max_val+1; i<=nights; i++) {
			var o = new Option(i, i);
			if (i == nights) {
				o.selected = "selected";
			}
			n.options[n.options.length] = o;
		}
	}
}

function updateMonthSelected(sel, val) {
	var val_year = parseInt(val.substr(0,4),10);
	var val_month = parseInt(val.substr(4),10);
	
	var str_max = sel.options[sel.options.length-1].value;
	var max_year = parseInt(str_max.substr(0, 4),10);
	var max_month = parseInt(str_max.substr(4),10);
	
	if (max_year>val_year || (max_year==val_year && max_month>=val_month)) {
		sel.value = val;
	} else {
		// option not available yet
		var end = new Date(val_year, val_month, 1);
		var d = new Date(max_year, max_month , 1);
		do {
			d.setMonth(d.getMonth()+1);
			var str = d.toDateString();
			var tmp = str.split(" ");
			var txt = tmp[1] + ", " + tmp[3];
			var val = d.getFullYear() + "" + d.getMonth();
			
			var o = new Option(txt, val);
			if (i==0) {
				o.selected = "selected";
			}
			sel.options[sel.options.length] = o;
		} while (d <= end);
	}
}

function setDateSelect(type) {
	if (type == "in") {
		var input = $('mtx_check_in');
		var output = $('check_in_date');
		var obj_month = $('check_in_month');
	} else if (type == "out") {
		var input = $('mtx_check_out');
		var output = $('check_out_date');
		var obj_month = $('check_out_month');
	}
	var str_date = input.value
	
	var tmp = str_date.split("/");
	var sel_date = new Date(tmp[2], tmp[1]-1, tmp[0]);
	
	if (type == "in") {
		// cannot be the past
		if (matrix.beginDate) {
			var chk = strToDate(matrix.beginDate);
		} else {
			var d = new Date();
			var chk = new Date(d.getFullYear(), d.getMonth(), d.getDate());
		}
	
		if (sel_date < chk) {
			sel_date = chk;
			$('mtx_check_in').value = padZero(sel_date.getDate()) + "/" + padZero(sel_date.getMonth()+1) + "/" + sel_date.getFullYear();
		}
	} else if (type == "out") {
		// cannot before check_in
		var chk_in = strToDateObj($('mtx_check_in').value);
		chk_in.setDate(chk_in.getDate()+1);
		if (sel_date < chk_in) {
			sel_date = chk_in;
			$('mtx_check_out').value = padZero(sel_date.getDate()) + "/" + padZero(sel_date.getMonth()+1) + "/" + sel_date.getFullYear();
		}
	}
	
	var tmp_date = new Date(sel_date.getFullYear(), sel_date.getMonth(), 1);
	output.options.length = 0;
	var i = 0;
	do {
		var o = dateToOption(tmp_date, "date")			
		if (tmp_date.getDate() == sel_date.getDate()) {
			o.selected = "selected";
		}
		output.options[i] = o;
		
		i++;
		tmp_date.setDate(tmp_date.getDate()+1);
	}
	while (tmp_date.getMonth()==sel_date.getMonth());
	
	// set month select box
	var val = sel_date.getFullYear() + "" + sel_date.getMonth();
	//obj_month.value = val;
	updateMonthSelected(obj_month, val);
	
}

function strToDateObj(str) {
	// assume dd/mm/yyyy
	if (str == "") {
		var tmp = new Date();
		var d = new Date(tmp.getFullYear(), tmp.getMonth(), tmp.getDate());
		return d;
	}
	var tmp = str.split("/");
	var d = new Date(tmp[2], tmp[1]-1, tmp[0]);
	return d;
}

function initializeCalendar() {
	if (!$('check_in_date')) {
		// no calendar for current matrix
		return false;
	}
	var d = new Date();
	d.setDate(1);
	var end = d.getFullYear()+2;
	$('check_in_month').options.length = 0;
	$('check_out_month').options.length = 0;
	var i = 0;
	do {
		var str = d.toDateString();
		var tmp = str.split(" ");
		var txt = tmp[1] + ", " + tmp[3];
		var val = d.getFullYear() + "" + d.getMonth();
		
		var o = new Option(txt, val);
		if (i==0) {
			o.selected = "selected";
		}
		$('check_in_month').options[i] = o;
		var oo = new Option(txt, val);
		if (i==0) {
			oo.selected = "selected";
		}
		$('check_out_month').options[i] = oo;
		d.setMonth(d.getMonth()+1);
		i++;
	} while (d.getFullYear() < end);
	
	// date/month selection
	var d = new Date();
	var chk = new Date(d.getFullYear(), d.getMonth(), d.getDate());
	$('mtx_check_in').value = padZero(chk.getDate()) + "/" + padZero(chk.getMonth()+1) + "/" + chk.getFullYear();
	setDateSelect("in");
	
	chk.setDate(chk.getDate()+1);
	$('mtx_check_out').value = padZero(chk.getDate()) + "/" + padZero(chk.getMonth()+1) + "/" + chk.getFullYear();
	setDateSelect("out");
	
	// some calculation incase calendar object is inside some relative position element
	crossobj.top = "0px";
	crossobj.left = "0px";
	var pos_c = Element.cumulativeOffset(document.getElementById("calendar"));
	calOffsetCompensate.top = pos_c['top'];
	calOffsetCompensate.left = pos_c['left'];

}

function dateToOption(date, type) {
	var str = date.toDateString();
	var tmp = str.split(" ");
	if (type == "date") {
		var txt = tmp[0] + " " + tmp[2];
		var val = tmp[2];
		var o = new Option(txt, val);
		return o;
	}
}

function dateSelectChange(obj) {
	if (obj.id=="check_in_date" || obj.id=="check_in_month") {
		var ym = $('check_in_month').value;
		var y = parseInt(ym.substr(0, 4),10);
		var m = parseInt(ym.substr(4),10);
		var d = parseInt($('check_in_date').value,10);
		var chk_in = new Date(y, m, d);
		validateSelectedDate(chk_in, "in");
		$('mtx_check_in').value = padZero(chk_in.getDate()) + "/" + padZero(chk_in.getMonth()+1) + "/" + chk_in.getFullYear();
		updateMtxDate("in");
	} else if (obj.id=="check_out_date" || obj.id=="check_out_month") {
		var ym = $('check_out_month').value;
		var y = parseInt(ym.substr(0, 4),10);
		var m = parseInt(ym.substr(4),10);
		var d = parseInt($('check_out_date').value,10);
		var chk_out = new Date(y, m, d);
		validateSelectedDate(chk_out, "out");
		$('mtx_check_out').value = padZero(chk_out.getDate()) + "/" + padZero(chk_out.getMonth()+1) + "/" + chk_out.getFullYear();
		updateMtxDate("out");
	}
}

function validateSelectedDate(sel_date, type) {
	if (type == "in") {
		// cannot be the past
		var d = new Date();
		var chk = new Date(d.getFullYear(), d.getMonth(), d.getDate());
		if (sel_date < chk) {
			sel_date = chk;
			$('mtx_check_in').value = padZero(sel_date.getDate()) + "/" + padZero(sel_date.getMonth()+1) + "/" + sel_date.getFullYear();
		}
	} else if (type == "out") {
		// cannot before check_in
		var chk_in = strToDateObj($('mtx_check_in').value);
		chk_in.setDate(chk_in.getDate()+1);
		if (sel_date < chk_in) {
			sel_date = chk_in;
			$('mtx_check_out').value = padZero(sel_date.getDate()) + "/" + padZero(sel_date.getMonth()+1) + "/" + sel_date.getFullYear();
		}
	}

}

function loadPeriodMatrix() {
    var s_in = $('mtx_check_in').value.split("/");
    var checkIn = s_in[2] + s_in[1] + s_in[0];
    var s_out = $('mtx_check_out').value.split("/");
    var checkOut = s_out[2] + s_out[1] + s_out[0];
    
    matrix.checkIn = checkIn;
    matrix.checkOut = checkOut;
    matrix.showOnRequest = !$('mtx_filterOnRequest').checked;
    
    matrix.setCookie();
    
    matrix.loadCheckInMatrix(checkIn, checkOut);
}

function syncronizeCalendar() {
	if (!window.matrix) {
		return false;
	}
	
	if (!$('mtx_check_in')) {
		return false;
	}
	
	if (window.matrix.checkIn) {
		var s_in = window.matrix.checkIn;
		$('mtx_check_in').value = s_in.substr(6) + "/" + s_in.substr(4, 2) + "/" + s_in.substr(0,4);
		updateMtxDate("in");
	}
	
	if (window.matrix.checkOut) {
		var s_out = window.matrix.checkOut;
		$('mtx_check_out').value = s_out.substr(6) + "/" + s_out.substr(4, 2) + "/" + s_out.substr(0,4);
		updateMtxDate("out");
	}
}

function showMapIcon(target) {
	$(target).style.display = "";
}
;
	if((String(typeof(crossobj))=="undefined") && (hasShortType=="true")) {
		var fixedX = -1			// x position (-1 if to appear below control)
		var fixedY = -1			// y position (-1 if to appear below control)
		var startAt = 0			// 0 - sunday ; 1 - monday
		var showWeekNumber = 1		// 0 - don't show; 1 - show
		var showToday = 1			// 0 - don't show; 1 - show
		var imgDir = prefixpath + "images/calendar/" + imagelang + "/";

		var gotoString = "Go To Current Month"
		var todayString = "Today is"
		var weekString = "Wk"

		//var scrollLeftMessage = "Click to scroll to previous month. Hold mouse button to scroll automatically."
		//var scrollRightMessage = "Click to scroll to next month. Hold mouse button to scroll automatically."
		//var selectMonthMessage = "Click to select a month."
		//var selectYearMessage = "Click to select a year."

		var scrollLeftMessage = ""
		var scrollRightMessage = ""
		var selectMonthMessage = ""
		var selectYearMessage = ""

		var closeCalendarMessage = "Close"
		var selectDateMessage = "Select [date] as date." // do not replace [date], it will be replaced by date.

		var crossobj, crossMonthObj, crossYearObj
		var monthSelected, yearSelected, dateSelected
		var omonthSelected, oyearSelected, odateSelected
		var monthConstructed, yearConstructed, intervalID1, intervalID2, timeoutID1, timeoutID2
		var ctlToPlaceValue1, ctlToPlaceValue2, ctlNow, dateFormat
		var nStartingYear

		var bPageLoaded=false
		var ie=document.all
		var ie6=!window.XMLHttpRequest;
		var dom=document.getElementById

		var ns4=document.layers
		var today = new Date()
		var dateNow = today.getDate()
		var monthNow = today.getMonth()
		if (currlang == 'en') {
			var yearNow = today.getYear()
		} else {
			var yearNow = today.getYear() + 543;
		}
		var imgsrc = new Array("drop1.gif","drop1.gif","left1.gif","left1.gif","right1.gif","right1.gif")
		var img = new Array()
		var badDate = imgDir + "baddate.gif"

		var imgBL = imgDir + "cornerbotleft.gif"
		var imgBR = imgDir + "cornerbotright.gif"
		var imgTL = imgDir + "cornertopleft.gif"
		var imgTR = imgDir + "cornertopright.gif"

		var bShow = false;
		var iStart,iEnd
		var calOffsetCompensate = new Object;

		/* hides <select> and <applet> objects (for IE only) */
		function hideElement( elmID, overDiv )
		{
			
		  if( ie6 )
		  {
			for( i = 0; i < document.all.tags( elmID ).length; i++ )
			{
			  obj = document.all.tags( elmID )[i];
			  if( !obj || !obj.offsetParent )
			  {
				continue;
			  }

			    var pos = Element.cumulativeOffset(obj);
			    objTop  = pos['top'];
			    objLeft = pos['left'];
			    
			    // compensation incase calendar locate inside position relative parent
			    objTop -= calOffsetCompensate.top;
			    objLeft -= calOffsetCompensate.left;

			  objHeight = obj.offsetHeight - 5;
			  objWidth = obj.offsetWidth;

			var tmpoverDivoffsetTop = overDiv.offsetTop;
			if(LongIsinLayer || ShortIsinLayer) {
				aTag = document.getElementById(LayerParentCalendar);
				if(aTag!=null) tmpoverDivoffsetTop += aTag.offsetTop;
			}
			
			  if(( overDiv.offsetLeft + overDiv.offsetWidth ) <= objLeft );
			  else if(( tmpoverDivoffsetTop + overDiv.offsetHeight ) <= objTop );
			  else if( tmpoverDivoffsetTop >= ( objTop + objHeight ));
			  else if( overDiv.offsetLeft >= ( objLeft + objWidth ));
			  else
			  {
				obj.style.visibility = "hidden";
				obj.style.display = "none";
			  }
			  
			}
		  }
		}

		/*
		* unhides <select> and <applet> objects (for IE only)
		*/
		function showElement( elmID )
		{
			if( ie )
			{
				for( i = 0; i < document.all.tags( elmID ).length; i++ )
				{
					obj = document.all.tags( elmID )[i];

					if( !obj || !obj.offsetParent )
					{
						continue;
					}
					if(obj.style.visibility=="hidden" && obj.style.display=="none"){
						obj.style.visibility = "visible";
						obj.style.display = "";
					}
				}
			}
		}

		function HolidayRec (d, m, y, desc)
		{
			this.d = d
			this.m = m
			this.y = y
			this.desc = desc
		}


		var HolidaysCounter = 0
		var Holidays = new Array()

		function addHoliday (d, m, y, desc)
		{
			Holidays[HolidaysCounter++] = new HolidayRec ( d, m, y, desc )
		}


		if (dom)
		{
			for(i=0;i<imgsrc.length;i++)
			{
				img[i] = new Image
				img[i].src = imgDir + imgsrc[i]
			}
			mainLayer = "<div onclick='bShow=true' id='calendar' style='z-index:+999;position:absolute;visibility:hidden;'>"
			mainLayer += "	<table cellspacing=0 cellpadding=0 style='font-family:arial;font-size:11px;'>"
			mainLayer += "		<tr><td>"
			mainLayer += "			<table width=100% cellspacing=0 cellpadding=0 border=0>"
			mainLayer += "				<tr><td><img src="+imgTL+"></td>"
			mainLayer += "					<td bgcolor='#ffbf00' style='padding-top:3px;font-family:arial; font-size:11px;' width=158><font color='#ffffff'><B><span id='caption'></span></B></font></td>"
			mainLayer += "					<td align=right bgcolor='#ffbf00'>"
			mainLayer += "						<table id='closeButton' cellpadding=0 cellspacing=1 border=0 bgcolor=#f9d35f>"
			mainLayer += "							<tr><td><a href='javascript:hideCalendar()'onMouseOver='document.getElementById(\"closeButton\").className=\"whiteBorder\"' onMouseOut='document.getElementById(\"closeButton\").className=\"\"'><IMG SRC='"+imgDir+"close.gif' BORDER='0' ALT='"+closeCalendarMessage+"'></a></td></tr>"
			mainLayer += "						</table></td>"
			mainLayer += "					<td><img src="+imgTR+"></td></tr>"
			mainLayer += "			</table>"
			mainLayer += "		</td></tr>"
			mainLayer += "		<tr><td style='padding:0px' bgcolor=#ffffff>"
			mainLayer += "			<table width=100% cellspacing=0 cellpadding=0 border=0>"
			mainLayer += "				<tr><td width=1 bgcolor=#FFBF00></td><td><span id='calendarcontent'></span></td><td width=1 bgcolor=#FFBF00></td></tr>"
			mainLayer += "			</table>"
			mainLayer += "		</td></tr>"

			if (showToday==1)
				mainLayer += "<tr><td align=center><table width=100% cellspacing=0 cellpadding=0 border=0><tr><td rowspan=2 width=1><img src=" + imgBL + "></td><td align=center height=5 bgcolor=#FFFFFF><span id='lblToday' style='font-family:Verdana;font-size:9px;'></span></td><td rowspan=2><img src=" + imgBR + "></td></tr><tr><td bgcolor=#FFBF00 width=100% height=1></td></tr></table></td></tr>";

			mainLayer += "</table></div><div id='selectMonth' style='z-index:+999;position:absolute;visibility:hidden;'></div><div id='selectYear' style='z-index:+999;position:absolute;visibility:hidden;'></div>";

			document.write (mainLayer);
		}

		//var	monthName = new Array("January","February","March","April","May","June","July","August","September","October","November","December")

		var monthName = new Array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec")

		if (startAt==0)
		{
			dayName = new Array ("Sun","Mon","Tue","Wed","Thu","Fri","Sat")
		}
		else
		{
			dayName = new Array ("Mon","Tue","Wed","Thu","Fri","Sat","Sun")
		}
		var	styleAnchor="text-decoration:none;color:black;"

		// Set Border Color of Selected Date
		var	styleLightBorder="border-style:solid;border-width:1px;border-color:#a0a0a0;"
		//var	styleLightBorder="border-style:solid;border-width:1px;border-color:#FF0000;"

		function swapImage(srcImg, destImg){
			if (ie)	{ document.getElementById(srcImg).setAttribute("src",imgDir + destImg) }
		}

		function initca() {
			if (!ns4)
			{
				if (!ie) { yearNow += 1900	}

				crossobj=(dom)?document.getElementById("calendar").style : ie? document.all.calendar : document.calendar
				hideCalendar()
				crossMonthObj=(dom)?document.getElementById("selectMonth").style : ie? document.all.selectMonth	: document.selectMonth
				crossYearObj=(dom)?document.getElementById("selectYear").style : ie? document.all.selectYear : document.selectYear

				monthConstructed=false;
				yearConstructed=false;

				if (showToday==1)
				{
					//document.getElementById("lblToday").innerHTML =	todayString + " <a onmousemove='window.status=\""+gotoString+"\"' onmouseout='window.status=\"\"' title='"+gotoString+"' style='"+styleAnchor+"' href='javascript:monthSelected=monthNow;yearSelected=yearNow;constructCalendar();'>"+dayName[(today.getDay()-startAt==-1)?6:(today.getDay()-startAt)]+", " + dateNow + " " + monthName[monthNow].substring(0,3)	+ "	" +	yearNow	+ "</a>"
				}

				
				sHTML1="<span id='spanLeft' style='border-style:solid;border-width:1;border-color:#f9d35f;cursor:pointer' onmouseover='swapImage(\"changeLeft\",\"left1.gif\");this.style.borderColor=\"#FFFFFF\";window.status=\""+scrollLeftMessage+"\"' onclick=\"javascript:decMonth()\" onmouseout='clearInterval(intervalID1);swapImage(\"changeLeft\",\"left1.gif\");this.style.borderColor=\"#f9d35f\";window.status=\"\"' onmousedown='clearTimeout(timeoutID1);timeoutID1=setTimeout(\"StartDecMonth()\",500)'onmouseup='clearTimeout(timeoutID1);clearInterval(intervalID1)'>&nbsp<IMG align=middle id='changeLeft' SRC='"+imgDir+"left1.gif' width=10 height=11 BORDER=0>&nbsp</span>&nbsp;"
				sHTML1+="<span id='spanRight' style='border-style:solid;border-width:1;border-color:#f9d35f;cursor:pointer' onmouseover='swapImage(\"changeRight\",\"right1.gif\");this.style.borderColor=\"#FFFFFF\";window.status=\""+scrollRightMessage+"\"' onmouseout='clearInterval(intervalID1);swapImage(\"changeRight\",\"right1.gif\");this.style.borderColor=\"#f9d35f\";window.status=\"\"' onclick='incMonth()' onmousedown='clearTimeout(timeoutID1);timeoutID1=setTimeout(\"StartIncMonth()\",500)'onmouseup='clearTimeout(timeoutID1);clearInterval(intervalID1)'>&nbsp<IMG align=middle id='changeRight' SRC='"+imgDir+"right1.gif'	width=10 height=11 BORDER=0>&nbsp</span>&nbsp"
				
				sHTML1+="<span id='spanMonth' style='border-style:solid;border-width:1;border-color:#f9d35f;cursor:pointer' onmouseover='swapImage(\"changeMonth\",\"drop1.gif\");this.style.borderColor=\"#FFFFFF\";window.status=\""+selectMonthMessage+"\"' onmouseout='swapImage(\"changeMonth\",\"drop1.gif\");this.style.borderColor=\"#f9d35f\";window.status=\"\"' onclick='popUpMonth()'></span>&nbsp;"
				sHTML1+="<span id='spanYear' style='border-style:solid;border-width:1;border-color:#f9d35f;cursor:pointer' onmouseover='swapImage(\"changeYear\",\"drop2.gif\");this.style.borderColor=\"#FFFFFF\";window.status=\""+selectYearMessage+"\"' onmouseout='swapImage(\"changeYear\",\"drop1.gif\");this.style.borderColor=\"#f9d35f\";window.status=\"\"'	onclick='popUpYear()'></span>"
				//sHTML1+="<span id='spanYear' style='display: none; border-style:solid;border-width:1;border-color:#f9d35f;cursor:pointer' onmouseover='swapImage(\"changeYear\",\"drop2.gif\");this.style.borderColor=\"#FFFFFF\";window.status=\""+selectYearMessage+"\"' onmouseout='swapImage(\"changeYear\",\"drop1.gif\");this.style.borderColor=\"#f9d35f\";window.status=\"\"'	onclick='popUpYear()'></span>&nbsp;"

				document.getElementById("caption").innerHTML  =	sHTML1

				bPageLoaded=true;
			}
			checkhasOtherCalendar();
		}

		var LongIsinLayer = false;
		var ShortIsinLayer = false;
		var LayerParentCalendar = "";

		function checkhasOtherCalendar() {
			if(LongIsinLayer==false) {
				for( j = 0; j < document.getElementsByTagName('div').length; j++ )
				{
					divtmp = document.getElementsByTagName('div')[j];
					
					for( i = 0; i < divtmp.getElementsByTagName('img').length; i++ )
					{
						obj = divtmp.getElementsByTagName('img')[i];
						if(obj.src.indexOf('images/calendar/calendar.gif')!=-1)
						{
							if(String(obj.onclick).indexOf('opencalendar')!=-1)
							{
								LongIsinLayer = true;
								ShortIsinLayer = true;
								LayerParentCalendar = divtmp.id;
								break;
							}
						}
					}
				}
			}
		}

		function hideCalendar()	{
			try
			{
				crossobj.visibility="hidden";
				if (crossMonthObj != null){crossMonthObj.visibility="hidden"}
				if (crossYearObj !=	null){crossYearObj.visibility="hidden"}

				showElement( 'SELECT' );
				showElement( 'APPLET' );
			} catch(e) {}
		}

		function padZero(num) {
			return (num< 10) ? '0' + num : num ;
		}

		function constructDate(d,m,y)
		{
			sTmp = dateFormat
			sTmp = sTmp.replace	("dd","<e>")
			sTmp = sTmp.replace	("d","<d>")
			sTmp = sTmp.replace	("<e>",padZero(d))
			sTmp = sTmp.replace	("<d>",d)
			sTmp = sTmp.replace	("mmm","<o>")
			sTmp = sTmp.replace	("mm","<n>")
			sTmp = sTmp.replace	("m","<m>")
			sTmp = sTmp.replace	("<m>",m+1)
			sTmp = sTmp.replace	("<n>",padZero(m+1))
			sTmp = sTmp.replace	("<o>",monthName[m])
			return sTmp.replace ("yyyy",y)
		}

		var eventdoonclose;
		function closeCalendar() {
			var	sTmp
			hideCalendar();
			if (yearSelected>(yearNow+prefixyearAddOn))
			{
				var strvar = padZero(dateNow) + "/" + (padZero(monthNow+1)) + "/" + yearNow;
			} 
			else 
			{
				var strvar = padZero(dateSelected) + "/" + (padZero(monthSelected+1)) + "/" + yearSelected;
			}
			ctlToPlaceValue1.value = strvar;
			eval(eventdoonclose);
		}

		/*** Year Pulldown	***/
		function StartDecYear()
		{
			intervalID2=setInterval("decYear()",80)
		}

		function StartIncYear()
		{
			intervalID2=setInterval("incYear()",80)
		}

		/*** Month Pulldown	***/
		function StartDecMonth()
		{
			intervalID1=setInterval("decMonth()",80)
		}

		function StartIncMonth()
		{
			intervalID1=setInterval("incMonth()",80)
		}

		function incMonth () {
			monthSelected++
			if (monthSelected>11) {
				monthSelected=0
				yearSelected++
			}
			constructCalendar()
		}

		function decMonth () {
			monthSelected--
			if (monthSelected<0) {
				monthSelected=11
				yearSelected--
			}
			constructCalendar()
		}

		function constructMonth() {
			popDownYear()
		//	if (!monthConstructed) {
				sHTML =	""
				iStart=0;
				iEnd=12;

					//iStart=monthNow;
					j=0;
					k=0;

					for(i=iStart; i<iEnd; i++) {
						j = i;
						sName =	monthName[j];
						//j = i + monthNow
						//if (j<=11) {
						//	k = yearNow
						//	sName =	monthName[j];
						//} else {
						//	j = j-12
						//	k = yearNow + 1
						//	sName =	monthName[j];
						//}
						k = yearSelected;
						if (i==monthSelected){
							sName =	"<B>" +	sName +	"</B>"
						}
						sHTML += "<tr><td id='m" + j + "/" + k + "' onmouseover='this.style.backgroundColor=\"#FFBF00\"' onmouseout='this.style.backgroundColor=\"\"' style='cursor:pointer' onclick='monthConstructed=false;monthSelected=" + j + ";yearSelected="+k+";constructCalendar();popDownMonth();event.cancelBubble=true' class=calendar10>&nbsp;" + sName + " &nbsp;</td></tr>"
					}

				document.getElementById("selectMonth").innerHTML = "<table width=43 style='font-family:arial; font-size:11px; border-width:1; border-style:solid; border-color:#FFBF00;' bgcolor='#FFFFDD' cellspacing=0 onmouseover='clearTimeout(timeoutID1)'	onmouseout='clearTimeout(timeoutID1);timeoutID1=setTimeout(\"popDownMonth()\",100);event.cancelBubble=true'>" +	sHTML +	"</table>"

				monthConstructed=true
		//	}
		}

		function popUpMonth() {
			constructMonth()
			crossMonthObj.visibility = (dom||ie)? "visible"	: "show"
			var oldcrossMonthObjleft = crossMonthObj.left;
			crossMonthObj.left = parseInt(crossobj.left) + 50
			if(crossMonthObj.left==oldcrossMonthObjleft) crossMonthObj.left = (parseInt(crossobj.left) + 50) +'px';
			var oldcrossMonthObjtop= crossMonthObj.top;
			crossMonthObj.top = parseInt(crossobj.top) + 26
			if(crossMonthObj.top==oldcrossMonthObjtop) crossMonthObj.top = (parseInt(crossobj.top) + 26) +'px';

			hideElement( 'SELECT', document.getElementById("selectMonth") );
			hideElement( 'APPLET', document.getElementById("selectMonth") );
		}

		function popDownMonth()	{
			crossMonthObj.visibility= "hidden"
		}

		/*** Year Pulldown ***/

		function incYear() {
			for	(i=0; i<7; i++){
				newYear	= (i+nStartingYear)+1
				if (newYear==yearSelected)
				{ txtYear =	"&nbsp;<B>"	+ newYear +	"</B>&nbsp;" }
				else
				{ txtYear =	"&nbsp;" + newYear + "&nbsp;" }
				document.getElementById("y"+i).innerHTML = txtYear
			}
			nStartingYear ++;
			bShow=true
		}

		function decYear() {
			for	(i=0; i<7; i++){
				newYear	= (i+nStartingYear)-1
				if (newYear==yearSelected)
				{ txtYear =	"&nbsp;<B>"	+ newYear +	"</B>&nbsp;" }
				else
				{ txtYear =	"&nbsp;" + newYear + "&nbsp;" }
				document.getElementById("y"+i).innerHTML = txtYear
			}
			nStartingYear --;
			bShow=true
		}

		function selectYear(nYear) {
			yearSelected=parseInt(nYear+nStartingYear);
			yearConstructed=false;
			constructMonth();
			constructCalendar();
			popDownYear();
		}

		function constructYear() {
			popDownMonth()
			sHTML =	""
			if (!yearConstructed) {
				sHTML =	"";
				//sHTML =	"<tr><td align='center'	onmouseover='this.style.backgroundColor=\"#FFBF00\"' onmouseout='clearInterval(intervalID1);this.style.backgroundColor=\"\"' style='cursor:pointer'	onmousedown='clearInterval(intervalID1);intervalID1=setInterval(\"decYear()\",30)' onmouseup='clearInterval(intervalID1)'>-</td></tr>"

				j =	0
				nStartingYear =	yearNow;
				for	(i=(yearNow); i<=(yearNow+prefixyearAddOn); i++) {
					sName =	i;
					if (i==yearSelected){
						sName =	"<B>" +	sName +	"</B>"
					}

					sHTML += "<tr><td id='y" + j + "' onmouseover='this.style.backgroundColor=\"#FFBF00\"' onmouseout='this.style.backgroundColor=\"\"' style='cursor:pointer' onclick='selectYear("+j+");event.cancelBubble=true' class=calendar10>&nbsp;" + sName + "&nbsp;</td></tr>"
					j ++;
				}

				//sHTML += "<tr><td align='center' onmouseover='this.style.backgroundColor=\"#FFCC99\"' onmouseout='clearInterval(intervalID2);this.style.backgroundColor=\"\"' style='cursor:pointer' onmousedown='clearInterval(intervalID2);intervalID2=setInterval(\"incYear()\",30)'	onmouseup='clearInterval(intervalID2)'>+</td></tr>"

				document.getElementById("selectYear").innerHTML	= "<table width=47 style='font-family:arial; font-size:11px; border-width:1; border-style:solid; border-color:#FFBF00;'	bgcolor='#FFFFDD' onmouseover='clearTimeout(timeoutID2)' onmouseout='clearTimeout(timeoutID2);timeoutID2=setTimeout(\"popDownYear()\",100)' cellspacing=0>"	+ sHTML	+ "</table>"

				yearConstructed	= true
			}
		}

		function popDownYear() {
			clearInterval(intervalID1)
			clearTimeout(timeoutID1)
			clearInterval(intervalID2)
			clearTimeout(timeoutID2)
			crossYearObj.visibility= "hidden"
		}

		function popUpYear() {
			var	leftOffset

			constructYear()

			crossYearObj.visibility	= (dom||ie)? "visible" : "show"
			leftOffset = parseInt(crossobj.left) + document.getElementById("spanYear").offsetLeft
			if (ie)
			{
				leftOffset += 6
			}
			var oldcrossYearObjleft = crossYearObj.left;
			crossYearObj.left =	leftOffset
			if(crossYearObj.left==oldcrossYearObjleft) crossYearObj.left = leftOffset +'px';
			var oldcrossYearObjtop = crossYearObj.top;
			crossYearObj.top = parseInt(crossobj.top) +	26
			if(crossYearObj.top==oldcrossYearObjtop) crossYearObj.top = (parseInt(crossobj.top) +	26) +'px';
		}

		/*** calendar ***/
	   function WeekNbr(n) {
		  // Algorithm used:
		  // From Klaus Tondering's Calendar document (The Authority/Guru)
		  // hhtp://www.tondering.dk/claus/calendar.html
		  // a = (14-month) / 12
		  // y = year + 4800 - a
		  // m = month + 12a - 3
		  // J = day + (153m + 2) / 5 + 365y + y / 4 - y / 100 + y / 400 - 32045
		  // d4 = (J + 31741 - (J mod 7)) mod 146097 mod 36524 mod 1461
		  // L = d4 / 1460
		  // d1 = ((d4 - L) mod 365) + L
		  // WeekNumber = d1 / 7 + 1

		  year = n.getFullYear();
		  month = n.getMonth() + 1;
		  if (startAt == 0) {
			 day = n.getDate() + 1;
		  }
		  else {
			 day = n.getDate();
		  }

		  a = Math.floor((14-month) / 12);
		  y = year + 4800 - a;
		  m = month + 12 * a - 3;
		  b = Math.floor(y/4) - Math.floor(y/100) + Math.floor(y/400);
		  J = day + Math.floor((153 * m + 2) / 5) + 365 * y + b - 32045;
		  d4 = (((J + 31741 - (J % 7)) % 146097) % 36524) % 1461;
		  L = Math.floor(d4 / 1460);
		  d1 = ((d4 - L) % 365) + L;
		  week = Math.floor(d1/7) + 1;

		  return week;
	   }

		function constructCalendar () {
			if (currlang == 'th') {
				tmpyearSelected = yearSelected - 543;
			} else {
				tmpyearSelected = yearSelected;
			}
			
			//if ((monthSelected<monthNow) && (yearSelected==yearNow)) yearSelected = yearSelected+1;	//For dropdown changed

			var aNumDays = Array (31,0,31,30,31,30,31,31,30,31,30,31)
			var dateMessage
			var startDate =	new Date (tmpyearSelected,monthSelected,1)
			var endDate

			if (monthSelected==1)
			{
				endDate	= new Date (tmpyearSelected,monthSelected+1,1);
				endDate	= new Date (endDate - (24*60*60*1000));
				numDaysInMonth = endDate.getDate()
			}
			else
			{
				numDaysInMonth = aNumDays[monthSelected];
			}

			datePointer	= 0
			dayPointer = startDate.getDay() - startAt

			if (dayPointer<0)
			{
				dayPointer = 6
			}

			sHTML =	"<table	 border=0 style='font-family:verdana;font-size:10px;'><tr>"

			//if (showWeekNumber==1)
			//{
			//	sHTML += "<td width=27><b>" + weekString + "</b></td><td width=1 rowspan=7 bgcolor='#d0d0d0' style='padding:0px'><img src='"+imgDir+"divider.gif' width=1></td>"
			//}

			for	(i=0; i<7; i++)	{
				//sHTML += "<td width='' align='right'><B>"+ dayName[i]+"</B></td>"
				sHTML += "<td width='' align='center' class=calendar10>"+ dayName[i]+"</td>"
			}
			sHTML +="</tr><tr>"

			//if (showWeekNumber==1)
		//	{
		//		sHTML += "<td align=right>" + WeekNbr(startDate) + "&nbsp;</td>"
		//	}

			for	( var i=1; i<=dayPointer;i++ )
			{
				sHTML += "<td class=calendar10>&nbsp;</td>"
			}

			for	( datePointer=1; datePointer<=numDaysInMonth; datePointer++ )
			{
				dayPointer++;
				//sHTML += "<td align=right>"
				sStyle=styleAnchor
				if ((datePointer==odateSelected) && (monthSelected==omonthSelected) && (yearSelected==oyearSelected))
				{ sStyle+=styleLightBorder }

				sHint = ""
				for (k=0;k<HolidaysCounter;k++)
				{
					if ((parseInt(Holidays[k].d)==datePointer)&&(parseInt(Holidays[k].m)==(monthSelected+1)))
					{
						if ((parseInt(Holidays[k].y)==0)||((parseInt(Holidays[k].y)==yearSelected)&&(parseInt(Holidays[k].y)!=0)))
						{
							sStyle+="background-color:#FFDDDD;"
							sHint+=sHint==""?Holidays[k].desc:"\n"+Holidays[k].desc
						}
					}
				}

				var regexp= /\"/g
				sHint=sHint.replace(regexp,"&quot;")
				dateMessage = "onmousemove='window.status=\""+selectDateMessage.replace("[date]",constructDate(datePointer,monthSelected,yearSelected))+"\"' onmouseout='window.status=\"\"' "

				currentDate = new Date(yearSelected, monthSelected, datePointer)
				//alert(currentDate)

				if ((datePointer==dateNow)&&(monthSelected==monthNow)&&(yearSelected==yearNow))
				{
					sHTML += "<td align=right class=calendar10>"
					sHTML += "<b><a "+dateMessage+" title=\"" + sHint + "\" style='"+sStyle+"' href='javascript:dateSelected="+datePointer+";closeCalendar();'><font color=#ff0000>&nbsp;" + datePointer + "</font>&nbsp;</a></b>"}
				//else if	(dayPointer % 7 == (startAt * -1)+1)
				//{
				//	sHTML += "<td align=right>"
				//	sHTML += "<a "+dateMessage+" title=\"" + sHint + "\" style='"+sStyle+"' href='javascript:dateSelected="+datePointer + ";closeCalendar();'>&nbsp;<font color=#909090>" + datePointer + "</font>&nbsp;</a>" }
				else
				{
					sHTML += "<td align=right class=calendar10>"
					sHTML += "<a "+dateMessage+" title=\"" + sHint + "\" style='"+sStyle+"' href='javascript:dateSelected="+datePointer + ";closeCalendar();'>&nbsp;" + datePointer + "&nbsp;</a>" }

				sHTML += ""
				if ((dayPointer+startAt) % 7 == startAt) {
					sHTML += "</tr><tr>"
				//	if ((showWeekNumber==1)&&(datePointer<numDaysInMonth))
				//	{
				//		sHTML += "<td align=right>" + (WeekNbr(new Date(yearSelected,monthSelected,datePointer+1))) + "&nbsp;</td>"
				//	}
				}
			}

			document.getElementById("calendarcontent").innerHTML   = sHTML
			document.getElementById("spanMonth").innerHTML = "&nbsp;" + monthName[monthSelected] + " &nbsp;<IMG id='changeMonth' SRC='"+imgDir+"drop1.gif' WIDTH='12' HEIGHT='10' BORDER=0>"
			document.getElementById("spanYear").innerHTML =	"&nbsp;" + yearSelected	+ "&nbsp;<IMG id='changeYear' SRC='"+imgDir+"drop1.gif' WIDTH='12' HEIGHT='10' BORDER=0>"
		}

		var prefixyearAddOn = 1;
		function prefixYear(values) {
			if(values==1) {
				prefixyearAddOn = 1;
			} else {
				var tnow = new Date();
				var sMonth = tnow.getMonth() + 1;
				var sYear = tnow.getFullYear();
				var sYearOld = sYear;
				var i;
				for(i=0;i<=17;i++) {
					sMonth = sMonth + 1;
					if(sMonth>=13) {
						sMonth = 1;
						sYear = sYear + 1;
					}
				}
				prefixyearAddOn = sYear - sYearOld;
			}
		}

		function opencalendar(format,ctl1,ctl2, eventonclose, FixShowX, FixShowY) {
			if (typeof(ctl1) == "string") {
				ctl1 = $(ctl1);
			}
			eventdoonclose = eventonclose;
			hideCalendar();
			var	leftpos=0
			var	toppos=0
			if (bPageLoaded)
			{
				if ( crossobj.visibility ==	"hidden" ) {
					ctlToPlaceValue1	= ctl1
					ctlToPlaceValue2	= ctl2
					dateFormat=format;

					formatChar = "/"
					aFormat	= dateFormat.split(formatChar)

					tokensChanged =	0
					if ( formatChar	!= "" )
					{
						var strDate
						if (ctl1.value == "")
						{
							strDate = padZero(dateNow) + "/" + padZero(monthNow + 1) + "/" + yearNow;
						}
						else
						{
							strDate = ctl1.value;
						}

						aData =	strDate.split(formatChar)

						for	(i=0;i<3;i++)
						{
							if ((aFormat[i]=="d") || (aFormat[i]=="dd"))
							{
								dateSelected = parseInt(aData[i], 10)
								tokensChanged ++
							}
							else if	((aFormat[i]=="m") || (aFormat[i]=="mm"))
							{
								monthSelected =	parseInt(aData[i], 10) - 1
								tokensChanged ++
							}
							else if	(aFormat[i]=="yyyy")
							{
								yearSelected = parseInt(aData[i], 10)
								tokensChanged ++
							}
							else if	(aFormat[i]=="mmm")
							{
								for	(j=0; j<12;	j++)
								{
									if (aData[i]==monthName[j])
									{
										monthSelected=j
										tokensChanged ++
									}
								}
							}
						}
					}

					if ((tokensChanged!=3)||isNaN(dateSelected)||isNaN(monthSelected)||isNaN(yearSelected))
					{
						dateSelected = dateNow
						monthSelected =	monthNow
						yearSelected = yearNow
					}

					odateSelected=dateSelected;
					omonthSelected=monthSelected;
					oyearSelected=yearSelected;

				    var pos = Element.cumulativeOffset(ctl2);
				    toppos  = pos['top'];
					leftpos = pos['left'];
					
					toppos  = ctl2.clientHeight + toppos;
					//leftpos = leftpos - document.getElementById("calendar").clientWidth;
					
					toppos -= calOffsetCompensate.top;
					leftpos -= calOffsetCompensate.left;
					
					if(leftpos<0) leftpos = 0;

					var oldcrossobjleft = crossobj.left;
					crossobj.left =	leftpos + 'px';
					
					var oldcrossobjtop = crossobj.top;
					crossobj.top = (toppos + 5) + 'px';

					constructCalendar(1, monthSelected, yearSelected);
					crossobj.visibility = (dom||ie) ? "visible" : "show"

					hideElement('SELECT', document.getElementById("calendar"));
					hideElement('APPLET', document.getElementById("calendar"));

					bShow = true;
				}
				else
				{
					hideCalendar();
					if (ctlNow!=ctl1) {opencalendar(format,ctl1,ctl2, eventonclose, FixShowX, FixShowY)}
				}
				ctlNow = ctl1;
			}
		}

		var _is_ie=document.all;
		var _have_dom=document.getElementById;
		function getEl(tmpname) {
			var a = (_have_dom)?document.getElementById(tmpname) : _is_ie? eval("document.all."+tmpname)	: eval("document."+tmpname)
			return a;
		}

		function checkattach(wevent,names,wfunc) {
			var oldonload;
			oldonload = eval(wevent);
			if(typeof(oldonload)=='function') {
				eval(wevent+'=function '+names+'() {oldonload();'+wfunc+'();}');
			} else {
				eval(wevent+'=function '+names+'() {'+wfunc+'();}');
			}
		}

		function hidecal1 () {
//			try {
//				if (event.keyCode==27)
//				{
//					hideCalendar()
//				}				
//			} catch(e) {}
		}

		checkattach("document.onkeypress","addhideandonkeypress","hidecal1");

		function hidecal2 () {
			if (!bShow)
			{
				hideCalendar()
			}
			bShow = false
		}

		checkattach("document.onclick","addhideandonclick","hidecal2");

		//checkattach("window.onload","onloadinitca","initca");
		initca();
	}
;
/*
ajax section
*/
var tmpDivNaMe = 'divAwdAjaxArea';
if(!document.getElementById(tmpDivNaMe)) document.write('<div id="' + tmpDivNaMe + '" name="' + tmpDivNaMe + '"></div>');

var objAjax = null;
var awdTasks;

function initTasks()
{
	if(!awdTasks) awdTasks = new class_awdTasks();
}

function class_awdTasks()
{
	this.initParam = function()
	{
		this.arrRequests = new Array();
		this.arrFrames = new Array();
	}
	this.setRequest = function(id, obj)
	{
		this.arrRequests[id] = obj;
	}
	this.getRequest = function(id)
	{
		return this.arrRequests[id];
	}
	this.makeRequest = function()
	{
		var obj = (arguments[0]) ? arguments[0] : new Object();
		return new Number(this.arrRequests.push(obj) - 1);
	}
	this.deleteRequest = function(id)
	{
		delete(this.arrRequests[id]);
	}
	this.setFrame = function(id, obj) {
		this.arrFrames[id] = obj;
	}
	this.getFrame = function(id) {
		return this.arrFrames[id];
	}
	this.deleteFrame = function(id)
	{
		delete(this.arrFrames[id]);
	}
	this.ready = function(id)
	{
		var tmpReq = this.getRequest(id);
		var tmpHTML = (arguments[1]) ? arguments[1] : "XxX";
		if(tmpHTML=="XxX") {
			if(tmpReq.callback instanceof Function) {
				tmpReq.callback(tmpReq.argsend, tmpHTML);
			}
			var tmpdom = new awdElement();
			if(document.getElementById(tmpdom.awdPrefix + id)) tmpdom.removeElement(document.getElementById(tmpdom.awdPrefix + id));
			this.deleteRequest(id);
		} else {
			if(tmpReq.typerun=='javascript') eval(tmpHTML);
			else {
				if(tmpReq.callback instanceof Function) {
					tmpReq.callback(tmpReq.argsend, tmpHTML);
				}
				var tmpdom = new awdElement();
				if(document.getElementById(tmpdom.awdPrefix + id)) tmpdom.removeElement(document.getElementById(tmpdom.awdPrefix + id));
				this.deleteRequest(id);
			}
		}
	}
	this.initParam();
}

function awdElement() 
{
	this.reqId = 'awdAjaxRequestId_';
	this.awdPrefix = 'awdGroup_';
	this.awdPrefixChild = 'divAwdAjaxChild';
	this.removeElement = function(elementName)
	{
		elementName.parentNode.removeChild(elementName);
	}
  
	this.createElement = function(parentElement, elementType, needProperty)
	{
		var textShow = (arguments[3]) ? arguments[3] : "";
		var el = document.createElement(elementType);
		var i = 0;
		for (var k in needProperty) 
		{
			var keys = k.split('.');
			if (keys.length == 2) el[keys[0]][keys[1]] = needProperty[k];
			else el[k] = needProperty[k];
		}
		try {el.innerHTML = textShow;} catch(e) {}
		parentElement.appendChild(el);
		return el;
	}

	this.createScript = function( parentElement, id, url )
	{ 
		var span = this.createElement( parentElement, 'span', {'style.display' : 'none', 'id' : id}, '%<scr' + 'ipt></' + 'script>' );
		setTimeout(
			function() {
				var tmpscript  = span.getElementsByTagName('script')[0];
				tmpscript.type = 'text/javascript';
				tmpscript.src  = url;
			}, 5
		);
	}
}

function awdAjax()
{
	this.awdError = function(errMessage, url, errLine)
	{
		var tmpFile = "File : " + url + " Line : " + errLine + "\n";
		var tmperror = "Error : " + errMessage + "\n" + tmpFile;
		if(errMessage.indexOf('unterminated string literal') + errMessage.indexOf('missing ;') + errMessage.indexOf('Syntax error') > -3) 
		{}
		alert(tmperror);
	}

	this.initParam = function()
	{
		this.setError = true;
		if(this.setError) window.onerror = this.awdError;

		this.dom = new awdElement();
		if(document.getElementById(tmpDivNaMe)) this.divAwdAjax = document.getElementById(tmpDivNaMe);
		else this.divAwdAjax = this.dom.createElement(document.body, 'div', {'id' : tmpDivNaMe});
	}

	this.validateFunction = function(callback)
	{
		if(callback && callback instanceof Function) return callback;
		else return function() {};
	}

	this.exec_query = function(url, callback)
	{
		var tmpid = (arguments[2]) ? arguments[2] : awdTasks.makeRequest();
		var methodToUse = (arguments[3]) ? arguments[3].toUpperCase() : "GET";
		var multiThread = (arguments[4]) ? arguments[4] : false;
		var argsend = (arguments[5]) ? arguments[5] : new Array();
		var typerun = (arguments[6]) ? arguments[6] : "html";
		var domuse = (arguments[7]) ? arguments[7] : "xml";
		callback = this.validateFunction(callback);
		var xmldom;
		try {xmldom = new XMLHttpRequest();} catch(e) {
			try {xmldom = new ActiveXObject('Msxml2.XMLHTTP');} catch(e) {
				try {xmldom = new ActiveXObject('Microsoft.XMLHTTP');} catch(e) {
					xmldom = null;
				}
			}
		}
		if((domuse=="xml") && (xmldom==null)) domuse = "awd";

		if(methodToUse=="GET") {
			awdTasks.setRequest(tmpid, {'callback' : callback, 'request' : url, 'argsend' : argsend, 'typerun' : typerun});
			(url.indexOf('?')==-1) ? url = url + '?' : url = url + '&';
			url = url + this.dom.reqId + '=' + tmpid;
		} else 

		if(methodToUse=="POST") {
			var variablesend = "";
			var tmpindexOf = url.indexOf("?");
			if(tmpindexOf!=-1) {
				variablesend = url.substring(tmpindexOf+1, url.length);
				url = url.substring(0, tmpindexOf);
			}
			if(variablesend=="") variablesend = this.dom.reqId + '=' + tmpid;
			else variablesend = variablesend + '&' + this.dom.reqId + '=' + tmpid;

			awdTasks.setRequest(tmpid, {'callback' : callback, 'request' : url, 'argsend' : argsend, 'typerun' : typerun});
		}

		if(domuse=="awd") {
			if(methodToUse=="GET") {
				//response must to be only javascript
				this.dom.createScript(this.divAwdAjax, this.dom.awdPrefix + tmpid, url);
			} else 
			
			if(methodToUse=="POST") {
				//response can be html or javascript upon callback function to process
				//html
				//   callback(HTML, typerun) {alert(HTML);}
				//javascript
				//   callback(HTML, typerun) {eval(HTML);}
				return this.frame({'url' : url, 'onComplete' : callback, 'argsend' : argsend, 'typerun' : typerun}, tmpid, multiThread);
			}
		} else {
			if(methodToUse=="GET") {
				xmldom.open(methodToUse, url, true);
				xmldom.onreadystatechange = function() {
					if(xmldom.readyState==4) {
						awdTasks.ready(tmpid, xmldom.responseText);
					}
				}
				xmldom.send(null);
			} else 
			
			if(methodToUse=="POST") {
				xmldom.open(methodToUse, url, false);
				xmldom.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
				xmldom.send(variablesend);
				awdTasks.ready(tmpid, xmldom.responseText);
			}
		}
	}

	this.ready = function(id)
	{
		var tmpReq = awdTasks.getRequest(id);
		if(tmpReq.callback instanceof Function) tmpReq.callback(tmpReq.argsend);
		if(document.getElementById(this.dom.awdPrefix + id)) this.dom.removeElement(document.getElementById(this.dom.awdPrefix + id));
		awdTasks.deleteRequest(id);
	}

	this.frame = function(c) 
	{
		var tmpid = (arguments[1]) ? arguments[1] : awdTasks.makeRequest();
		var multiThread = (arguments[2]) ? arguments[2] : false;
		var url = (c && c.url) ? c.url : "about:blank";
		var objRunResponse;
		objRunResponse = (multiThread) ? "awdTasks.getFrame("+tmpid+")" : "objAjax";
		var n = 'ifrmAwdAjax' + tmpid;
		var d = this.dom.createElement(this.divAwdAjax, 'div', {'id' : this.dom.awdPrefixChild+tmpid}, '<iframe style="display:;" height="100" width="100" src="" id="'+n+'" name="'+n+'" onload="'+objRunResponse+'.loaded(\''+n+'\', '+tmpid+')"></iframe>' );
		var i = document.getElementById(n);
		i.src = url;
		if(c && typeof(c.onComplete) == 'function') i.onComplete = c.onComplete;
		if(c && typeof(c.argsend) == 'object') i.argsend = c.argsend;
		return n;
	}
  
	this.form = function(f, name) {
		f.setAttribute('target', name);
	}
  
	this.submit = function(f, c) {
		var tmpid = (arguments[2]) ? arguments[2] : awdTasks.makeRequest();
		this.form(f, this.frame(c, tmpid, true));
		if(c && c.onStart instanceof Function) return c.onStart(f);
		else return true;
	}

	this.loaded = function(id, tmpid) {
        var i = document.getElementById(id);
        if (i.contentDocument) var d = i.contentDocument;
        else if (i.contentWindow) var d = i.contentWindow.document;
        else var d = window.frames[id].document;
        if (d.location.href == "about:blank") return;

		//if(i.onComplete instanceof Function) i.onComplete(i.argsend, d.body.innerHTML);
		awdTasks.ready(tmpid, d.body.innerHTML);
		if(i) {
			this.dom.removeElement(document.getElementById(this.dom.awdPrefixChild+tmpid));
			//awdTasks.deleteRequest(tmpid);
			awdTasks.deleteFrame(tmpid);
		}
	}
	this.initParam();
}

/*
e.g.
runReturnFunction("sendparam.php?id=10", doneReturn);
function doneReturn(argsend, P) {
	//P is response look like text
	//should be use eval to compile text to command
	//e.g. P = "var Error = false;"
	eval(P);
	if(Error) alert("Has something error");
	else alert("OK");
}
function doneReturn(argsend, P) {   
	document.getElementById('r').innerHTML = P;
}
*/
function runAjax() {
	initTasks();
	var url = (arguments[0]) ? arguments[0] : null;
	var callback = (arguments[1]) ? arguments[1] : null;
	var multiThread = (arguments[2]) ? arguments[2] : false;
	var setMethod = (arguments[3]) ? arguments[3].toUpperCase() : "GET";
	var argsend = (arguments[4]) ? arguments[4] : new Array();
	var typerun = (arguments[5]) ? arguments[5] : "html";
	var domuse = (arguments[6]) ? arguments[6] : "xml";
	var tmparray = new Array();
	var tmpid = awdTasks.makeRequest();
	if(multiThread) {
		eval("var objAjax"+tmpid+" = new awdAjax();");
		eval("tmparray[0] = objAjax"+tmpid+";");
		awdTasks.setFrame(tmpid, tmparray[0]);
	} else {
		if(objAjax==null) objAjax = new awdAjax();
		tmparray[0] = objAjax;
	}
	tmparray[0].exec_query(url, callback, tmpid, setMethod, multiThread, argsend, typerun, domuse);
}

function runXmlReturnJavascript(url) {
	var callback = function() {}
	var multiThread = (arguments[1]) ? arguments[1] : false;
	var argsend = new Array();
	if(typeof(multiThread)=="object") {
		for(var k in multiThread) {
			if(k=="function") callback = multiThread[k];
			else if(k=="argsend") argsend = multiThread[k];
		}
		multiThread = false;
	}
	var setMethod = (arguments[2]) ? arguments[2].toUpperCase() : "GET";

	runAjax(url, callback, multiThread, setMethod, argsend, 'javascript', 'xml');
}

function runAwdReturnJavascript(url) {
	var callback = function() {}
	var multiThread = (arguments[1]) ? arguments[1] : false;
	var argsend = new Array();
	if(typeof(multiThread)=="object") {
		for(var k in multiThread) {
			if(k=="function") callback = multiThread[k];
			else if(k=="argsend") argsend = multiThread[k];
		}
		multiThread = false;
	}
	var setMethod = (arguments[2]) ? arguments[2].toUpperCase() : "GET";

	runAjax(url, callback, multiThread, setMethod, argsend, 'javascript', 'awd');
}

function runXmlReturnHtml(url, callback) {
	var multiThread = (arguments[2]) ? arguments[2] : false;
	var setMethod = (arguments[3]) ? arguments[3] : "POST";
	var argsend = new Array();
	if(typeof(callback)=="object") {
		var tmpcallback = callback;
		for(var k in tmpcallback) {
			if(k=="function") callback = tmpcallback[k];
			else if(k=="argsend") argsend = tmpcallback[k];
		}
	}

	runAjax(url, callback, multiThread, setMethod, argsend, 'html', 'xml');
}

function runAwdReturnHtml(url, callback) {
	var multiThread = (arguments[2]) ? arguments[2] : false;
	var setMethod = "POST";
	var argsend = new Array();
	if(typeof(callback)=="object") {
		var tmpcallback = callback;
		for(var k in tmpcallback) {
			if(k=="function") callback = tmpcallback[k];
			else if(k=="argsend") argsend = tmpcallback[k];
		}
	}

	runAjax(url, callback, multiThread, setMethod, argsend, 'html', 'awd');
}

function runFormReturn(f, callback) {
	initTasks();
	var tmparray = new Array();
	var tmpid = awdTasks.makeRequest();
	eval("var objAjax"+tmpid+" = new awdAjax();");
	eval("tmparray[0] = objAjax"+tmpid+";")
	awdTasks.setFrame(tmpid, tmparray[0]);
	return tmparray[0].submit(f, {
			'onStart' : ((callback && callback.onStart instanceof Function) ? callback.onStart : ""), 
			'onComplete' : (callback && callback.onComplete instanceof Function) ? callback.onComplete : ""
			}, tmpid);
}

/*
useful function
*/
function setInnerHTML(textShow, elementId) 
{
	var showError = (arguments[2]) ? arguments[2] : true;
	var divspan = document.getElementById(elementId);
	if(typeof(divspan)!='object') {
		if(showError) alert("Does not have object id : " + elementId);
		return false;	
	}
	var tag;
	try {
		tag = divspan.tagName;
	} catch(e) {
		tag = "";
	}
	if(tag!="") tag = tag.toUpperCase();
	if((tag=="DIV") || (tag=="SPAN")) divspan.innerHTML = textShow;
	else if(showError) alert("Can not set text : " + textShow);
}

/*
user defined function
*/
function runPostForm(f, startCallback) {
	runFormReturn(f, {'onStart' : startCallback, 'onComplete' : completeCallback});
}

function donereturn(argsend, P) {
	setInnerHTML(P, 'myElement');
}

function clearHTML() {
	setInnerHTML("Loading...", 'myElement');
}

var zdgfdf1;
var zdgfdf2;
var zdgfdf3;

function AAA1() {
	zdgfdf1.submit();
}

function AAA2() {
	zdgfdf2.submit();
}

function AAA3() {
	zdgfdf3.submit();
}

function startCallback1(f) {
	zdgfdf1 = f;
	setTimeout(AAA1, 3000);
	return false;
}

function startCallback2(f) {
	zdgfdf2 = f;
	setTimeout(AAA2, 3000);
	return false;
}

function startCallback3(f) {
	zdgfdf3 = f;
	setTimeout(AAA3, 3000);
	return false;
}

function completeCallback(response) {
	document.getElementById('nr').innerHTML = parseInt(document.getElementById('nr').innerHTML) + 1;
	document.getElementById('r').innerHTML = document.getElementById('r').innerHTML+'<br>'+response;
}


;
/* 
 * MATRIX CLASSES
 *
 * Matrix
 * Reservation
 * Restriction
 */

String.prototype.splitOnUnderscore = String.prototype.split.curry("_");

Array.prototype.multiSort = function(index) {
	for(var i=0; i<this.length; i++) {
		var temp = this[i].splice(index,1);
		this[i].unshift(temp);
	}
return merge_sort(this,function (a,b) {return a[0][0] == b[0][0] ? 0 : (a[0][0] < b[0][0] ? -1 : 1)});
//	return this.sort(function (a,b) {return a[0] == b[0] ? 0 : (a[0] < b[0] ? -1 : 1)});
} 

/**
 * Matrix Class
 */
function Matrix(requestedId, startDate, displayDays, languageCode, showOnRequest) {
	//full parameter is (requestedId, startDate, displayDays, languageCode, showOnRequest, skin, usePagination, resultPerPage)
	//normally send only (requestedId, startDate, displayDays, languageCode, showOnRequest)
	//for asiawebdirect.com destination page, we will show with skin "list" and show 12 hotels per page
	//so asiawebdirect.com will send (requestedId, startDate, displayDays, languageCode, showOnRequest, "list", true, 10)
	var tmp_fix_skin = (arguments[5]) ? arguments[5] : 'matrix';
	var tmp_usePagination = (arguments[6]) ? arguments[6] : false;
	var tmp_resultPerPage = (arguments[7]) ? arguments[7] : 5;
	if((tmp_fix_skin=="list") || (tmp_fix_skin=="matrix") || (tmp_fix_skin=="photo_list")) {}
	else {tmp_fix_skin = "matrix";}

	try {if(tmp_usePagination!=true) tmp_usePagination = false;} catch (e) {tmp_usePagination = false;}
	try {if(tmp_resultPerPage<=0) tmp_resultPerPage = 12;} catch (e) {tmp_resultPerPage = 12;}

	this.loaded = false;
    this.requestedId = requestedId;
    this.startDate = startDate;
    this.days = displayDays;
    this.endDate = "";
    this.languageCode = languageCode;
    this.showOnRequest = showOnRequest;
    this.matrix = null;
    this.checkIn = "";
    this.checkOut = "";
    
    this.renderFilter = true;
    
    this.extractQueryParams();

    this.reservation = null;
    this.lastRatePlan = null;
    this.lastRatePlanClone = null;
    this.lastRatePlanBlurb = null;
    this.restrictions = new Restriction();
    
    this.xDomain = true;
    this.destMatrix = false;
    this.domainName = 'localhost';
    this.skin = tmp_fix_skin;
    
    this.matrixType = "Hotel";
    
    this.matrixActions = new Array();
    this.matrixActions["Hotel"] = "hotel";
    this.matrixActions["Destination"] = "dest";
    this.matrixActions["MultipleHotel"] = "hotels";
    this.matrixActions["AccomType"] = "searchType";
    
    this.resultPerPage = tmp_resultPerPage;
    this.pageNo = 1;
    this.usePagination = tmp_usePagination;
    
    this.sortDirection = {"Popular": -1, "HotelName": 1, "Category": -1, "LowRate": 1, "GuestRating": -1, "Price": 1, "PriceDesc" : -1, "Header": 1};
    this.curSortBy = "Popular";
    this.mapResultFieldName = {"HotelName": "name", "Category": "rating", "GuestRating": "guest_rating", "Price": "lowestRateNum", "PriceDesc" : "lowestRateNum", "Header": "header_idx", "Popular" : "popularity" }
}

	Matrix.prototype.sortData = function(by) {
		// need to sort by hotel name first for price and star rating
		if (by=="Category" || by=="Price") {
			var current = this.curSortBy;
			var nameDirection = this.sortDirection[by];
			this.sortDirection["HotelName"] = 1;
			this.curSortBy = 'HotelName';
			this.sort();
			this.curSortBy = current;
			this.sortDirection["HotelName"] = nameDirection;
		}
		if (arguments[1] && this.curSortBy==by) this.sortDirection[by] = this.sortDirection[by] * -1;
		this.curSortBy = by;
		this.sort();

		// if there is grouping, sort again by group header
		if (this.data.places) {
			this.curSortBy = 'Header';
			this.sort();
			this.curSortBy = by;
		}
	}

	Matrix.prototype.sortBy = function(by) {
		this.sortData(by, true); // 2nd parameter force the sort data function not to toggle sort direction.
		this.renderFilter = false;
		this.setSkin(this.skin);
	}
	
	Matrix.prototype.sort = function() {
		// we sort both data.results and data.showResults
		// so we can filter and display it correctly afterward
		var by = this.curSortBy;
		var asc = this.sortDirection[by];
		var field_name = this.mapResultFieldName[by];
		if (typeof(this.data) != "undefined")
		{
			switch (by) {
			    case "Popular":
					this.data.results = merge_sort(this.data.results, this._numComparator(field_name, asc)); 
					this.data.showResults = merge_sort(this.data.results, this._numComparator(field_name, asc)); 
					break;

				case "Price":
					this.data.results = merge_sort(this.data.results, this._numComparator(field_name, asc)); 
					this.data.showResults = merge_sort(this.data.results, this._numComparator(field_name, asc)); 
					break;
					
				case "Category":
					this.data.results = merge_sort(this.data.results, this._numComparator(field_name, asc)); 
					this.data.showResults = merge_sort(this.data.results, this._numComparator(field_name, asc)); 
					break;
					
				case "HotelName":
					this.data.results = merge_sort(this.data.results, this._stringComparator(field_name, asc)); 
					this.data.showResults = merge_sort(this.data.results, this._stringComparator(field_name, asc)); 
					break;
					
				case "GuestRating":
					this.data.results = merge_sort(this.data.results, this._numComparator(field_name, asc)); 
					this.data.showResults = merge_sort(this.data.results, this._numComparator(field_name, asc)); 
					break;
					
				case "Header":
					this.data.results = merge_sort(this.data.results, this._numComparator(field_name, asc)); 
					this.data.showResults = merge_sort(this.data.results, this._numComparator(field_name, asc)); 
					break;

				default: return;
			}
		}
	}
	
	Matrix.prototype._numComparator = function(by, asc) {
		return function (a, b) { return (parseFloat(new Number(a[by])) - parseFloat(new Number(b[by]))) * asc; };
	}
	
	Matrix.prototype._stringComparator = function(by, asc) {
		return function (a, b) {
			if ( a[by].toLowerCase() < b[by].toLowerCase() ) return -1 * asc;
			if ( a[by].toLowerCase() > b[by].toLowerCase() ) return 1 * asc;
			return 0;
		};
	} 

	Matrix.prototype.filterData = function() {
		this.filter = new Filter();
		this.filter.currencyCode = this.data.currency;
		this.filter.loadFilters();
		
		this.data.totalShowResult = 0;
		this.data.showResults = new Array();
		for (var i=0; i<this.data.results.length; i++) {
			if (this.filter.computeFilters(this.data.results[i])) {
				this.data.results[i].Show = true;
				this.data.showResults.push(this.data.results[i]);
				this.data.totalShowResult +=1 ;
			} else {
				this.data.results[i].Show = false;
			}
		}
		
		// Featured Hotel
		this.data.showFeaturedHotels = new Array();
		if (this.data.featured) {
			for (var i=0; i < this.data.featured.length; i++) {
				if (this.filter.computeFilters(this.data.featured[i])) {
					this.data.featured[i].Show = true;
					this.data.showFeaturedHotels.push(this.data.featured[i]);
				} else {
					this.data.featured[i].Show = false;
				}
			}
		}
		
		// reset page
		this.pageNo = 1;
		this.renderFilter = false;
	}

	Matrix.prototype.doFilter = function() {
		this.filterData();
		if (this.matrixType != "MultipleHotel") {
		    document.fire("searchResults:listChange", this.data.showResults);
		}
		this.setSkin(this.skin);
	}
	
	Matrix.prototype.sortShow = function() {
		this.data.results.sort(function(a, b) { if(b.Show>a.Show) { return 1 } else { return 0 } });
	}

	Matrix.prototype.setUsePagination = function(setValue) {
		this.usePagination = setValue;
	}
	
	Matrix.prototype.movePrevious = function() {
		this.pageNo -=1;
		this.renderFilter = false;
		this.setSkin(this.skin);
	}

	Matrix.prototype.moveNext = function() {
		this.pageNo +=1;
		this.renderFilter = false;
		this.setSkin(this.skin);
	}
	
	Matrix.prototype.gotoPage = function(pageNo) {
		this.pageNo = parseInt(pageNo);
		this.renderFilter = false;
		this.setSkin(this.skin);
	}
	
	Matrix.prototype.setResultPerPage = function(resultNo) {
		this.resultPerPage = resultNo;
	}

    Matrix.prototype.enableXDomain = function(domainName) {
    	this.domainName = domainName;
    }
    
    Matrix.prototype.setMatrixType = function(matrixType) {
    	this.matrixType = matrixType;
    }
    
    Matrix.prototype.setRequestedId = function(requestedId) {
    	this.requestedId = requestedId;
    }

    Matrix.prototype.setParacheckInOut = function(_tmp_checkIn, _tmp_checkOut) {
		if(String(_tmp_checkIn)!="null")
		if(String(_tmp_checkOut)!="null")
		if(String(_tmp_checkIn).substring(0,1)=="2")
		if(String(_tmp_checkOut).substring(0,1)=="2")
		{
        	var checkIn = strToDate(_tmp_checkIn);
        	var my_date = new Date();
        	var to_day = new Date(my_date.getFullYear(), my_date.getMonth(), my_date.getDate());
        	if (checkIn >= to_day) {
				this.checkIn = _tmp_checkIn;
				this.checkOut = _tmp_checkOut;
				this.startDate = 'checkIn';
        	}
		}
		this.loadMatrix();
    }

    Matrix.prototype.setCookie = function(requestedId) {
		var url = "/asahi/setcookie.php?mtxSetCookie=1&mtxCheckIn=" + this.checkIn + "&mtxCheckOut=" + this.checkOut + "&tm="+(Math.random());
		this._doMatrixRequest(url);
    }

    Matrix.prototype.extractQueryParams = function() {
        var checkInParam  = queryParam("mtxCheckIn");
        var checkOutParam = queryParam("mtxCheckOut");
        if (checkInParam != '' && checkOutParam != '') {
        	var checkIn = strToDate(checkInParam);
        	var my_date = new Date();
        	var to_day = new Date(my_date.getFullYear(), my_date.getMonth(), my_date.getDate());
        	
        	if (checkIn < to_day) return;

        	this.checkIn   = checkInParam;
        	this.checkOut  = checkOutParam;
        	this.startDate = 'checkIn';
        }
        
        // allow query params to specify portal
        var portal = queryParam('mtxPortal');
        if (portal != '') {
        	window.mtx_portal = portal;
        }
    }
    
    Matrix.prototype.extractCookie = function() {
		if((this.checkIn==null) || (this.checkIn==""))
		{
			var url = "/asahi/setcookie.php?tm="+(Math.random());
			this._doMatrixRequest(url);
		}
		else
		{
			this.loadMatrix();
		}
	}

    Matrix.prototype.loadMatrix = function () {
    	var action = this.matrixActions[this.matrixType];
        url = "/asahi/frontend.php/rates/" + action + "/" +this.languageCode + "/"  + this.requestedId+ "/" + this.startDate  + "/" + this.days  + "/" + this.showOnRequest;
        
        if (this.checkIn && this.checkIn != "")
        	url = url + "/" + this.checkIn  + "/" + this.checkOut;
        document.fire("matrix:loading", this);
        this._doMatrixRequest(url);
    }

    Matrix.prototype._doMatrixRequest = function (url) {
        url = 'http://' + this.domainName + url;
        var headNode = document.getElementsByTagName("head")[0];
        var script   = document.createElement('script');
        script.type  = 'text/javascript';
        script.src   = url;
        headNode.appendChild(script);
    }
    
    Matrix.prototype.displayMatrix = function(data) {
    	this.displayReady = false;
    	this.waitingForDisplayCurrency = false;
    	if (this.matrixType=="AccomType" || this.matrixType=="MultipleHotel") {
    		// multi-currencies matrix, have to set display matrix
    		// if no display currency cookies, get currency by IP
    		if (!getCookie('ccCodePersist')) {
    			this.waitingForDisplayCurrency = true;
    			this._doMatrixRequest('/asahi/frontend_dev.php/geoip/currency');
    		}
    	}
        this.lastRatePlan = null;
        this.lastRatePlanClone = null;
        this.lastRatePlanBlurb = null;
        if (data["detail"]) {
        	this.beginDate = data["detail"]["beginDate"];
            this.startDate = data["detail"]["startDate"];
            this.endDate   = data["detail"]["endDate"];
            if (data["detail"]["checkIn"]) this.checkIn   = data["detail"]["checkIn"];
            if (data["detail"]["checkOut"]) this.checkOut  = data["detail"]["checkOut"];
            
            this.numCols   = data["detail"]["numCols"];
        }
        if (this.data != null) {
        	this.accomList = this.data.accomList;
        } else {
        	this.accomList = [];
        }
        this.data = data;
        this.filterData();
        if (this.matrixType != "Hotel") {
            this.sortData(this.curSortBy);
        }
        this.applySkin(data);
        this.accomList = this.data.accomList;
        if (!this.loaded) this.doInitialLoad(data);
        this.restrictions.initialise(data["results"]);
        
        if (getCookie('mtxBookCheckInDate')!=null && getCookie('mtxBookCheckOutDate')!=null) {
        	this.checkIn = getCookie('mtxBookCheckInDate');
        	this.checkOut = getCookie('mtxBookCheckOutDate');
        	delCookie('mtxBookCheckInDate');
        	delCookie('mtxBookCheckOutDate');
        }
        
        if (this.beginDate && this.checkIn && this.checkOut) {
        	// Check beginDate with checkInDate for each timezone.
            if (this.checkIn < this.beginDate) { this.checkIn = data["detail"]["beginDate"] }
            if (this.checkOut <= this.beginDate) { this.checkOut = formatDate(incrementDate(strToDate(data["detail"]["beginDate"]), 1)) }
        }
        
        if (this.checkIn && this.checkOut) {
        	if (!this.reservation) {
        		this.reservation = new Reservation();
        		this.reservation.setNights(strToDate(this.checkIn), strToDate(this.checkOut));
        	}
        }
        
        if (this.reservation) {
        	if (this.reservation.numNights>0) {
        		this.reservation.setRatePlanInvalidDates();
        	}
        	this.reservation.setDateSelected();
        }
        
        document.fire("matrix:checkInOutSetExternaly", this); // synchronize calendar dates with matrix checkin/checkout dates
        this.displayReady = true;
        this.loaded = true;
    	if (!this.waitingForDisplayCurrency) {
    		document.fire("matrix:loaded", this);
    	}
    	
        if (this.data.results.length == 0) {
        	document.fire("matrix:noResults", this);
        }
    }
    
    Matrix.prototype.setDisplayCurrencyExternally = function(currencyCode) {
    	if (this.displayReady) {
    		document.fire("matrix:loaded", this);
    	} else {
    		this.waitingForDisplayCurrency = false;
    	}
    }
    
    Matrix.prototype.doInitialLoad = function(data) {
		// tooltip
		var ttDiv = document.createElement("div");
		ttDiv.id = "mtx_rateBlurb";
		ttDiv.className = "popup-container";
		ttDiv.style.display = 'none';
		
		div_top = document.createElement("div");
		div_top.className = "popup-top";
		ttDiv.appendChild(div_top);
		
		div_body = document.createElement("div");
		div_body.className = "popup-body";
		ttDiv.appendChild(div_body);
		
		div_bottom = document.createElement("div");
		div_bottom.className = "popup-bottom";
		ttDiv.appendChild(div_bottom);
		
		

	    ttP = document.createElement("p");
	    ttP.id = "mtx_rateBlurbMsg";
	    div_body.appendChild(ttP);

		document.body.appendChild(ttDiv);

		// Error
		var ttDiv = document.createElement("div");
		ttDiv.id = "dealSelectionError";
		ttDiv.className = "dealselectionerror";
		ttDiv.style.display = 'none';

	    ttP = document.createElement("p");
	    ttP.id = "mtx_errorMsg";
	    ttDiv.appendChild(ttP);

        ttP = document.createElement("p");
        ttP.id = "mtx_errorMsgCloseButton";
        ttP.innerHTML = '<span id="mtx_errorButton"></span>&nbsp;<input id="errMsgCloseBtn" type="submit" value = "Close" onclick="hideDealSelectionError()" />';
        ttP.style.textAlign = 'center';
        ttDiv.appendChild(ttP);

        document.body.appendChild(ttDiv);
        
        var pink_popup = document.createElement("div");
        pink_popup.id = "pink_popup";
        pink_popup.className = "floatbox-cover";
        pink_popup.style.display = 'none';
        pink_popup.innerHTML = '<div class="floatbox-top"><span class="floatbox-header">Sorry, you can\'t book these dates</span></div><div id="pink_popup_message" class="floatbox-text"></div><div class="floatbox-bottom"></div>';        
        document.body.appendChild(pink_popup);
        
        initializeCalendar();
        //startapp(document.forms['checkAvailShort'], "");
    }
    
    Matrix.prototype.setSkin = function(name) {
    	this.skin = name;
    	var data = this.data;
    	this.applySkin(data);
    	document.fire("matrix:loaded", this);
    	document.fire("matrix:checkInOutSetExternaly", this); // synchronize calendar dates with matrix checkin/checkout dates
    }
    
    Matrix.prototype.applySkin_list = function(data) {
    	var mtx = tmpl_str(data.skins.list.template_list, data);
    	//if (!this.loaded) {
    		this.matrix.innerHTML = tmpl_str(data.skins.list.template_outline, {
    			'checkIn' : this.checkIn != null ? strToDate(this.checkIn) : null,
    			'checkOut' : this.checkOut != null ? strToDate(this.checkOut) : null
    		});

    	//}
    	//if (this.renderFilter) {
		   //fltr = tmpl_str(data.skins.matrix.template_filter, data);
		   //document.getElementById("div_mtx_filter").innerHTML = fltr;
    	//}
    	this.renderFilter = true;
    	document.getElementById("thematrixdiv").innerHTML = mtx;
    	//startapp(document.forms['checkAvailShort'], "");
    	//document.fire("matrix:checkInOutSetExternaly", this); // synchronize calendar dates with matrix checkin/checkout dates
    }
    
    Matrix.prototype.applySkin_matrix = function(data) {
    	data['dateRow'] = tmpl_str(data.skins.matrix.template_dateRow, data);
    	var mtx = tmpl_str(data.skins.matrix.template_matrix, data);
    	if (!this.loaded) {
    		//this.matrix.innerHTML = tmpl_str(data.skins.matrix.template_outline, {'domainName' : 'localhost'});
    		this.matrix.innerHTML = tmpl_str(data.skins.matrix.template_outline, data);
    		/*
    		if (data.skins.matrix.template_filter) {
    			fltr = tmpl_str(data.skins.matrix.template_filter, data);
    			document.getElementById("div_mtx_filter").innerHTML = fltr;
    		}
    		*/
    	}
    	document.getElementById("thematrixdiv").innerHTML = mtx;
    	startapp(document.forms['checkAvailShort'], "");
    }
    
    Matrix.prototype.applySkin_photo_list = function(data) {
    	var mtx = tmpl_str(data.skins.list.template_photo_list, data);
    		this.matrix.innerHTML = tmpl_str(data.skins.list.template_outline, {
    			'checkIn' : this.checkIn != null ? strToDate(this.checkIn) : null,
    			'checkOut' : this.checkOut != null ? strToDate(this.checkOut) : null
    		});
//    	this.renderFilter = true;
    	document.getElementById("thematrixdiv").innerHTML = mtx;
    }
    
    Matrix.prototype.applySkin_places = function(data) {
    	var mtx = tmpl_str(data.skins.places.template_places, data);
    	/*
    		this.matrix.innerHTML = tmpl_str(data.skins.list.template_outline, {
    			'checkIn' : this.checkIn != null ? strToDate(this.checkIn) : null,
    			'checkOut' : this.checkOut != null ? strToDate(this.checkOut) : null
    		});
    		*/
//    	this.renderFilter = true;
    	document.getElementById("thematrixdiv").innerHTML = mtx;
    }
    
    Matrix.prototype.applySkin = function(data) {
    	var featuredNum = 0;
    	if (this.data.featured) { featuredNum = this.data.featured.length; }
		if (typeof(data) == "undefined") return false;
		this.saveCriteria();
    	this.matrix = document.getElementById("_mtx_container");
    	data.showPagination = false;
    	data.pagination = new Array();
    	data.pagination.startRecord = 0;
    	data.pagination.endRecord = data.totalShowResult;
    	if (this.usePagination) {
    		data.showPagination = true;
	    	data.pagination.showPreviousButton = false;
	    	data.pagination.showNextButton = false;
	    	if (featuredNum > 0) {
	    		if (this.pageNo == 1) {
	    			data.pagination.startRecord = (this.pageNo-1)*this.resultPerPage;
	    			data.pagination.endRecord = (this.resultPerPage*this.pageNo) - featuredNum;
	    		} else {
	    			data.pagination.startRecord = ((this.pageNo-1)*this.resultPerPage) - featuredNum;
	    			data.pagination.endRecord = (this.resultPerPage*this.pageNo) - featuredNum;
	    		}
	    	} else {
	    		data.pagination.startRecord = (this.pageNo-1)*this.resultPerPage;
	    		data.pagination.endRecord = this.resultPerPage*this.pageNo;
	    	}
	    	data.pagination.numberOfPage = parseInt(data.totalShowResult/this.resultPerPage);
	    	if (data.pagination.numberOfPage*this.resultPerPage < data.totalShowResult) data.pagination.numberOfPage += 1;
	    	data.pagination.pageNo = this.pageNo;
	    	if (data.pagination.endRecord > data.totalShowResult) data.pagination.endRecord = data.totalShowResult;
	    	if (data.totalShowResult > data.pagination.endRecord) data.pagination.showNextButton = true;
	    	if (this.pageNo > 1) data.pagination.showPreviousButton = true;
    	}
    	this['applySkin_' + this.skin](data);
    	this.restoreCriteria();
    }
    
    Matrix.prototype.restoreCriteria = function() {
    	if (typeof(matrixFilter) != "undefined") matrixFilter.Restore();
    }
    
    Matrix.prototype.saveCriteria = function() {
    	matrixFilter = new MatrixFilter();
    	matrixFilter.KeepCurrent();
    }

    Matrix.prototype.loadCheckInMatrix = function (checkIn, checkOut) {
        this.checkIn = checkIn;
        this.checkOut = checkOut;
        this.startDate = "checkIn";
        
        /* change the reservation dates to the new dates */
        if (this.reservation) {
        	this.reservation.clearNights();
        	if (this.checkIn && this.checkOut) { 
        		this.reservation.setNights(strToDate(this.checkIn), strToDate(this.checkOut));
        	}
        }
        this.loadMatrix();
    }
    
    Matrix.prototype.nextPage = function(incDays) { this.changePage(incDays); }
    Matrix.prototype.prevPage = function(incDays) { this.changePage(-incDays); }

    Matrix.prototype.changePage = function(days) {
        this.startDate = incDateStr(this.startDate, days);
        this.endDate = incDateStr(this.startDate, this.days);
        this.loadMatrix();        
    }
    
    Matrix.prototype.selectRatePlan = function(ratePlanId, ratePlanName, offerId, bookingAdapter) {
    	if (!this.reservation) {
    		this.reservation = new Reservation(ratePlanId, ratePlanName, '0', offerId, this.requestedId, this.restrictions, bookingAdapter);
    	} else {
    		this.reservation.ratePlanId = ratePlanId;
    		this.reservation.restrictions = this.restrictions;
    	}
    	
		mtxHelper.updateTotals();
		this.showCurrentRatePlan(ratePlanId);
    }
    
    Matrix.prototype.showCurrentRatePlan = function(ratePlanId) {
          var ratePlan = document.getElementById(ratePlanId);
  
          if (ratePlan) {
        	  //this.checkLastSelected(ratePlan, ratePlanId);
              
        	  haveBlurb = this.showRatePlanBlurb(ratePlan, ratePlanId);
              $(ratePlanId + '_moreinfo').style.display = "none";
              $(ratePlanId + '_hideinfo').style.display = "";
  
              highlightRow(ratePlan, !haveBlurb); 
          }
    }

    /**
     * Checks that all current reservation nights displayed in the matrix have rates.
     */
    Matrix.prototype.allNightsAvailable = function() {
    	if (this.reservation && this.reservation.numNights > 0) {
	 	    for (dateIndex = this.startDate; dateIndex <= this.endDate; dateIndex = incDateStr(dateIndex, 1)) {
	 	    	if (this.isInReservationPeriod(dateIndex)) {
		 	    	rateCell = document.getElementById(this.reservation.ratePlanId + "_" + dateIndex);
		 	        if (!rateCell) return false;
	 	    	}
	  	    }
    	}
    	return true;
    }
    
    Matrix.prototype.setDailyInclusions = function(blurb, idx) {
    	if (!$(blurb)); return;
    	var dv = $(blurb).getElementsByClassName('inclusions');
    	if (!dv) return;
        eIncl = dv[0];
        if (!eIncl) return;
        
    	var inclusionsText = '';
        
        if (typeof(this.checkIn) != 'null') {
        	var selectedDates = [];
        	var inclusions = [];
        	var rates = this.data.results[idx].rates;
        	var numNights = this.reservation.numNights;

        	for(var i = 0; i < numNights ; i++) {
        		if (this.data.results[idx].invSrc != "L") {
        			curr_date = new Date(this.reservation.checkIn.getTime() + (i * 24 * 60 * 60 * 1000));
        			if (typeof(rates[curr_date.format('%Y%m%d')]) != 'undefined') {
        				inclusions.push([rates[curr_date.format('%Y%m%d')].dailyInclusions, curr_date]);
        			}
        		}
        	}
        	var start_date;
        	var text;
        	
        	// sort into same text date range
        	var sortedInclusions = [];
        	var start = '';
        	var end = '';
        	var text = '';
        	
        	for (i = 0; i < inclusions.length; i++) {
    			if (i == 0) { // seed
        			start = inclusions[i][1];
        			end = inclusions[i][1]; 
        			text = inclusions[i][0];
    			}

    			if (inclusions[i][0] != text) { // text is different
    				sortedInclusions.push({'start': start, 'end': end, 'text': text});
    				start = inclusions[i][1];
    				end = inclusions[i][1];
        			text = inclusions[i][0];
    				
    			} else { // text is the same
    				end = inclusions[i][1];
    			}
    			
    			if (i + 1 == inclusions.length) { // last iteration, always save
    				sortedInclusions.push({'start': start, 'end': end, 'text': text});
    			}
    			
        	}
        	
        	var inclusionsText = '';
        	
        	for(i = 0; i < sortedInclusions.length; i++) {
    			start_date = sortedInclusions[i].start;
    			end_date = sortedInclusions[i].end;
    			text = sortedInclusions[i].text;
    			if (text == '') {
    				continue;
    			}
    			
    			if (start_date.getMonth() == end_date.getMonth()) { // same month
    				if (end_date.getDate() - start_date.getDate() > 0) { // multiple days
    					inclusionsText += '<div class="inclusion">' + start_date.getDate() + '-' + end_date.getDate() + " " + lookupMonth(start_date.getMonth()) + ' ' + start_date.getFullYear() + ' - ' + text + '</div>';
    				} else {
    					inclusionsText += '<div class="inclusion">' + start_date.getDate() + " " + lookupMonth(start_date.getMonth()) + ' ' + start_date.getFullYear() + ' - ' + text + '</div>';
    				}
    				
    			} else { // different month
    				inclusionsText += '<div class="inclusion">' + start_date.getDate() + " " + lookupMonth(start_date.getMonth()) + ' - ' + end_date.getDate() + ' ' + lookupMonth(end_date.getMonth()) + ' ' + start_date.getFullYear() + ' - ' + text + '</div>';
    				
    			}
        	}
        }
        
        $(eIncl).update(inclusionsText);
    };

    Matrix.prototype.setNotAvailable = function(idx) {
    	var deal_id = mtxHelper.ratesMapping[idx];
    	var eNotAvailable = $$("#ratePlanBlurb_" + deal_id + " div.not-available")[0];
//        var eNotAvailable = $(this.lastRatePlanBlurb).getElementsByClassName('not-available')[0];
        var msg = '';
        
        if (mtxHelper.rates[idx].numberOfNights > 0) {
        	msg = mtxHelper.deals[idx].errMsg;
        }
        eNotAvailable.update(msg);
    	if (msg) {
    		eNotAvailable.show();

    	} else {
    		eNotAvailable.hide();
    	}
    	
    };
    
    Matrix.prototype.showRatePlanBlurb = function(ratePlanRow, ratePlanId, even) {
        var blurb = this.getBlurb([ratePlanId]);
        var idx = blurb[1];
        this.blurbIdx = idx;
        
        if (blurb) {
        	var na = '';
            var table = ratePlanRow.parentNode;
            this.lastRatePlanBlurb = table.insertRow(ratePlanRow.rowIndex + 1);
            this.lastRatePlanBlurb.id = "ratePlanBlurb_" + ratePlanId;
            this.lastRatePlanBlurb.className = 'rate_plan_blurb_row';
            
            var odd_even = blurb[0] ? "even" : "odd";
            
            var free_nights_desc = '';
            if (this.data.results[idx].promotions) {
            	for (var x=0; x<this.data.results[idx].promotions.length; x++) {
            		if (this.data.results[idx].promotions[x].type=="FreeNights") {
            			var period_start = "";
            			var period_end = "";
            			
            			if (this.data.results[idx].promotions[x].start_date=="" && this.data.results[idx].promotions[x].end_date=="") {
            				period = "";
            			} else {
            				if (this.data.results[idx].promotions[x].start_date=="") {
            					period_start = "Now";
            				} else {
            					var start_date = strToDate(this.data.results[idx].promotions[x].start_date);
            					period_start = start_date.getDate() + ' ' + lookupMonth(start_date.getMonth()) + ' ' + start_date.getFullYear();
            				}
            				if (this.data.results[idx].promotions[x].end_date=="") {
            					period = "From " + period_start + ": ";
            				} else {
            					var end_date = strToDate(this.data.results[idx].promotions[x].end_date);
            					period_end = end_date.getDate() + ' ' + lookupMonth(end_date.getMonth()) + ' ' + end_date.getFullYear();
            					period = period_start + " - " + period_end + ": ";
            				}
            			}
            			if (free_nights_desc != '') free_nights_desc += "<br />";
            			free_nights_desc += period + this.data.results[idx].promotions[x].text;
            		}
            	}
            }
            
            //make sure data in the same currency
            mtxHelper.verify();
            var data 					= Object.clone(this.data.results[idx]);
            data.odd_even				= odd_even;
            data.symbol 				= mtxHelper.rates[idx].currencySymbol;
            data.total 					= addComma(mtxHelper.rates[idx].totalRate);
            data.tatal_local			= mtxHelper.rates[idx].totalRateLocal;
            data.saved 					= addComma(mtxHelper.rates[idx].savedRate);
            data.saved_local			= mtxHelper.rates[idx].savedRateLocal;
            data.rack_rate				= addComma(mtxHelper.rates[idx].totalRackRate);
            data.rack_rate_local		= mtxHelper.rates[idx].totalRackRateLocal;
            data.cancellation_policy	= mtxHelper.updateCancellation(idx);
            data.bookState				= mtxHelper.deals[idx].state;
            data.free_nights_description = free_nights_desc;
            data.total_nights			= mtxHelper.rates[idx].numberOfNights;
            
            if (mtxHelper.rates[idx].savedRate > 0) {
            	data.display = 'block';
        	} else {
            	data.display = 'none';
            }
            
            var cell0 = this.lastRatePlanBlurb.insertCell(0);
            cell0.innerHTML = tmpl_str(this.data.skins.matrix.template_ratePlanBlurb0, data);
            cell0.className = "mtx_blurb_add_left mtx_blurb_even";
            var cell1 = this.lastRatePlanBlurb.insertCell(1);
            cell1.innerHTML = tmpl_str(this.data.skins.matrix.template_ratePlanBlurb1, data);
            cell1.className = "mtx_blurb_add_right mtx_blurb_even";
            cell1.colSpan = table.rows[2].cells.length-1;
            
            mtxHelper.ratePlanBlurbId = this.lastRatePlanBlurb.id;
            mtxHelper.ratePlanBlurbIndex = idx;
            
            this.checkRatePlanDateSelection(ratePlanId);
            
            this.setDailyInclusions(this.lastRatePlanBlurb, idx);
        } else {
            this.lastRatePlanBlurb = null;
            mtxHelper.ratePlanBlurbId = null;
            mtxHelper.ratePlanBlurbIndex = null;
        }
        this.setNotAvailable(idx);
    	        
        return blurb[1];
    }
    
    Matrix.prototype.checkRatePlanDateSelection = function(ratePlanId) {
    	var tr_id = "ratePlanBlurb_" + ratePlanId;
    	var idx = mtxHelper.ratesMapping.indexOf(ratePlanId);
    	if ($(tr_id)) {
    		if (mtxHelper.rates[idx].numberOfNights>0) {
    			$$("#" + tr_id + " div.mtxRatePlanNoDateSelected")[0].style.display = 'none';
    			
    			if (mtxHelper.deals[idx].active) {
    				$$("#" + tr_id + " div.total-cover")[0].show();
    			} else {
    				/** 
    				 * TODO: Change this to
    				 * $("rate_section").hide();
    				 */
    				$$("#" + tr_id + " div.total-cover")[0].hide();
    			}
    			
    		} else {
    			$$("#" + tr_id + " div.mtxRatePlanNoDateSelected")[0].style.display = '';
    			$$("#" + tr_id + " div.total-cover")[0].hide();
    		}
		}
    }


    Matrix.prototype.getBlurb = function(ratePlanId) {
    	for (var i = 0; i < this.data.results.length; i++) {
    		if (this.data.results[i].id == ratePlanId) {
    			var even = (i % 2) == 1;
    			return [even, i];
    		}
    	}
    	return null;
    }              
                  
    Matrix.prototype.checkLastSelected = function(ratePlanRow, ratePlanId) {
    	this.replaceSelectedRatePlan();
        
        this.lastRatePlan = ratePlanRow;
        this.lastRatePlanClone = ratePlanRow.cloneNode(true);
    }
    
    Matrix.prototype.replaceSelectedRatePlan = function(ratePlanId, remove) {
        	// we have to refetch the 'lastRatePlan' row as the innerHTML may have been
        	// reset, rendering any DOM nodes we hold onto useless.
        	var lastRatePlanVer2 = $(ratePlanId);
            var table = lastRatePlanVer2.parentNode;
            if (table) {
            	/* TBR
                table.replaceChild(this.lastRatePlanClone, lastRatePlanVer2);
                */
            	var blurb = $("ratePlanBlurb_" + ratePlanId);
                if (blurb && remove===true) {
                	table.removeChild(blurb);
                }
                
                mtxHelper.updateTotals(this.lastRatePlanClone);
            } 
    }
    
    Matrix.prototype.hideRatePlanSelection = function(ratePlanId) {
    	if (ratePlanId) {
        	$(ratePlanId + "_hideinfo").style.display = 'none';
        	$(ratePlanId + "_moreinfo").style.display = '';
    	}
    	this.replaceSelectedRatePlan(ratePlanId, true);
        this.lastRatePlan = null;
        this.lastratePlanClone = null;
        this.lastRatePlanBlurb = null;
        mtxHelper.ratePlanBlurbId = null;
        mtxHelper.ratePlanBlurbIndex = null;

    }
    
    Matrix.prototype.unhideRatePlanSelection = function() {
    	if (this.reservation != null) this.showCurrentRatePlan();
    }
    
    Matrix.prototype.isInReservationPeriod = function(dateStr) {
        return this.reservation && this.reservation.numNights > 0 && this.reservation.isInReservation(strToDate(dateStr));
    }  



/**
 * Reservation Class
 */
function Reservation(ratePlanId, ratePlanName, rtId, offerId, hotelId, restrictions, bookingAdapter) {
    this.hotelId = hotelId;
    this.ratePlanId = ratePlanId;
    this.ratePlanName = ratePlanName;
    this.rtId = rtId;
    this.offerId = offerId;
    this.restrictions = restrictions;
    this.bookingAdapter = bookingAdapter;
    this.checkIn = null;
    this.numNights = 0;
    this.errorMsg = "";
    this.ratePlanInvalidDates = new Object();


    Reservation.prototype.setNights = function(checkIn, checkOut) {
        var dateIndex = checkIn; 
        while (dateIndex.valueOf() < checkOut.valueOf()) {
            this.toggleDate(dateIndex);            
            dateIndex = incrementDate(dateIndex, 1);
        }    
    }

    Reservation.prototype.setDateSelected = function() {
    	if (this.numNights == 0) return;
    	
    	// clear other date selected remember by Chrome and Safari
    	var d = strToDate(matrix.startDate);
    	for (i=0; i<matrix.days; i++) {
    		var cb = $(d.format('%Y%m%d') + "_cb");
    		if (cb) {
    			cb.checked = false;
    		}
    		
    		d = incrementDate(d, 1)
    	}
    	
    	for (var dateIndex=this.checkIn; dateIndex < this.getCheckOut(); dateIndex = incrementDate(dateIndex, 1)) {
    		var cb = $(dateIndex.format('%Y%m%d') + "_cb");
    		if (cb) {
    			cb.checked = true;
    			setMatrixDateCheckBoxes(cb, dateIndex.format('%Y%m%d'));
    		}
    	}
    }

    Reservation.prototype.clearNights = function() {
        this.checkIn = null;
        this.numNights = 0;
        this.ratePlanInvalidDates = new Object();
    }

    Reservation.prototype.getLastNight = function() {
        return incrementDate(this.checkIn, this.numNights - 1);
    }
    
    Reservation.prototype.getCheckOut = function() {
        return incrementDate(this.checkIn, this.numNights);
    }
    
    Reservation.prototype.toggleDate = function (newDate) {
    	if (!this.checkIn || this.isDayBeforeCheckIn(newDate)) {
    		this.checkIn = newDate;
    		this.numNights++;
    	} else if (this.isCheckIn(newDate)) {
    		this.checkIn = (this.numNights > 1)?incrementDate(this.checkIn, 1):null;
    		this.numNights--;
    	} else if (this.isCheckOut(newDate)) {
    		this.numNights++;
    	} else if (this.isLastNight(newDate)) {
    		this.numNights--;
    	} else {
    		return false;
    	}
    	
    	if (this.checkIn == null) {
    		matrix.checkIn =  null;
    		matrix.checkOut =  null;
    	} else {
    		matrix.checkIn =  this.checkIn.format('%Y%m%d');
    		matrix.checkOut = this.getCheckOut().format('%Y%m%d');
    	}
    	
    	//find no rates date for each ratePlan
    	this.findRatePlanInvalidDates(newDate);
    	
    	/* move to updateTotals
    	if (typeof(matrix.blurbIdx) != 'undefined') {
    		matrix.setDailyInclusions();
    		//matrix.setNotAvailable();
    	}
    	*/
    	return true;
    }
    
    Reservation.prototype.setRatePlanInvalidDates = function() {
    	this.ratePlanInvalidDates = new Object();
    	for (var i=0; i<matrix.data.results.length; i++) {
    		var ratePlanId = matrix.data.results[i].id;
    		if (matrix.data.results[i].ratePlanInvalidDates) {
    			this.ratePlanInvalidDates[ratePlanId] = matrix.data.results[i].ratePlanInvalidDates;
    		}
    	}
    }
    
    Reservation.prototype.findRatePlanInvalidDates = function(newDate) {
    	var dateStr = newDate.format('%Y%m%d');
    	for (var i=0; i<matrix.data.results.length; i++) {
    		var ratePlanId = matrix.data.results[i].id;
    		if (!matrix.data.results[i].rates[dateStr]) {
    			if (!this.ratePlanInvalidDates[ratePlanId]) {
    				this.ratePlanInvalidDates[ratePlanId] = new Array();
    				this.ratePlanInvalidDates[ratePlanId].push(dateStr);
    			} else {
    				var found = false;
    				for (var j=0; j<this.ratePlanInvalidDates[ratePlanId].length; j++) {
    					if (this.ratePlanInvalidDates[ratePlanId][j] == dateStr) {
    						this.ratePlanInvalidDates[ratePlanId].splice(j, 1);
    						found = true;
    						break;
    					}
    				}
    				
    				if (!found) this.ratePlanInvalidDates[ratePlanId].push(dateStr);
    			}
    		}
    	}
    }

    Reservation.prototype.isLastNight = function(newDate) {
        return newDate.valueOf() == this.getLastNight().valueOf();
    }

    Reservation.prototype.isCheckOut = function(newDate) {
    	return newDate.valueOf() == incrementDate(this.checkIn, this.numNights).valueOf();
    }

    Reservation.prototype.isCheckIn = function(newDate) {
        return newDate.valueOf() == this.checkIn.valueOf();
    }

    Reservation.prototype.isDayBeforeCheckIn = function(newDate) {
        return newDate.valueOf() == incrementDate(this.checkIn, -1).valueOf();
    }
    
    Reservation.prototype.rateAvailable = function() {
    	if (this.ratePlanInvalidDates[this.ratePlanId] && this.ratePlanInvalidDates[this.ratePlanId].length>0) {
    		return false;
    	}
    	
    	return true;
    }

    Reservation.prototype.isValid = function () {
        if (this.numNights <= 0) {
        	this.errorMsg = "You need to check the dates you wish to stay before you book. <br><br>You can also scroll forward or back to select more dates.";
            return false;
        } else if (!this.rateAvailable()) {
        	this.errorMsg = "This room is sold out for some of the nights you want to stay.";
            return false;
        } else if (this.restrictions.reservationIsRestricted(this, this.ratePlanId, "MinNightsStay")) {
            this.errorMsg = "This offer requires a minimum booking of at least " + this.restrictions.lastError.numNights + " nights. Select more dates to stay or a different offer.";
            return false;
        } else if (this.restrictions.reservationIsRestricted(this, this.ratePlanId, "MaxNightsStay")) {
            this.errorMsg = "This offer does not allow bookings of more than " + this.restrictions.lastError.numNights + " nights. Choose fewer dates to stay or a different offer.";
            return false;
        } else if (this.restrictions.reservationIsRestricted(this, this.ratePlanId, "DayUse") && this.numNights > 1) {
            this.errorMsg = "This offer cannot be booked overnight. It is available for day use only.";
            return false;
        } else if (this.restrictions.restrictionApplies(this.ratePlanId, this.checkIn, this.checkIn, "ClosedToArrival", this.numNights)) {
        	suffix = (this.restrictions.lastError.numNights && this.restrictions.lastError.numNights > 0)?" unless you book at least " + this.restrictions.lastError.numNights + " nights":"";
            this.errorMsg = "The hotel does not allow arrivals on the first day you want to stay" + suffix + ". Choose another first date or a different offer.";
            return false;
        } else if (this.restrictions.restrictionApplies(this.ratePlanId, this.getCheckOut(), this.getCheckOut(), "ClosedToDeparture", this.numNights )) {
            suffix = (this.restrictions.lastError.numNights && this.restrictions.lastError.numNights > 0)?" unless you book at least " + this.restrictions.lastError.numNights + " nights":"";
            this.errorMsg = "The hotel does not allow check-outs on the last day you want to stay" + suffix + ". Choose another date to check out or a different offer.";
            return false;
        } 
        return true;
    }  

    Reservation.prototype.getRestrictionLabel = function () {
    	var label = '';
        if (!this.rateAvailable()) {
        	label = "Not Available";
        } else if (this.restrictions.reservationIsRestricted(this, this.ratePlanId, "MinNightsStay")) {
            label = this.restrictions.lastError.numNights + "+ nts";
        } else if (this.restrictions.reservationIsRestricted(this, this.ratePlanId, "MaxNightsStay")) {
//            label = "Max " + this.restrictions.lastError.numNights + " nts";
        	label = "Not Available";
        } else if (this.restrictions.reservationIsRestricted(this, this.ratePlanId, "DayUse") && this.numNights > 1) {
//            label = "Day Use";
        	label = "Not Available";
      } else if (this.restrictions.restrictionApplies(this.ratePlanId, this.checkIn, this.checkIn, "ClosedToArrival", this.numNights)) {
//        	label = (this.restrictions.lastError.numNights && this.restrictions.lastError.numNights > 0) ? "Min " + this.restrictions.lastError.numNights + " nts" : "No Check In";
        	label = "Not Available";
      } else if (this.restrictions.restrictionApplies(this.ratePlanId, this.getCheckOut(), this.getCheckOut(), "ClosedToDeparture", this.numNights )) {
//        	label = (this.restrictions.lastError.numNights && this.restrictions.lastError.numNights > 0) ? "Min " + this.restrictions.lastError.numNights + " nts" : "No Check Out";
        	label = "Not Available";
      } 
        return label;
    }
    
    Reservation.prototype.getNotAvailableMessage = function () {
    	var msg = '';
    	if (this.numNights<=0) return msg;
        if (!this.rateAvailable()) {
        	msg = "This room is sold out for some of the nights you want to stay.";

        } else if (this.restrictions.reservationIsRestricted(this, this.ratePlanId, "MinNightsStay")) {
            msg = "This offer requires a minimum booking of at least " + this.restrictions.lastError.numNights + " nights. Select more dates to stay or a different offer.";

        } else if (this.restrictions.reservationIsRestricted(this, this.ratePlanId, "MaxNightsStay")) {
            msg = "This offer does not allow bookings of more than " + this.restrictions.lastError.numNights + " nights. Choose fewer dates to stay or a different offer.";

        } else if (this.restrictions.reservationIsRestricted(this, this.ratePlanId, "DayUse") && this.numNights > 1) {
            msg = "This offer cannot be booked overnight. It is available for day use only.";

        } else if (this.restrictions.restrictionApplies(this.ratePlanId, this.checkIn, this.checkIn, "ClosedToArrival", this.numNights)) {
        	suffix = (this.restrictions.lastError.numNights && this.restrictions.lastError.numNights > 0)?" unless you book at least " + this.restrictions.lastError.numNights + " nights":"";
            msg = "The hotel does not allow arrivals on the first day you want to stay" + suffix + ". Choose another first date or a different offer.";

        } else if (this.restrictions.restrictionApplies(this.ratePlanId, this.getCheckOut(), this.getCheckOut(), "ClosedToDeparture", this.numNights )) {
            suffix = (this.restrictions.lastError.numNights && this.restrictions.lastError.numNights > 0)?" unless you book at least " + this.restrictions.lastError.numNights + " nights":"";
            msg = "The hotel does not allow check-outs on the last day you want to stay" + suffix + ". Choose another date to check out or a different offer.";

        } 
        return msg;
    };
    
    
    Reservation.prototype.book = function () {
    	if (!window.mtx_portal) {
    		window.mtx_portal = 'asiawebdirect.com';
    	}
    	if (!window.mtx_rsvn) {
    		window.mtx_rsvn = '2.0';
    	}
    	
    	if (this.isValid()) {
    		// special cookie use when customer click back
    		var expire = new Date(new Date().getTime() + (24 * 1000 * 60 * 60 * 24));
    		setCookie('mtxBookCheckInDate', this.checkIn.format('%Y%m%d'), expire);
    		setCookie('mtxBookCheckOutDate', this.getCheckOut().format('%Y%m%d'), expire);
    		
            var bookUrl = "/asahi/frontend.php/book?" +
                          "bookingAdapter=" + this.bookingAdapter +
                          "&ratePlanName=" + this.encodeRatePlanName(this.ratePlanName) + 
                          "&startMonth=" + (this.checkIn.getMonth() + 1) +
                          "&startDay=" + this.checkIn.getDate() + 
                          "&startYear=" + this.checkIn.getFullYear() +
                          "&numNights=" + this.numNights +
                          "&hotelId=" +  this.hotelId +
                          "&rtId=" + this.rtId +
                          "&offerId=" + this.offerId +
                          "&portal=" + mtx_portal +
                          "&rsvn=" + mtx_rsvn +
                          "&onRequest=" + this.restrictions.reservationIsRestricted(this, this.ratePlanId, "OnRequest");
            
            if (matrix.xDomain) {
            	bookUrl = 'http://' + matrix.domainName + bookUrl;
            }
            
        	// send preferred currency
        	var ccode = getCookie('ccCodePersist');
        	if (ccode && ccode.length==3) {
        		bookUrl += "&PreferredCurrency=" + ccode;
        	}
        	
        	document.location.href = bookUrl;
            //window.open(bookUrl);
            return true;
    	} else {
    		return false;
    	}           
          
    }
    
    Reservation.prototype.encodeRatePlanName = function(name) {
    	return name.replace(/\+/g,'%2B');
    }

    Reservation.prototype.isInReservation = function(date) {
        return date.valueOf() >= this.checkIn.valueOf() && date.valueOf() <= this.getLastNight().valueOf();
    }
    
}


/**
 * Restriction rules class.
 */
function Restriction() {
	this._restrictionTypes = ["OnRequest", "ClosedToArrival", "ClosedToDeparture", "MinNightsStay", "MaxNightsStay", "DayUse"];
  
	/* An array of restriction arrays */
    this.restrictions = new Array();  
    this.lastError = null;
    this.weekDays = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
        
    Restriction.prototype.initialise = function(results) {
        for (var i = 0; i < results.length; i++) {
            this.restrictions[results[i].id] = new Array();
        	for (var typeIndex = 0; typeIndex < this._restrictionTypes.length; typeIndex++) {
        		var restrictionType = this._restrictionTypes[typeIndex];
                if (results[i].restrictions[restrictionType] && (results[i].restrictions[restrictionType].length > 0)) {
                    this.restrictions[results[i].id][restrictionType] = results[i].restrictions[restrictionType];
                }
        	}
        }
    }

    Restriction.prototype.reservationIsRestricted = function(reservation, ratePlanId, restrictionType) {
        return this.restrictionApplies(ratePlanId, reservation.checkIn, reservation.getLastNight(), restrictionType, reservation.numNights);             
    }

    Restriction.prototype.restrictionApplies = function(ratePlanId, startDate, endDate, restrictionType, numNights) {
        if (this.restrictions[ratePlanId] && this.restrictions[ratePlanId][restrictionType]) {

            var rules = this.restrictions[ratePlanId][restrictionType];
             
            for (var i = 0; i < rules.length; i++) {
            	  if (this.isByRestrictedByNumNights(rules[i], numNights) && 
            	      ( (this.isRestrictedByDate(rules[i], startDate, endDate) || this.isRestrictedByDay(rules[i], startDate)) || this.isGlobalRestriction(rules[i])) )
            	  {
                      this.lastError = rules[i];
                      return true;
                  }                 
    
            }

        }
        return false;            
    }

    Restriction.prototype.isByRestrictedByNumNights = function(rule, numNights) {
        return rule["numNights"] == null || 
               ((rule["relation"] == "atLeast" && (rule["numNights"] == 0 || numNights < rule["numNights"])) ||
                (rule["relation"] == "atMost" && numNights > rule["numNights"]));
    }

    Restriction.prototype.isRestrictedByDay = function(rule, startDate) {
        return rule["dayOfWeek"] != null  && rule["dayOfWeek"] == this.weekDays[startDate.getDay()];
    }

    Restriction.prototype.isRestrictedByDate = function(rule, startDate, endDate) {
        if (rule['startDate'] == null || rule['endDate'] == null) return false;
        
        var endDateToCheck = endDate;
        if (rule['periodCheck'] && rule['periodCheck'] == "checkIn") {
            endDateToCheck = startDate; // only check if the rule overlaps with the check-in date
        }
        return rule["startDate"] != null && 
               rule["endDate"] != null  && 
               startDate.valueOf() <= strToDate(rule["endDate"]).valueOf() && 
               endDateToCheck.valueOf() >= strToDate(rule["startDate"].valueOf());
    }

    Restriction.prototype.isGlobalRestriction = function(rule) {
        return rule["startDate"] == null && 
               rule["endDate"] == null  &&
               rule["dayOfWeek"] == null;
    }
    
} 


/***** external includes ****/

function queryParam(name)
{
  name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
  var regexS = "[\\?&]"+name+"=([^&#]*)";
  var regex = new RegExp( regexS );
  var results = regex.exec( window.location.href );
  if( results == null )
    return "";
  else
    return results[1];
}


/**
 * Date.format()
 * string format ( string format )
 * Formatting rules according to http://php.net/strftime
 *
 * Copyright (C) 2006  Dao Gottwald
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Contact information:
 *   Dao Gottwald  <dao at design-noir.de>
 *
 * @version  0.7
 * @todo     %g, %G, %U, %V, %W, %z, more/better localization
 * @url      http://design-noir.de/webdev/JS/Date.format/
 */

var _lang = (navigator.systemLanguage || navigator.userLanguage || navigator.language || navigator.browserLanguage || '').replace(/-.*/,'');
switch (_lang) {
	case 'de':
		Date._l10n = {
			days: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],
			months: ['Januar','Februar','M\u00E4rz','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'],
			date: '%e.%m.%Y',
			time: '%H:%M:%S'};
		break;
	case 'es':
		Date._l10n = {
			days: ['Domingo','Lunes','Martes','Mi�rcoles','Jueves','Viernes','S\u00E1bado'],
			months: ['enero','febrero','marcha','abril','puede','junio','julio','agosto','septiembre','octubre','noviembre','diciembre'],
			date: '%e.%m.%Y',
			time: '%H:%M:%S'};
		break;
	case 'fr':
		Date._l10n = {
			days: ['dimanche','lundi','mardi','mercredi','jeudi','vendredi','samedi'],
			months: ['janvier','f\u00E9vrier','mars','avril','mai','juin','juillet','ao\u00FBt','septembre','octobre','novembre','decembre'],
			date: '%e/%m/%Y',
			time: '%H:%M:%S'};
		break;
	case 'it':
		Date._l10n = {
			days: ['domenica','luned\u00EC','marted\u00EC','mercoled\u00EC','gioved\u00EC','venerd\u00EC','sabato'],
			months: ['gennaio','febbraio','marzo','aprile','maggio','giugno','luglio','agosto','settembre','ottobre','novembre','dicembre'],
			date: '%e/%m/%y',
			time: '%H.%M.%S'};
		break;
	case 'pt':
		Date._l10n = {
			days: ['Domingo','Segunda-feira','Ter\u00E7a-feira','Quarta-feira','Quinta-feira','Sexta-feira','S\u00E1bado'],
			months: ['Janeiro','Fevereiro','Mar\u00E7o','Abril','Maio','Junho','Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'],
			date: '%e/%m/%y',
			time: '%H.%M.%S'};
		break;
	case 'en':
	default:
		Date._l10n = {
			days: ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'],
			months: ['January','February','March','April','May','June','July','August','September','October','November','December'],
			date: '%Y-%m-%e',
			time: '%H:%M:%S'};
		break;
}
Date._pad = function(num, len) {
	for (var i = 1; i <= len; i++)
		if (num < Math.pow(10, i))
			return new Array(len-i+1).join(0) + num;
	return num;
};
Date.prototype.format = function(format) {
	if (format.indexOf('%%') > -1) { // a literal `%' character
		format = format.split('%%');
		for (var i = 0; i < format.length; i++)
			format[i] = this.format(format[i]);
		return format.join('%');
	}
	format = format.replace(/%D/g, '%m/%d/%y'); // same as %m/%d/%y
	format = format.replace(/%r/g, '%I:%M:%S %p'); // time in a.m. and p.m. notation
	format = format.replace(/%R/g, '%H:%M:%S'); // time in 24 hour notation
	format = format.replace(/%T/g, '%H:%M:%S'); // current time, equal to %H:%M:%S
	format = format.replace(/%x/g, Date._l10n.date); // preferred date representation for the current locale without the time
	format = format.replace(/%X/g, Date._l10n.time); // preferred time representation for the current locale without the date
	var dateObj = this;
	return format.replace(/%([aAbhBcCdegGHIjmMnpStuUVWwyYzZ])/g, function(match0, match1) {
		return dateObj.format_callback(match0, match1);
	});
}
Date.prototype.format_callback = function(match0, match1) {
	switch (match1) {
		case 'a': // abbreviated weekday name according to the current locale
			return Date._l10n.days[this.getDay()].substr(0,3);
		case 'A': // full weekday name according to the current locale
			return Date._l10n.days[this.getDay()];
		case 'b':
		case 'h': // abbreviated month name according to the current locale
			return Date._l10n.months[this.getMonth()].substr(0,3);
		case 'B': // full month name according to the current locale
			return Date._l10n.months[this.getMonth()];
		case 'c': // preferred date and time representation for the current locale
			return this.toLocaleString();
		case 'C': // century number (the year divided by 100 and truncated to an integer, range 00 to 99)
			return Math.floor(this.getFullYear() / 100);
		case 'd': // day of the month as a decimal number (range 01 to 31)
			return Date._pad(this.getDate(), 2);
		case 'e': // day of the month as a decimal number
			return this.getDate();
		/*case 'g': // like %G, but without the century
			return ;
		case 'G': // The 4-digit year corresponding to the ISO week number (see %V). This has the same format and value as %Y, except that if the ISO week number belongs to the previous or next year, that year is used instead
			return ;*/
		case 'H': // hour as a decimal number using a 24-hour clock (range 00 to 23)
			return Date._pad(this.getHours(), 2);
		case 'I': // hour as a decimal number using a 12-hour clock (range 01 to 12)
			return Date._pad(this.getHours() % 12, 2);
		case 'j': // day of the year as a decimal number (range 001 to 366)
			return Date._pad(this.getMonth() * 30 + Math.ceil(this.getMonth() / 2) + this.getDay() - 2 * (this.getMonth() > 1) + (!(this.getFullYear() % 400) || (!(this.getFullYear() % 4) && this.getFullYear() % 100)), 3);
		case 'm': // month as a decimal number (range 01 to 12)
			return Date._pad(this.getMonth() + 1, 2);
		case 'M': // minute as a decimal number
			return Date._pad(this.getMinutes(), 2);
		case 'n': // newline character
			return '\n';
		case 'p': // either `am' or `pm' according to the given time value, or the corresponding strings for the current locale
			return this.getHours() < 12 ? 'am' : 'pm';
		case 'S': // second as a decimal number
			return Date._pad(this.getSeconds(), 2);
		case 't': // tab character
			return '\t';
		case 'u': // weekday as a decimal number [1,7], with 1 representing Monday
			return this.getDay() || 7;
		/*case 'U': // week number of the current year as a decimal number, starting with the first Sunday as the first day of the first week
			return ;
		case 'V': // The ISO 8601:1988 week number of the current year as a decimal number, range 01 to 53, where week 1 is the first week that has at least 4 days in the current year, and with Monday as the first day of the week. (Use %G or %g for the year component that corresponds to the week number for the specified timestamp.)
			return ;
		case 'W': // week number of the current year as a decimal number, starting with the first Monday as the first day of the first week
			return ;*/
		case 'w': // day of the week as a decimal, Sunday being 0
			return this.getDay();
		case 'y': // year as a decimal number without a century (range 00 to 99)
			return this.getFullYear().toString().substr(2);
		case 'Y': // year as a decimal number including the century
			return this.getFullYear();
		/*case 'z':
		case 'Z': // time zone or name or abbreviation
			return ;*/
		default:
			return match0;
	}
}

function Filter() {
	this.filters = null;		// keep all filter need to compute
	this.currencyCode = null;
	this.failed = false;
	
	// initial function, load all require filter function into array
	this.loadFilters = function() {
		this.filters = new Array();
		this.filters.push(this.filterAccom);
		this.filters.push(this.filterFacility);
		this.filters.push(this.filterRating);
		this.filters.push(this.filterPrice);
		this.filters.push(this.filterArea);
	}
	
	// function use to filter each result record
	this.computeFilters = function(record) {
		for (var i=0; i<this.filters.length; i++) {
			if (!this.filters[i](record, this)) {
				return false;
			}
		}
		return true;
	}
	
	this.filterFacility = function(result) {
		var facility_mapping = {'restaurant': "Restaurant", 'pool': "Swimming Pool", 'broadbandInternet': "Broadband Internet", 'kitchenette': "Kitchenette", 'fitnessCentre': "Fitness Centre", 'satelliteCableTV': "Satellite/Cable TV" };
		for (key in facility_mapping) {
			if ($(key)) {
				if ($(key).checked) {
					var okay = false;
					if(result.facilities!=null)
					{
						for (var j=0; j<result.facilities.length; j++) {
							if (result.facilities[j] == facility_mapping[key]) {
								okay = true;
								break;
							}
						}
					}
					if (!okay) return false;
				}
			}
		}
		return true;
	}
	
	this.filterAccom = function (result) {
		if (!window.matrix.data.accomList) return true;
		for (var i=0; i<window.matrix.data.accomList.length; i++) {
			var chk = $('mtx_fltr_accom_'+i);
			if (!chk) return true;
			if (chk.checked) {
				var okay = false;
				var sValue = chk.value;
				for (var j=0; j<result.accomType.length; j++) {
					if (result.accomType[j] == sValue) {
						okay = true;
						break;
					}
				}
				if (!okay) return false;
			}
		}
		return true;
	}
	
	this.filterRating = function (result) {
		if (!$('minCategory')) return true;
		var min_value = parseInt($('minCategory').innerHTML);
		var max_value = parseInt($('maxCategory').innerHTML);
		var chk_value = parseFloat(result.rating);
		if (result.rating == null) chk_value = 1;  // allow to show no rating hotels
		
		if (chk_value>=min_value && chk_value<=max_value) return true;
		return false;
	}
	
	this.filterPrice = function (result, parent) {
		if (!$('minPrice') || !$('maxPrice') || !$('priceRangeCurrency')) return true;
		var min_value = parseInt($('minPrice').innerHTML.replace(/,/g, ''));
		var max_value = parseInt($('maxPrice').innerHTML.replace(/,/g, ''));
		var chk_value = parseFloat(result.lowestRateNum);
		
		if (min_value==0 && isNaN(max_value)) return true;	// this means show all
		
		var filter_currency = $('priceRangeCurrency').value;
		if (result.currency != filter_currency) {
			// find currency index
			var fc_idx = null;
			var cu_idx = null;
			for (var i=0; i<matrix.data.currencies.length; i++) {
				if (matrix.data.currencies[i]['code'] == filter_currency) fc_idx = i;
				if (matrix.data.currencies[i]['code'] == result.currency) cu_idx = i;
			}

			if (fc_idx==null || cu_idx==null) {
				parent.failed = true;
				return true;
			}

			min_value = min_value*matrix.data.currencies[fc_idx]['rate']/matrix.data.currencies[cu_idx]['rate'];
			max_value = max_value*matrix.data.currencies[fc_idx]['rate']/matrix.data.currencies[cu_idx]['rate'];
			chk_value = chk_value*matrix.data.currencies[cu_idx]['rate']/matrix.data.currencies[fc_idx]['rate'];
		}
		
		var lowest_rate = parseFloat(result.lowestRateNum);
		var highest_rate = parseFloat(result.highestRateNum);

		if ((highest_rate >= min_value) && ((lowest_rate <= max_value) || isNaN(max_value))) {
			return true;
		}
		return false;
	}
	
	this.filterArea = function (result) {
		if (!$('mtxSubDestCount')) return true;
		var okay = true;
		for (var i=0; i<$('mtxSubDestCount').value; i++) {
			var chk = $('mtxSubDest_'+i);
			if (!chk) return true;
			
			if (chk.checked) {
				if (result.Area == chk.value) {
					return true;
				} else {
					okay = false;
				}
			}
		}
		return okay;
	}

}

// chrome's implementation of Array.sort() is not stable (has unexpected results) 
// for arrays with more than 22 elements so use these functions instead
// functions merge_sort and merge are from http://en.literateprograms.org/Special:Downloadcode/Merge_sort_%28JavaScript%29?oldid=16699

/* Copyright (c) 2011 the authors listed at the following URL, and/or
2 the authors of referenced articles or incorporated external code:
3 http://en.literateprograms.org/Merge_sort_(JavaScript)?action=history&offset=20100428205145
4 
5 Permission is hereby granted, free of charge, to any person obtaining
6 a copy of this software and associated documentation files (the
7 "Software"), to deal in the Software without restriction, including
8 without limitation the rights to use, copy, modify, merge, publish,
9 distribute, sublicense, and/or sell copies of the Software, and to
10 permit persons to whom the Software is furnished to do so, subject to
11 the following conditions:
12 
13 The above copyright notice and this permission notice shall be
14 included in all copies or substantial portions of the Software.
15 
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 
24 Retrieved from: http://en.literateprograms.org/Merge_sort_(JavaScript)?oldid=16699
25 */
function merge_sort(array,comparison)
{
	if(array.length < 2)
		return array;
	var middle = Math.ceil(array.length/2);
	return merge(merge_sort(array.slice(0,middle),comparison),
			merge_sort(array.slice(middle),comparison),
			comparison);
}
function merge(left,right,comparison)
{
	var result = new Array();
	while((left.length > 0) && (right.length > 0))
	{
		if(comparison(left[0],right[0]) < 0)
			result.push(left.shift());
		else
			result.push(right.shift());
	}
	while(left.length > 0)
		result.push(left.shift());
	while(right.length > 0)
		result.push(right.shift());
	return result;
}


/**
 * DestinationMatrix Class
 */
function DestinationMatrix(requestedId, startDate, displayDays, languageCode, skin, resultPerPage) {

	this.loaded       = false;
    this.requestedId  = requestedId;
    this.startDate    = startDate;
    this.days         = displayDays;
    this.endDate      = "";
    this.languageCode = languageCode;
    this.matrix       = null;
    this.checkIn      = "";
    this.checkOut     = "";

    this.sortTypeMapping = {
        'Popularity' : 'byPopularity',
        'Category'   : 'byStar',
        'Price'      : 'byPrice',
        'PriceDesc'  : 'byPriceDesc',
        'HotelName'  : 'byName'
    };

    this.facilityCodeMapping = {
        'restaurant'        : 'RR',
        'pool'              : 'SP',
        'broadbandInternet' : 'BB',
        'kitchenette'       : 'KC',
        'fitnessCentre'     : 'FC',
        'satelliteCableTV'  : 'TV'
    }
    
    // XXX: do we need this?
    this.renderFilter = true;
    
    this.extractQueryParams();
    
    /** Matrix results are defined by these parameters */
	this.params = {};
	this.params['requestedId']  = requestedId;
	this.params['startDate']    = startDate;
	this.params['days']         = displayDays;
	this.params['languageCode'] = languageCode;
	this.params['checkIn']      = this.checkIn;
	this.params['checkOut']     = this.checkOut;
	this.params['serviceHost']  = 'rates.asiawebdirect.com';
	this.params['pageSize']     = resultPerPage;
	this.params['pageNum']      = 1;
	this.params['sortBy']       = 'byPopularity';
	this.params['facilities']   = [];
	this.params['accomTypes']   = [];
	this.params['minPrice']     = 0;
	this.params['maxPrice']     = -1;
	this.params['priceFilterCurrency'] = 'THB';
	
	this.extractExtraQueryParams();

    // XXX: do we need this?
    this.reservation = null;

    // XXX: do we need this?
    this.restrictions = new Restriction();
    
    this.xDomain = true;
    this.destMatrix = true;
    this.domainName = 'rates.asiawebdirect.com'; // should be removed in favor of params['serviceHost']
    this.skin = skin;
    
    this.matrixType = "Destination"; // should be removed as this is a specific class for the destination matrix only
    
    this.matrixActions = new Array(); // should be removed
    this.matrixActions["Destination"] = "dest"; // should be removed
    
    this.resultPerPage = resultPerPage; // should be removed in favor of this.params
    this.pageNo = 1; // should be removed in favor of this.params
    this.usePagination = true;
}

	DestinationMatrix.prototype.sortBy = function(by) {
		this.params['sortBy'] = this.sortTypeMapping[by];
		this.params['pageNum'] = 1;
		this.loadMatrix();
	}

	DestinationMatrix.prototype.doFilter = function() {
        // filter facilities
		var facilityCodes = [];
        for (var key in this.facilityCodeMapping) {
        	if ($(key) && $(key).checked) {
        		facilityCodes.push(this.facilityCodeMapping[key]);
        	}
        }
        this.params['facilities'] = facilityCodes;
        
        // filter accom types
        var accomTypeIds = [];
		if (window.matrix.data.accomList) {
		    for (var i = 0; i < window.matrix.data.accomList.length; i++) {
		    	var chk = $('mtx_fltr_accom_' + i);
			    if (!chk) continue;
			    if (chk.checked) {
				    var name = chk.value;
				    for (var j = 0; j < window.matrix.data.accomList.length; j++) {
				    	var sType = window.matrix.data.accomList[j];
				    	if (sType.name == name) {
				    		accomTypeIds.push(sType.id);
				    	}
				    }
			    }
		    }
		}
		this.params['accomTypes'] = accomTypeIds;
        
		// filter min and max price
		var minPrice = parseInt($('minPrice').innerHTML.replace(/,/g, ''), 10);
		var maxPrice = parseInt($('maxPrice').innerHTML.replace(/,/g, ''), 10);
		if (isNaN(minPrice) || minPrice < 0) minPrice = 0;
		if (isNaN(maxPrice) || maxPrice < 0) maxPrice = 0;

		// convert min and max prices to the destination currency
		var filter_currency = $('priceRangeCurrency').value;
		if (this.data.currency != filter_currency) {
			// find currency index
			var fc_idx = null;
			var cu_idx = null;
			for (var i = 0; i < this.data.currencies.length; i++) {
				if (this.data.currencies[i]['code'] == filter_currency) fc_idx = i;
				if (this.data.currencies[i]['code'] == this.data.currency) cu_idx = i;
			}

			if (fc_idx != null && cu_idx != null) {
			    minPrice = Math.ceil(minPrice * this.data.currencies[fc_idx]['rate'] / this.data.currencies[cu_idx]['rate']);
			    maxPrice = Math.floor(maxPrice * this.data.currencies[fc_idx]['rate'] / this.data.currencies[cu_idx]['rate']);
			}
		}
		this.params['minPrice'] = minPrice;
		this.params['maxPrice'] = maxPrice;

        // reset to first page
        this.params['pageNum'] = 1;
        
        // reload results
        this.loadMatrix();
	}

	// should be removed as pagination is now mandatory
	DestinationMatrix.prototype.setUsePagination = function(setValue) {
		this.usePagination = true; // always force pagination
	}

	DestinationMatrix.prototype.movePrevious = function() {
		if (this.params['pageNum'] != 1) {
		    this.params['pageNum'] = this.params['pageNum'] - 1;
		}
		this.loadMatrix();
	}

	DestinationMatrix.prototype.moveNext = function() {
		this.params['pageNum'] = this.params['pageNum'] + 1;
		this.loadMatrix();
	}

	DestinationMatrix.prototype.gotoPage = function(pageNo) {
		this.params['pageNum'] = parseInt(pageNo);
		this.loadMatrix();
	}
	
	DestinationMatrix.prototype.setResultPerPage = function(resultNo) {
		this.params['pageSize'] = resultNo;
		this.params['pageNum'] = 1;
		this.loadMatrix();
	}

    DestinationMatrix.prototype.enableXDomain = function(domainName) {
    	this.domainName = domainName; // XXX Remove me
    	this.params['serverHost'] = domainName;
    }
    
    // XXX do we need this function?
    DestinationMatrix.prototype.setMatrixType = function(matrixType) {
    	this.matrixType = "Destination"; // only allow this matrix type
    }
    
    // XXX do we need this function?
    DestinationMatrix.prototype.setRequestedId = function(requestedId) {
    	this.requestedId = requestedId;
    	this.params['requestedId'] = requestedId;
    	this.loadMatrix();
    }

    DestinationMatrix.prototype.setParacheckInOut = function(_tmp_checkIn, _tmp_checkOut) {
		if(String(_tmp_checkIn)!="null")
		if(String(_tmp_checkOut)!="null")
		if(String(_tmp_checkIn).substring(0,1)=="2")
		if(String(_tmp_checkOut).substring(0,1)=="2")
		{
        	var checkIn = strToDate(_tmp_checkIn);
        	var my_date = new Date();
        	var to_day = new Date(my_date.getFullYear(), my_date.getMonth(), my_date.getDate());
        	if (checkIn >= to_day) {
				this.checkIn = _tmp_checkIn;
				this.checkOut = _tmp_checkOut;
				this.startDate = 'checkIn';
				this.params['checkIn'] = this.checkIn;
				this.params['checkOut'] = this.checkOut;
				this.params['startDate'] = 'checkIn';
        	}
		}
		this.loadMatrix();
    }

    DestinationMatrix.prototype.setCookie = function(requestedId) {
		var url = "/asahi/setcookie.php?mtxSetCookie=1&mtxCheckIn=" + this.checkIn + "&mtxCheckOut=" + this.checkOut + "&tm="+(Math.random());
		this._doMatrixRequest(url);
    }

    DestinationMatrix.prototype.extractQueryParams = function() {
        var checkInParam  = queryParam("mtxCheckIn");
        var checkOutParam = queryParam("mtxCheckOut");
        if (checkInParam != '' && checkOutParam != '') {
        	var checkIn = strToDate(checkInParam);
        	var my_date = new Date();
        	var to_day = new Date(my_date.getFullYear(), my_date.getMonth(), my_date.getDate());
        	
        	if (checkIn < to_day) return;

        	this.checkIn   = checkInParam;
        	this.checkOut  = checkOutParam;
        	this.startDate = 'checkIn';
        }
        
        // allow query params to specify portal
        var portal = queryParam('mtxPortal');
        if (portal != '') {
        	window.mtx_portal = portal;
        }
    }
    
    DestinationMatrix.prototype.extractExtraQueryParams = function() {
    	// facility params
        if (queryParam('mtxRestaurant')) {
            this.params['facilities'].push(this.facilityCodeMapping['restaurant']);
        }
        if (queryParam('mtxSatelliteCableTV')) {
        	this.params['facilities'].push(this.facilityCodeMapping['satelliteCableTV']);
        }
        if (queryParam('mtxKitchenette')) {
        	this.params['facilities'].push(this.facilityCodeMapping['kitchenette']);
        }
        if (queryParam('mtxPool')) {
        	this.params['facilities'].push(this.facilityCodeMapping['pool']);
        }
        if (queryParam('mtxFitnessCentre')) {
        	this.params['facilities'].push(this.facilityCodeMapping['fitnessCentre']);
        }
        if (queryParam('mtxBroadbandInternet')) {
        	this.params['facilities'].push(this.facilityCodeMapping['broadbandInternet']);
        }

    }
    
    DestinationMatrix.prototype.extractCookie = function() {
		if((this.checkIn==null) || (this.checkIn==""))
		{
			var url = "/asahi/setcookie.php?tm="+(Math.random());
			this._doMatrixRequest(url);
		}
		else
		{
			this.loadMatrix();
		}
	}

    DestinationMatrix.prototype.loadMatrix = function () {
    	var facilityCodes = 'None';
    	if (this.params['facilities'].length > 0) {
    		facilityCodes = this.params['facilities'].join(',');
    	}
    	
    	var accomTypeIds = 'None';
    	if (this.params['accomTypes'].length > 0) {
    		accomTypeIds = this.params['accomTypes'].join(',');
    	}
    	
    	if (this.portal == 1) {
    		var urltarget = "pdestf";
    	} else {
    		var urltarget = "destf";
    	}
    	
        url = "/asahi/frontend.php/rates/"+ urltarget +"/" +
              this.params['sortBy'] + "/" +
              this.params['languageCode'] + "/AWD/"  +
              this.params['requestedId'] + "/" +
              this.params['startDate'] + "/" +
              this.params['days'] + "/" +
              this.params['pageSize'] + "/" +
              this.params['pageNum'] + "/" +
              facilityCodes + "/" +
              accomTypeIds + "/" +
              this.params['minPrice'] + "/" +
              this.params['maxPrice'] + "/" +
              this.params['priceFilterCurrency']

        if (this.params['checkIn'] && this.params['checkOut'] != "")
        	url = url + "/" + this.params['checkIn']  + "/" + this.params['checkOut'];
        document.fire("matrix:loading", this);
        this._doMatrixRequest(url);
    }

    DestinationMatrix.prototype._doMatrixRequest = function (url) {
        url = 'http://' + this.params['serviceHost'] + url;
        var headNode = document.getElementsByTagName("head")[0];
        var script   = document.createElement('script');
        script.type  = 'text/javascript';
        script.src   = url;
        headNode.appendChild(script);
    }
    
    DestinationMatrix.prototype.displayMatrix = function(data) {
    	this.displayReady = false;
    	this.waitingForDisplayCurrency = false;

        if (data["detail"]) {
            this.startDate = data["detail"]["startDate"];
            this.endDate   = data["detail"]["endDate"];
            if (data["detail"]["checkIn"]) this.checkIn    = data["detail"]["checkIn"];
            if (data["detail"]["checkOut"]) this.checkOut  = data["detail"]["checkOut"];
            this.numCols   = data["detail"]["numCols"];
        }
        if (this.data != null) {
        	this.accomList = this.data.accomList;
        } else {
        	this.accomList = [];
        }
        this.data = data;
        this.data.showResults = this.data.results;
        this.applySkin(data);

        if (!this.loaded) this.doInitialLoad(data);
        
        if (getCookie('mtxBookCheckInDate') != null && getCookie('mtxBookCheckOutDate') != null) {
        	this.checkIn = getCookie('mtxBookCheckInDate');
        	this.checkOut = getCookie('mtxBookCheckOutDate');
        	delCookie('mtxBookCheckInDate');
        	delCookie('mtxBookCheckOutDate');
        }
        
        // XXX do we need this?
        if (this.checkIn && this.checkOut) {
        	if (!this.reservation) {
        		this.reservation = new Reservation();
        		this.reservation.setNights(strToDate(this.checkIn), strToDate(this.checkOut));
        	}
        }
        
        // XXX do we need this?
        if (this.reservation) {
        	if (this.reservation.numNights > 0) {
        		this.reservation.setRatePlanInvalidDates();
        	}
        }

        document.fire("matrix:checkInOutSetExternaly", this); // synchronize calendar dates with matrix checkin/checkout dates
        this.displayReady = true;

    	if (!this.waitingForDisplayCurrency) {
    		document.fire("matrix:loaded", this);
    	}
    	
        if (this.data.results.length == 0) {
        	document.fire("matrix:noResults", this);
        }
        this.loaded = true;
    }
    
    DestinationMatrix.prototype.setDisplayCurrencyExternally = function(currencyCode) {
    	if (this.displayReady) {
    		document.fire("matrix:loaded", this);
    	} else {
    		this.waitingForDisplayCurrency = false;
    	}
    }
    
    DestinationMatrix.prototype.doInitialLoad = function(data) {
		// tooltip
		var ttDiv = document.createElement("div");
		ttDiv.id = "mtx_rateBlurb";
		ttDiv.className = "popup-container";
		ttDiv.style.display = 'none';

		div_top = document.createElement("div");
		div_top.className = "popup-top";
		ttDiv.appendChild(div_top);

		div_body = document.createElement("div");
		div_body.className = "popup-body";
		ttDiv.appendChild(div_body);

		div_bottom = document.createElement("div");
		div_bottom.className = "popup-bottom";
		ttDiv.appendChild(div_bottom);

	    ttP = document.createElement("p");
	    ttP.id = "mtx_rateBlurbMsg";
	    div_body.appendChild(ttP);

		document.body.appendChild(ttDiv);

		// Error
		var ttDiv = document.createElement("div");
		ttDiv.id = "dealSelectionError";
		ttDiv.className = "dealselectionerror";
		ttDiv.style.display = 'none';

	    ttP = document.createElement("p");
	    ttP.id = "mtx_errorMsg";
	    ttDiv.appendChild(ttP);

        ttP = document.createElement("p");
        ttP.id = "mtx_errorMsgCloseButton";
        ttP.innerHTML = '<span id="mtx_errorButton"></span>&nbsp;<input id="errMsgCloseBtn" type="submit" value = "Close" onclick="hideDealSelectionError()" />';
        ttP.style.textAlign = 'center';
        ttDiv.appendChild(ttP);

        document.body.appendChild(ttDiv);
        initializeCalendar();
    }
    
    DestinationMatrix.prototype.setSkin = function(name) {
    	this.skin = name;
    	var data = this.data;
    	this.applySkin(data);
    	document.fire("matrix:loaded", this);
    	document.fire("matrix:checkInOutSetExternaly", this); // synchronize calendar dates with matrix checkin/checkout dates
    }
    
    DestinationMatrix.prototype.applySkin_list = function(data) {
    	var mtx = tmpl_str(data.skins.list.template_list, data);

    	this.matrix.innerHTML = tmpl_str(data.skins.list.template_outline, {
    		'checkIn' : this.checkIn != null ? strToDate(this.checkIn) : null,
    		'checkOut' : this.checkOut != null ? strToDate(this.checkOut) : null
    	});

    	this.renderFilter = true;
    	document.getElementById("thematrixdiv").innerHTML = mtx;
    }
    
    DestinationMatrix.prototype.applySkin_matrix = function(data) {
    	data['dateRow'] = tmpl_str(data.skins.matrix.template_dateRow, data);
    	var mtx = tmpl_str(data.skins.matrix.template_matrix, data);
    	if (!this.loaded) {
    		this.matrix.innerHTML = tmpl_str(data.skins.matrix.template_outline, data);
    	}
    	document.getElementById("thematrixdiv").innerHTML = mtx;
    	startapp(document.forms['checkAvailShort'], ""); // XXX Is this needed?
    }
    
    DestinationMatrix.prototype.applySkin_photo_list = function(data) {
    	var mtx = tmpl_str(data.skins.list.template_photo_list, data);
    	this.matrix.innerHTML = tmpl_str(data.skins.list.template_outline, {
    		'checkIn' : this.checkIn != null ? strToDate(this.checkIn) : null,
    		'checkOut' : this.checkOut != null ? strToDate(this.checkOut) : null
    	});

    	document.getElementById("thematrixdiv").innerHTML = mtx;
    }
    
    DestinationMatrix.prototype.applySkin = function(data) {
    	var featuredNum = 0;
    	if (this.data.featured) { featuredNum = this.data.featured.length; }
		if (typeof(data) == "undefined") return false;
		this.saveCriteria();
    	this.matrix = document.getElementById("_mtx_container");

    	data.showPagination = true;
    	data.pagination = new Array();
    	data.pagination.startRecord = 0;
    	data.pagination.endRecord = data.results.length - 1;
    	data.pagination.showPreviousButton = this.params['pageNum'] > 1;
    	data.pagination.numberOfPage = data.numPages;
    	data.pagination.showNextButton = this.params['pageNum'] != data.pagination.numberOfPage;
    	data.pagination.pageNo = this.params['pageNum'];

    	this['applySkin_' + this.skin](data);
    	this.restoreCriteria();
    }
    
    DestinationMatrix.prototype.restoreCriteria = function() {
    	if (typeof(matrixFilter) != "undefined") matrixFilter.Restore();
    }
    
    DestinationMatrix.prototype.saveCriteria = function() {
    	matrixFilter = new MatrixFilter();
    	matrixFilter.KeepCurrent();
    }

    DestinationMatrix.prototype.loadCheckInMatrix = function (checkIn, checkOut) {
        this.checkIn = checkIn;
        this.checkOut = checkOut;
        this.startDate = "checkIn";
        this.params['checkIn'] = checkIn;
        this.parans['checkOut'] = checkOut;
        this.params['startDate'] = 'checkIn';
        
        /* change the reservation dates to the new dates */
        if (this.reservation) {
        	this.reservation.clearNights();
        	if (this.checkIn && this.checkOut) { 
        		this.reservation.setNights(strToDate(this.checkIn), strToDate(this.checkOut));
        	}
        }
        this.loadMatrix();
    }
    
    DestinationMatrix.prototype.nextPage = function(incDays) { this.changePage(incDays); }
    DestinationMatrix.prototype.prevPage = function(incDays) { this.changePage(-incDays); }

    DestinationMatrix.prototype.changePage = function(days) {
        this.startDate = incDateStr(this.startDate, days);
        this.endDate = incDateStr(this.startDate, this.days);
        this.params['startDate'] = this.startDate;
        this.loadMatrix();        
    }

    DestinationMatrix.prototype.resetSelectedNights = function(dateStr) {
    	if (this.reservation) {
    		for (var i=0; i<this.data.dates.length; i++) {
    			cb = $(this.data.dates[i].fmt + '_cb');
    			if (cb) {
    				cb.checked = (this.data.dates[i].fmt == dateStr);
    				hilightSelectedColumn(cb, i+1);
    			}
    		}
    	}
    }

    DestinationMatrix.prototype.isInReservationPeriod = function(dateStr) {
        return this.reservation && this.reservation.numNights > 0 && this.reservation.isInReservation(strToDate(dateStr));
    }
    
    DestinationMatrix.prototype.hideRatePlanSelection = function() {
        // this function does nothing but is required to exist by the currency conversion utility
    }
    
    DestinationMatrix.prototype.unhideRatePlanSelection = function() {
        // this function does nothing but is required to exist by the currency conversion utility
    }
    
    function MatrixHelper() {
    	this.DealRow 			= $$("tr.deal_row");
    	this.firstSelectedCol 	= null;
    	this.lastSelectedCol 	= null;
    	this.previousTotalCol 	= null;
    	this.totalTemplate 		= new Template('<div class="total_wrapper"><div class="total" style="width: #{Width}%;#{ExtraStyle}"><nobr><span class="currency_symbol_sup" name="ccs">#{Symbol}</span><span class="per_night_value" name="drc">#{FormattedAverageRate}<span class="or">#{AverageRate}</span></span></nobr><br/><span class="per_night">per night</span></div></div>');
    	this.dateNotAvailableTemplate = new Template('<div class="total_wrapper"><div class="date_not_available_wrapper" style="width: #{Width}%" onmouseover="#{OnMouseOver}" onmouseout="hidePinkPopup()" onclick="#{OnClick}"><div class="date_not_available">#{Label}</div><div class="date_not_available_icon">&nbsp;</div></div>');
    	this.ratePlanBlurbIndex	= null;
    	this.ratePlanBlurbId 	= null;
    	this.rackRates 			= 0;
    	this.Cancellation		= new Array();
    	this.cancellationPolicy = '';
    	
    	this.state = {
            columns: [	{ selected: false },
            			{ selected: false },
            			{ selected: false },
            			{ selected: false },
            			{ selected: false },
            			{ selected: false },
            			{ selected: false },
            			{ selected: false },
            			{ selected: false },
            			{ selected: false },
            			{ selected: false },
            			{ selected: false },
            			{ selected: false },
            			{ selected: false }
            		],
            totalDays: 14,
            firstSelectedColumn: null,
            lastSelectedColumn: null,
    		firstCheckedDate: null,
    		lastCheckedDate: null,
    		hiddenSelectOffset: 0,
            selectedColumns: []
    	}
    	
    	this.mouseOver = new Array();
    	
    	this.nodes = {
    			checkboxes: $$("#checkbox_row td input"),
    			dates: $$("#thematrix .mtxDateRow"),
    			checks: $$("#thematrix .mtx_date_select_td"),
    			dealTables: $('thematrix'),
    			hotelRows: $$("#thematrix tr.deal_row"),
    			deals: $$("#thematrix td.mtx_rate")
    	};
    	
    	this.rates 			= new Array();
    	this.dates 			= new Array();
    	this.deals 			= new Array();
    	this.ratesMapping	= new Array();
    	
    	MatrixHelper.prototype.checkCol = function(idx) {
    		var checkboxes = $$("#checkbox_row td input");
    		if (checkboxes[idx]) {
    			checkboxes[idx].checked = true;
    		}
    	}
    	
    	MatrixHelper.prototype.clearSelectedColumns = function() {
    		var checkboxes = $$("#checkbox_row td input");
    		checkboxes.each(function(item) {
    			item.checked = false;
    		});
    		
    		this.state.firstSelectedColumn = null;
    		this.state.lastSelectedColumn = null;    		
    		this.state.firstCheckedDate = null;
    		this.state.lastCheckedDate = null;
//    		this.state.hiddenSelectOffset = 0;

    		for (var i=0; i<this.state.columns.length; i++) {
    			if (this.state.columns[i].selected) {
    				this.deSelectColumn(i);
    			}
    		}
    	}
    	
    	MatrixHelper.prototype.initialize = function() {
    		if (!window.matrix || !window.matrix.loaded || window.matrix.matrixType!="Hotel") {
    			return;
    		}
    		this.state.firstSelectedColumn = null;
    		this.state.lastSelectedColumn = null;
    		this.state.firstCheckedDate = null;
    		this.state.lastCheckedDate = null;
    		this.state.hiddenSelectOffset = 0;
    		
    		this.state.columns.each(function(item) {
    			item.selected = false;
    		});
    		
    		if (window.matrix) {
    	    	matrix.data.allDates.each(function(item, idx) {
    	    		this[idx] = item.fmt;
        		}, this.dates);
    	    	for (var i=0; i<matrix.data.results.length; i++) {
    	    		this.rates[i]			= new RateObject(matrix.data.allDates, matrix.data.results[i].rates, matrix.data.results[i].promotions, matrix.data.results[i].rack_rate, matrix.data.currency, matrix.data.currency_symbol);
    	    		this.ratesMapping[i]	= matrix.data.results[i].id;
    	    		this.Cancellation[i]	= new Cancellation(matrix.data.results[i].cancellation_policy);
    	    		this.deals[i]			= { state: 'Book', active: true , errMsg: '' }
    	    	}

	    		if (window.matrix.checkIn && window.matrix.checkOut) {
	    			// pre-check for checkIn/chcekOut date in cookie
	    			var start = this.dates.indexOf(window.matrix.checkIn);
	    			this.state.firstCheckedDate = start;
	    			this.state.hiddenSelectOffset = this.dates.indexOf(window.matrix.startDate);
					var c_out = strToDate(window.matrix.checkOut);
					c_out.setDate(c_out.getDate()-1);
    				var end = this.dates.indexOf(c_out.format("%Y%m%d"));
    				this.state.lastCheckedDate = end;
    				end = end-this.state.hiddenSelectOffset;
    				
    				if (end > this.state.totalDays-1) {
    					end = this.state.totalDays-1;
    				}
    				
    				if (start>=0 && end>=0) {
	    				var $checkboxes = $$("#checkbox_row td input");
    			
    					for (var i=start; i<=end; i++) {
    						$checkboxes[i].checked = true;
    						this.selectColumn(i);
    					}
 						this.updateTotals();
 						this.reOrderMatrix();
    				} else {
    					this.setBookButtonState();
    				}
     			}
     		}
    	}
    	
    	MatrixHelper.prototype.setBookButtonState = function() {
    		$hotelRows = $$("#thematrix tr.deal_row");
        	for (i = 0; i < $hotelRows.length; i++) {
    	    	// remove existing total div
    	    	var tr_id = $($hotelRows[i]).id;
    	    	var rate_idx = this.ratesMapping.indexOf(tr_id);
    	    	var valid = true;
    	    	
    	    	var res						= new Reservation();
    	    	res.ratePlanId				= tr_id;
    	    	res.restrictions			= matrix.restrictions;
    	    	res.numNights				= matrix.reservation.numNights;
    	    	res.checkIn					= matrix.reservation.checkIn;
    	    	res.checkOut				= matrix.reservation.checkOut;
    	    	res.ratePlanInvalidDates	= matrix.reservation.ratePlanInvalidDates;
    	    	
    	    	if (res.numNights<1 || 
    	    			(res.numNights>0 && !res.isValid())) {
    	    		valid = false;
    	    	}
    	    	
    	    	this.deals[rate_idx].active = valid;

    	    	if (res.numNights > 0 && matrix.restrictions.reservationIsRestricted(matrix.reservation, tr_id, "OnRequest")) {
    	    		this.deals[rate_idx].state = 'Request Now';
    	    	} else {
    	    		this.deals[rate_idx].state = 'Book Now';
    	    	}

    	    	var btn = document.getElementById(tr_id + "_submit");
    	    	if (btn) {
    	    		if (this.deals[rate_idx].state == 'Book Now') {
    	    			if (this.deals[rate_idx].active) {
    	    				btn.className = "submitBook";
    	    			} else {
    	    				btn.className = "submitDisabled";
    	    			}
    	    		} else {
    	    			if (this.deals[rate_idx].active) {
    	    				btn.className = "submitRequest";
    	    			} else {
    	    				btn.className = "requestDisabled";
    	    			}
    	    		}
    	    	}
        	}
    	}
    	
    	MatrixHelper.prototype.verify = function() {
    		/* verify that calculated data is in the same currency as the updated selected currency */
    		if (!window.currencyConverter || !window.currencyConverter.indicativeCurrency) return;
    		if (this.rates[0].currencyCode.valueOf() != window.currencyConverter.indicativeCurrency.isoCode.valueOf()) {
    			this.refreshTotal();
    		}
    	}
    	
    	MatrixHelper.prototype.updateCancellation = function(idx) {
    		if (this.state.firstSelectedColumn===null && this.state.firstCheckedDate===null) return;
    		
    		//this.cancellationPolicy = this.Cancellation[idx].update(this.dates[this.state.firstSelectedColumn], this.dates[this.state.lastSelectedColumn]);
    		this.cancellationPolicy = this.Cancellation[idx].update(this.dates[this.state.firstCheckedDate], this.dates[this.state.lastCheckedDate]);
    		
    		return this.cancellationPolicy;
    	}
    	
    	MatrixHelper.prototype.refreshTotal = function() {
    		this.rates.each(function(item) { item.refresh(); });
    	}
    	
    	MatrixHelper.prototype.checkCheckboxes = function() {
			var checkboxes = $$("#checkbox_row td input");
	
			for (var i=0; i<checkboxes.length; i++) {
				if (this.state.columns[i].selected) {
					checkboxes[i].checked = true;
				}
			}
    	}
    	
    	MatrixHelper.prototype.toggleColumn = function(col) {
    		if (col< 0) return;
    		
    		if (this.state.columns[col].selected) {
    			this.deSelectColumn(col);
    		} else {
    			this.selectColumn(col);
    		}
    		this.updateTotals();
			this.reOrderMatrix();
    	}
    	
    	MatrixHelper.prototype.selectColumn = function(col) {
    		this.state.columns[col].selected = true;
    		if ((!this.state.firstSelectedColumn && this.state.firstSelectedColumn!=0) || col < this.state.firstSelectedColumn) {
    			this.state.firstSelectedColumn = col;			
    		}
    		if (!this.state.lastSelectedColumn || col > this.state.lastSelectedColumn) {
    			this.state.lastSelectedColumn = col;
    		}

    		if ((!this.state.firstCheckedDate && this.state.firstCheckedDate!=0) || col < this.state.firstCheckedDate-this.state.hiddenSelectOffset) {
    			this.state.firstCheckedDate = col+this.state.hiddenSelectOffset;
    		}
    		if (!this.state.lastCheckedDate || col+this.state.hiddenSelectOffset > this.state.lastCheckedDate) {
    			this.state.lastCheckedDate = col+this.state.hiddenSelectOffset;
    		}

        	$dates = $$("#thematrix .mtxDateRow");
        	$checks = $$("#thematrix .mtx_date_select_td");
    		
    		$dates[col].addClassName("selected");
    		$checks[col].addClassName("selected");
    		$('thematrix').addClassName("select" + col);

    		// remove mouse over
    		$hotelRows = $$("#thematrix tr.deal_row");
    		for (i = 0; i < $hotelRows.length; i++) {
    			var tr_id = $($hotelRows[i]).id;
    			var rate_idx = this.ratesMapping.indexOf(tr_id);
        		var deals = $$("#" + tr_id + " td.mtx_rate");
        		
        		if (!this.mouseOver[tr_id]) {
        			this.mouseOver[tr_id] = new Array();
        		}
        		this.mouseOver[tr_id][col] = deals[col].onmouseover;
        		deals[col].onmouseover = function() { return true; };
        	}
    	}
    	
    	MatrixHelper.prototype.deSelectColumn = function (col) {
    		this.state.columns[col].selected = false;		

        	$dates = $$("#thematrix .mtxDateRow");
        	$checks = $$("#thematrix .mtx_date_select_td");
        	
    		$dates[col].removeClassName("selected");
    		$checks[col].removeClassName("selected");
    		
    		// update first and last column references
    		var isFirst = col === (this.state.firstCheckedDate-this.state.hiddenSelectOffset);
    		var isLast = col === (this.state.lastCheckedDate-this.state.hiddenSelectOffset);
    		if (isFirst && isLast) {
    			this.state.firstSelectedColumn = null;
    			this.state.lastSelectedColumn = null;
    			if (this.state.hiddenSelectOffset == 0) {
    				this.state.firstCheckedDate = null;
    				this.state.lastCheckedDate = null;
    			}
    		} else {
    			if (isFirst) {
    				this.state.firstSelectedColumn++;
    				this.state.firstCheckedDate++;
    				if (this.state.firstSelectedColumn<this.state.totalDays) {
    					// in case of remove the last selected night in current window but still date selected for the future
    					$(this.nodes.checkboxes[this.state.firstSelectedColumn]).removeAttribute("disabled");
    				}
    			}
    			if (isLast) {
    				this.state.lastSelectedColumn--;
    				this.state.lastCheckedDate--;
    				if (this.state.lastSelectedColumn >= 0) {
    					$(this.nodes.checkboxes[this.state.lastSelectedColumn]).removeAttribute("disabled"); 				
    				}
    			}
    		}
    		$('thematrix').removeClassName("select" + col);

    		// put back mouse over
    		$hotelRows = $$("#thematrix tr.deal_row");
    		for (i = 0; i < $hotelRows.length; i++) {
    			var tr_id = $($hotelRows[i]).id;
        		var deals = $$("#" + tr_id + " td.mtx_rate");
        		deals[col].onmouseover = this.mouseOver[tr_id][col];
        	}
        }
    	
    	MatrixHelper.prototype.removeHoverMsg = function (oRow) {
    		// remove mouseover popup for selected column
    		if (this.state.firstSelectedColumn === null) return;
    		
    		$hotelRows = $$("#thematrix tr.deal_row");
        	for (i = 0; i < $hotelRows.length; i++) {
        		if (oRow && oRow.id!=$hotelRows[i].id) {
        			continue;
        		}
        		
    	    	// remove existing total div
    	    	var tr_id = $($hotelRows[i]).id;
    	    	var rate_idx = this.ratesMapping.indexOf(tr_id);
    	    	var deals = $$("#" + tr_id + " td.mtx_rate");
       
        		var startPos = this.state.firstSelectedColumn;
        		var endPos = startPos + (this.state.lastSelectedColumn - this.state.firstSelectedColumn);
        		
	    		for (var idx=startPos; idx<=endPos; idx++) {
	    			deals[idx].onmouseover = function() { return true; };
	    		}

    	    	if (oRow && oRow.id==$hotelRows[i].id) {
    	    		break;
    	    	}
    	    }
    	}
    	
    	MatrixHelper.prototype.updateTotals = function (cloned_row) {
        	// Loop through rows
    		$hotelRows = $$("#thematrix tr.deal_row");
        	for (i = 0; i < $hotelRows.length; i++) {
        		if (cloned_row && cloned_row.id!=$hotelRows[i].id) {
        			continue;
        		}
        		
    	    	// remove existing total div
    	    	var tr_id = $($hotelRows[i]).id;
    	    	var rate_idx = this.ratesMapping.indexOf(tr_id);
    	    	var deals = $$("#" + tr_id + " td.mtx_rate");
    	    	var total_wrappers = $$("#" + tr_id + " div.total_wrapper");
    	    	total_wrappers.each(function(item) {
    	    		item.remove();
    	    	});
    	    
    	    	var valid = true;
    	    	
    	    	var res						= new Reservation();
    	    	res.ratePlanId				= tr_id;
    	    	res.restrictions			= matrix.restrictions;
    	    	res.numNights				= matrix.reservation.numNights;
    	    	res.checkIn					= matrix.reservation.checkIn;
    	    	res.checkOut				= matrix.reservation.checkOut;
    	    	res.ratePlanInvalidDates	= matrix.reservation.ratePlanInvalidDates;
    	    	
    	    	if (res.numNights<1 || 
    	    			(res.numNights>0 && !res.isValid())) {
    	    		valid = false;
    	    	}
    	    	
    	    	this.deals[rate_idx].active = valid;
    	    	this.deals[rate_idx].errMsg = res.getNotAvailableMessage();

    	    	if (res.numNights > 0 && matrix.restrictions.reservationIsRestricted(matrix.reservation, tr_id, "OnRequest")) {
    	    		this.deals[rate_idx].state = 'Request Now';
    	    	} else {
    	    		this.deals[rate_idx].state = 'Book Now';
    	    	}

    	    	var btn = document.getElementById(tr_id + "_submit");
    	    	if (btn) {
    	    		if (this.deals[rate_idx].state == 'Book Now') {
    	    			if (this.deals[rate_idx].active) {
    	    				btn.className = "submitBook";
    	    			} else {
    	    				btn.className = "submitDisabled";
    	    			}
    	    		} else {
    	    			if (this.deals[rate_idx].active) {
    	    				btn.className = "submitRequest";
    	    			} else {
    	    				btn.className = "requestDisabled";
    	    			}
    	    		}
    	    	}
    	    	
    	    	if (this.state.firstSelectedColumn===null && this.state.firstCheckedDate===null) {
    	    		this.rates[rate_idx].numberOfNights = res.numNights;
    	    		continue;
    	    	}
    	    	
    	    	var rowPrice = 0;
    	    	rowPrice = this.rates[rate_idx].getTotal(this.dates[this.state.firstCheckedDate], this.dates[this.state.lastCheckedDate]);
    	    	
    	    	if (this.state.firstSelectedColumn===null || this.state.firstSelectedColumn>=this.state.totalDays) {
    	    		continue;
    	    	}
       
        		var extra_style = '';
        		var startPos = this.state.firstSelectedColumn;
        		var endPos = startPos + (this.state.lastSelectedColumn - this.state.firstSelectedColumn);
        		var days = endPos - startPos + 1;
        		var merge = true;
        		
        		if (endPos-startPos < 0) continue
				
        		if (endPos-startPos == 0) {
					// only one column show as selected
					extra_style = 'position:static;padding-top:14px';
					merge = false;
	        		if (this.state.firstCheckedDate!==null && this.state.lastCheckedDate!=null) {
	        			if (this.state.lastCheckedDate-this.state.firstCheckedDate) {
	        				merge = true;
	        			}
	        		}
				}
    	    	
    	    	if (!valid) {
    	    		merge = true;
    	    	}
    	    	
    	    	if (valid && merge) {
    	    		var symbol = this.rates[rate_idx].currencySymbol;
    	    		
    	    		if (window.currencyConverter.indicativeCurrency) {
    	    			symbol = window.currencyConverter.indicativeCurrency.symbol;
    	    		}
    	    		var data = {
    	    			Width: days*100,
    	    			AverageRate: this.rates[rate_idx].averageRateLocal,
    	    			FormattedAverageRate: addComma(this.rates[rate_idx].averageRate),
    	    			Symbol: symbol,
    	    			ExtraStyle: extra_style
    	    		};

    		    	$(deals[endPos]).innerHTML += this.totalTemplate.evaluate(data);
    		    	$($hotelRows[i]).addClassName("valid");
    	    	}
    	    	if (!valid) {
    		    	if (res.errorMsg != '') {
	    		    	var mouseOver = "showPinkPopup(this,'" + res.errorMsg + "', event)";
	    		    	var onClick = "toggleRatePlan('" + window.matrix.data.results[rate_idx].id + "', '" + escape(window.matrix.data.results[rate_idx].name) + "', '" + window.matrix.data.results[rate_idx].rpCode + "', '" + window.matrix.data.results[rate_idx].invSrc + "')";
    		    	}
    		    	$($hotelRows[i]).addClassName("valid");
    		    	
    		    	var label = res.getRestrictionLabel();

    		    	var data = {
    		    			Label: label,
        	    			Width: days*100,            	    			
        	    			Title: res.errorMsg,
        	    			OnMouseOver: mouseOver,
        	    			OnClick: onClick
        	    		};
		    		$(deals[endPos]).innerHTML += this.dateNotAvailableTemplate.evaluate(data);
    	    	}
    	    	if (!merge) {
    		    	$($hotelRows[i]).removeClassName("valid");
    	    	}
    	    	
    	    	if (cloned_row && cloned_row.id==$hotelRows[i].id) {
    	    		// remove mouseover on selected columns
    	    		for (var idx=startPos; idx<=endPos; idx++) {
    	    			deals[idx].onmouseover = function() { return true; };
    	    		}
    	    		break;
    	    	}
    	    }
        	
        	this.updateBlurbTotals();
        	
        }
    	
    	MatrixHelper.prototype.updateBlurbTotals = function() {
        	/* update expanded more info */
    		/* all rates are updated with updateTotals method */
    		var blurbs = $$('#thematrix tr.rate_plan_blurb_row');
    		if (blurbs && blurbs.length>0) {
    			for (var i=0; i<blurbs.length; i++) {
    				var row_id = blurbs[i].id;
    				var deal_id = row_id.split("_")[1];
    				var rate_idx = this.ratesMapping.indexOf(deal_id);
    				
    				if (rate_idx < 0) continue;
    				
    				matrix.checkRatePlanDateSelection(deal_id);
    				matrix.setDailyInclusions(blurbs[i], rate_idx);
    				
    				var d = $$("#" + row_id + " div.total-cover");
    				if (!this.deals[rate_idx].active) {
        				if (d && d[0]) {
    						d[0].hide();
        				}
        				matrix.setNotAvailable(rate_idx);
        				continue;
    				}
    				if (d && d[0]) {
    					d[0].show();
    				}
    				
    				var sp = $$("#" + row_id + " span.text-total-number");
    				if (sp && sp[0]) {
    					sp[0].update(addComma(this.rates[rate_idx].totalRate));
    					sp[0].update(addComma(this.rates[rate_idx].totalRate) + '<span class="or">' + this.rates[rate_idx].totalRateLocal + '</span>');
    				}
    				
    				var sp = $$("#" + row_id + " span.saved_currency_symbol");
    				if (sp && sp[0]) {
    					sp[0].update(this.rates[rate_idx].currencySymbol);
    				}
    				
    				var sp = $$("#" + row_id + " span.total_currency_symbol_sup");
    				if (sp && sp[0]) {
    					sp[0].update(this.rates[rate_idx].currencySymbol);
    				}
    				var save_span = $$("#" + row_id + " span.save-text");
    				if (save_span && save_span[0]) {
    					save_span[0].update(addComma(this.rates[rate_idx].savedRate) + '<span class="or">' + this.rates[rate_idx].savedRateLocal + '</span>');
    				}
    				
    				var save_span = $$("#" + row_id + " span.rack_rate");
    				if (save_span && save_span[0]) {
    					save_span[0].update(this.rates[rate_idx].currencySymbol);
    					save_span[1].update(addComma(this.rates[rate_idx].totalRackRate) + '<span class="or">' + this.rates[rate_idx].totalRackRateLocal + '</span>');
    				}
    				//total-nights-number
    				var sp = $$("#" + row_id + " span.total-nights-number");
    				if (sp && sp[0]) {
    					var text = this.rates[rate_idx].numberOfNights + " ";
    					text += (this.rates[rate_idx].numberOfNights>1) ? 'nights' : 'night';
    					sp[0].update(text);
    				}
    				
    				var d = $$("#" + row_id + " div.save-icon");
    				if (d && d[0]) {
    					if (this.rates[rate_idx].savedRate <=0) {
    						d[0].hide();
    					} else {
    						d[0].show();
    					}
    				}
    				
    				var cancellation_policy = this.updateCancellation(rate_idx);
    				var sp = $$("#" + row_id + " span.cancellation_policy");
    				if (sp && sp[0]) {
    					sp[0].update(cancellation_policy);
    				}
    				
    				var sp = $$("#" + row_id + " div.btn-pink");
    				if (sp && sp[0]) {
    					sp[0].update(this.deals[rate_idx].state);
    				}
    				matrix.setNotAvailable(rate_idx);
    			}
    		}
    	}
    	MatrixHelper.prototype.reOrderMatrix = function () {
	    	if (this.state.firstSelectedColumn===null && this.state.firstCheckedDate===null) {
	    		return;
	    	}

    		$hotelRows = $$("#thematrix tr.deal_row");
    		var activeDeals = Array();var aD=0;
        	for (i = 0; i < $hotelRows.length; i++) {
        		var deal_id = $hotelRows[i].id;
        		var rate_idx = this.ratesMapping.indexOf(deal_id);
    	    	var rowPrice = 0;
    	    	rowPrice = this.rates[rate_idx].getTotal(this.dates[this.state.firstCheckedDate], this.dates[this.state.lastCheckedDate]);
    	    	if (this.deals[rate_idx].active && rowPrice>0) {
    	    		var sortOrder = rowPrice+i.toPaddedString(4);
    	    		activeDeals[aD] = [ Number(sortOrder) , i ];aD++;
    	    	}
        	}

        	$ratePlanBlurbs = $$("#thematrix tr.rate_plan_blurb_row");
        	var activeBlurbs = Array();var aB=0;
        	for (i = 0; i < $ratePlanBlurbs.length; i++) {
        		var blurb_id = $ratePlanBlurbs[i].id;
        		var ids = blurb_id.splitOnUnderscore();
        		if(ids[1]>0) {
        			activeBlurbs[aB] = [ Number(ids[1]), Number(i) ];aB++;
        		}
        	}

    		var x = activeDeals.multiSort(0);

    		if(aD>0) {
	    		for(var i=(aD-1);i>=0;i--) {
	    			$('checkbox_row').insert({after : $hotelRows[x[i][1]] });
	    		}

	    		if(aB>0) {
	    			for(var i=0;i<aB;i++) {
	    				var deal_id = activeBlurbs[i][0].toString();
	   					$(deal_id).insert({after : $ratePlanBlurbs[activeBlurbs[i][1]] });
	    			}
	    		}
    		}
    	}
    }
    
    function RateObject (dates, rates, promotions, rack_rate, currency, currencySymbol) {
    	this.rates 				= rates;
    	this.valid 				= false;
    	this.promotions			= promotions;
    	this.rackRate 			= parseFloat(rack_rate);
    	this.dates 				= new Array();
    	this.totalRate 			= 0;
    	this.totalRateLocal 	= 0;
    	this.averageRateLocal	= 0;
    	this.averageRate		= 0;
    	this.savedRate 			= 0;
    	this.savedRateLocal		= 0;
    	this.numberOfNights		= 0;
    	this.currencyCode		= currency;
    	this.currencySymbol 	= currencySymbol;
    	this.totalRackRate		= 0;
    	this.totalRackRateLocal	= 0;
    	
    	dates.each(function(item, idx) {
    		this[idx] = item.fmt;
    	}, this.dates);
    	
    	RateObject.prototype.refresh = function() {
    		if (window.currencyConverter && window.currencyConverter.indicativeCurrency) {
    			this.currencyCode	= window.currencyConverter.indicativeCurrency.isoCode;
    			this.currencySymbol	= window.currencyConverter.indicativeCurrency.symbol;
    			this.totalRate 		= convertCurrency(this.totalRateLocal+'', window.currencyConverter.defaultCurrency.relativeRate, window.currencyConverter.indicativeCurrency.relativeRate);
    			this.averageRate	= convertCurrency(this.averageRateLocal+'', window.currencyConverter.defaultCurrency.relativeRate, window.currencyConverter.indicativeCurrency.relativeRate);
    			this.totalRackRate	= convertCurrency(this.totalRackRateLocal+'', window.currencyConverter.defaultCurrency.relativeRate, window.currencyConverter.indicativeCurrency.relativeRate);
    			this.savedRate		= this.totalRackRate-this.totalRate;
    		}
    	}
    	
    	RateObject.prototype.getTotal = function(checkIn, checkOut) {
    		this.numberOfNights = this.dateDiff(checkIn, checkOut)+1;
    		var total = 0;
    		this.valid = true;
    		var start = this.dates.indexOf(checkIn);
    		var end = this.dates.indexOf(checkOut);
    		var p_rates = new Array();
    		var idx = 0;
    		
    		for (var i=start; i<=end; i++) {
    			var fmt = this.dates[i];
    			if (!this.rates[fmt]) {
    				this.valid = false;
    				return 0;
    			} else {
    				total += parseFloat(this.rates[fmt]['p']);
    			}
    			p_rates[idx] = parseFloat(this.rates[fmt]['p']);
    			idx++;
    		}
    		
    		// apply promotion discount
    		var discount = 0;
    		for (var i=0; i<this.promotions.length; i++) {
    			if (this.promotions[i].type == "FreeNights") {
    				var fn = new FreeNights(this.promotions[i]);
    				discount += fn.getDiscount(checkIn, checkOut, p_rates);
    			}
    			
    		}
    		
    		if (this.rackRate > 0) {
    			this.totalRackRate = this.rackRate*this.numberOfNights;
    		} else {
    			this.totalRackRate = total;
    		}
    		
    		this.totalRackRate = this.totalRackRate.floor();
    		this.totalRackRateLocal = this.totalRackRate;
    		
    		total -= discount;
    		this.averageRate = total/this.numberOfNights;
    		
    		this.averageRate = this.averageRate.floor();
    		this.averageRateLocal = this.averageRate;
    		
    		this.totalRate = total.floor();
    		this.totalRateLocal = this.totalRate;
    		
    		this.savedRate		= this.totalRackRate-this.totalRate;
    		this.savedRate		= this.savedRate.floor();
    		this.savedRateLocal = this.savedRate;

    		total = total.floor();
    		
    		if (window.currencyConverter && window.currencyConverter.indicativeCurrency) {
    			this.currencyCode	= window.currencyConverter.indicativeCurrency.isoCode;
    			this.currencySymbol	= window.currencyConverter.indicativeCurrency.symbol;
    			this.totalRate 		= convertCurrency(this.totalRate+'', window.currencyConverter.defaultCurrency.relativeRate, window.currencyConverter.indicativeCurrency.relativeRate);
    			this.averageRate	= convertCurrency(this.averageRate+'', window.currencyConverter.defaultCurrency.relativeRate, window.currencyConverter.indicativeCurrency.relativeRate);
    			this.totalRackRate	= convertCurrency(this.totalRackRate+'', window.currencyConverter.defaultCurrency.relativeRate, window.currencyConverter.indicativeCurrency.relativeRate);
    			total				= convertCurrency(total+'', window.currencyConverter.defaultCurrency.relativeRate, window.currencyConverter.indicativeCurrency.relativeRate);
    			this.savedRate		= this.totalRackRate-this.totalRate;
    		}
    		
    		return total;
    	}
    	
    	RateObject.prototype.dateDiff = function(date1, date2) {
    		var d1 = strToDate(date1);
    		var d2 = strToDate(date2);
    		return (d2-d1)/(24*60*60*1000);
    	}
    }
    
    function FreeNights(obj) {
    	this.rule = obj;
    	this.nightCount = 0;
    	
    	FreeNights.prototype.getDiscount = function(checkIn, checkOut, rates) {
    		var discount = 0;
    		this.startDate = strToDate(this.rule.start_date);
    		this.endDate = strToDate(this.rule.end_date);
    		this.numberOfNights = this.rule.number_of_nights;
    		this.data = this.rule.data;
    		var c_in = strToDate(checkIn);
    		var c_out = strToDate(checkOut);
    		
		if (this.startDate>c_out || this.endDate<c_in) {
			return 0;
		}

    		if (c_in>=this.startDate) {
			var d = new Date(c_in);
		} else {
			var d = new Date(this.startDate);
		}
    		
    		while (d<=c_out) {
			if (d > this.endDate) break;

    			if (d>=this.startDate || d<=this.endDate) this.nightCount++;
    			d.setDate(d.getDate()+1);
    		}
    		if (this.nightCount>= this.numberOfNights) {
    			var data = this.data.split(",");
    			var limit = data[1];
    			
    			for (var i=this.numberOfNights-1; i<this.nightCount; i+=this.numberOfNights) {
    				discount += parseFloat(rates[i])*parseFloat(data[0]);
    				if (limit!="*" && i >= parseFloat(limit)) break;
    			}
    		}
    		
    		return discount;
    	}
    	
    	FreeNights.prototype.strToDate = function(str) {
    		return new Date(str.substr(0,4), str.substr(4,2), str.substr(6,2));
    	}
    }

    function Cancellation(obj) {
    	this.details	= obj;    	
    	this.startDate	= null;
    	this.endDate	= null;
    	
    	Cancellation.prototype.update = function(startDate, endDate) {
    		this.startDate = strToDate(startDate);
    		this.endDate = strToDate(endDate);
    		
    		var applies = new Array();
    		for (var i=0; i<this.details.length; i++) {
    			var start = strToDate(this.details[i].start_date);
    			var end = strToDate(this.details[i].end_date);
    			
				if (start<= this.endDate && end>=this.startDate) {
    				applies.push(this.details[i]);
    				if (this.details[i].type == "F") {
    					break;
    				}
    			}
    		}
    		
    		if (applies.length >0) {
    			this.apply(applies);
    		}
    		
    		return this.policy;
    	}
    	
    	Cancellation.prototype.apply = function(policies) {
			for (var i=0; i<policies.length; i++) {
				var policy = policies[i];
				if (policy.type == "F") {
					break;
				}
			}
    		
			if (!policy) {
				return false;
			}
    		
			this.decode(policy);
    	}
    	
    	Cancellation.prototype.decode = function(policy) {
    		if (policy.type == "T") {
    			this.policy = policy.text;
    			return;
    		}
    		if (policy.type == "O") {
    			if (policy.due_date == -1) {
    				this.policy = "This property's policy is that any cancellations or changes of dates to bookings will forfeit the full amount of the first changed or cancelled night.";
    			} else {
    				this.policy = "This rate requires any cancellation or date changes to be made at least " + (policy.due_date+1) + " days prior to check-in time to avoid forfeiting the full amount of the first changed or cancelled night.";    				
    			}
    		} else if (policy.type == "F") {
    			if (policy.due_date == -1) {
    				this.policy = "This property will not offer a refund if you want to cancel your booking for any reason.";
    			} else {
    				this.policy = "This rate requires any cancellation or date changes to be made at least " + (policy.due_date+1) + " days prior to check-in time to avoid forfeiting the full amount of the booking.";
    			}
    		}
    	}
    	
    	Cancellation.prototype.formatDate = function (oDate) {
    	    var d = oDate.getDate();
    	    var dateStr = (d<10) ? "0" + d : d;
    	    var m = oDate.getMonth() + 1;
    	    dateStr += " " + ((m<10) ? "0" + m : m);
    	    dateStr += " " + oDate.getFullYear();
    	    return dateStr;  

    	}
    }

;
//function checkShortlistIcon() { }
/**** MATRIX EVENT LISTENERS ****/

document.observe("matrix:loading", function(e) {
	var d = document.getElementById("mtx_loading");
	if (d) {
	    d.style.display = "inline";
	}
});

document.observe("matrix:loaded", function(e) {
	var d = document.getElementById("mtx_loading");
	if (d) {
	    d.style.display = "none";
	}
	
	var reqFilter = $('mtx_filterOnRequest');
	if (reqFilter != null) {
        reqFilter.checked = !matrix.showOnRequest;
	}
	if ($('mtx_rateBlurb')) $('mtx_rateBlurb').style.display = 'none';
	
	if (!window.mtxHelper) {
		mtxHelper = new MatrixHelper();
	}
	mtxHelper.initialize();
	
	
});

document.observe("matrix:checkInOutSetExternaly", function(e) {
	syncronizeCalendar();
	_f_set_mtx_s_ChangeMY();
});

document.observe("dom:loaded", function(e) {
	if (window.matrix && !window.mtxHelper) {
		mtxHelper = new MatrixHelper();
		mtxHelper.initialize();
	}
	
	preLoadImages();
});

/**** MATRIX WRAPPER FUNCTIONS ****/

function setMatrixSkin(skinName) {
	window.matrix.setSkin(skinName);
}

function loadCheckInMatrix() {
    var checkIn = document.getElementById("mtx_checkInYear").value + document.getElementById("mtx_checkInMonth").value + document.getElementById("mtx_checkInDate").value;
    var checkOut = document.getElementById("mtx_checkOutYear").value + document.getElementById("mtx_checkOutMonth").value + document.getElementById("mtx_checkOutDate").value;

    matrix.loadCheckInMatrix(checkIn, checkOut);
}

function loadCheckInMatrixMonth(obj) {
	var checkIn = obj.value;
	var checkOut = obj.value;

	var _today = new Date();
	var _cMonth = _today.getMonth() + 1;
	var _cYear = _today.getFullYear();
	if(_cYear<2000) _cYear = _cYear + 1900;
	_cMonth = "0" + _cMonth;
	_cMonth = _cMonth.substring(_cMonth.length - 2, _cMonth.length);
	var checkIn;
	var checkOut;
	var _cDate;
	if(obj.value == (_cYear + "" + _cMonth))
	{
		_cDate = "0" + _cDate;
		_cDate = _cDate.substring(_cDate.length - 2, _cDate.length);
		_cDate = obj.value + "" + _cDate;
	}
	else
	{
		_cDate = obj.value + "01";
	}

	matrix.startDate = _cDate;
	matrix.endDate = incDateStr(matrix.startDate, matrix.days);
	matrix.loadMatrix();  
}

function loadCheckInDestMatrix() {
	loadCheckInMatrix();
}

function foobarbaz() { loadCheckInMatrix(); }

function resetCheckIn() {
	document.getElementById("mtx_loading").style.display = "none";
	matrix.checkIn = "";
	matrix.checkOut = "";
	matrix.reservation = null;
    matrix.loadMatrix();
}

function loadMatrixFrom(startDate) {
	matrix.startDate = startDate;  
    matrix.loadMatrix();
}

function mtx_nextPage() { matrix.nextPage(1); }
function mtx_prevPage() { matrix.prevPage(1); }
function mtx_nextPageJump() { matrix.nextPage(7); }
function mtx_prevPageJump() { matrix.prevPage(7); }

function mtx_gotoPage(pageNum) {
	window.matrix.gotoPage(pageNum);
	gotoMtxTop();
}

function mtx_moveNext() {
	window.matrix.moveNext();
	gotoMtxTop();
}

function mtx_movePrevious() {
	window.matrix.movePrevious();
	gotoMtxTop();
}

function gotoMtxTop() {
	var currentHref = window.location.href;
	window.location.href = currentHref.substr(0, currentHref.lastIndexOf('#')) + '#mtxTop';
}

function selectRatePlan(ratePlanId, ratePlanName, offerId, bookingAdapter, even) { matrix.selectRatePlan(ratePlanId, ratePlanName, offerId, bookingAdapter); }

function toggleRatePlan(ratePlanId, ratePlanName, offerId, bookingAdapter, even) {
	if (matrix.lastRatePlan && matrix.lastRatePlan.id==ratePlanId) {
		closeInfo(ratePlanId);
	} else {
		matrix.selectRatePlan(ratePlanId, ratePlanName, offerId, bookingAdapter);
	}
}

function displayMatrix(data) {
	matrix.displayMatrix(data);
	if ($("ssSearchBtn")) $("ssSearchBtn").disabled = "";
}

function setDisplayCurrencyExternally(currencyCode) {
	var expire = new Date(new Date().getTime() + (24 * 1000 * 60 * 60 * 24));
	setCookie('ccCodePersist', currencyCode, expire);
	matrix.setDisplayCurrencyExternally(currencyCode);
}


/**** USER INTERACTION FUNCTIONS ****/

/**
 *  Actioned when a user clicks a rate checkbox 
 */

function findParentNodeByTagName(obj, name) {
	  var pr = obj.parentNode;
	  while (pr.tagName.toLowerCase() != name) {
		  pr = pr.parentNode;
	  }
	  return pr;
}

function toggleDate(checkbox, dateStr, idx) {
	if (!matrix.reservation) matrix.reservation = new Reservation();
	var changed = matrix.reservation.toggleDate(strToDate(dateStr));
	matrix.setCookie();

  if (!changed) {
	  var xy = getXYpos(checkbox);
      document.getElementById("mtx_errorMsg").innerHTML = "<strong>You may only book consecutive dates.</strong><br />Please ensure that the room you have chosen is available on each night you wish to stay, and check the corresponding boxes for each night. If you wish, you may clear all currently selected dates.";
      
      // extra clear button
      document.getElementById("mtx_errorButton").innerHTML = "<input type='submit' value='Clear' onclick='mtx_clearOtherDates(" + 
	  	"\"" + dateStr + "\"," + idx + ");document.getElementById(\"dealSelectionError\").style.display = \"none\";'>";
      
      // change value for default close button
      $('errMsgCloseBtn').value = 'Keep my selected dates';
    	  
    showDealSelectionErrorAt(xy["y"], xy["x"]);
  } else {
	  mtxHelper.toggleColumn(idx);
  }
 
  return changed;
}

function closeInfo(ratePlanId) {
	matrix.hideRatePlanSelection(ratePlanId);
	var a;
	eval("a = $('" + ratePlanId + "');");
	if(a!=null)
	{
		unHilightRow(a);
	}
	lowLightRow(ratePlanId);
}

function mtx_clearOtherDates(dateStr, idx) {
	matrix.checkIn = "";
	matrix.checkOut = "";
	matrix.reservation.clearNights();
	mtxHelper.clearSelectedColumns();
	mtxHelper.checkCol(idx);
	return toggleDate(null, dateStr, idx);
}



function book(ratePlanId, ratePlanName, rtId, offerId, bookingAdapter) {
	if (!matrix.reservation) {
		matrix.reservation = new Reservation (ratePlanId, ratePlanName, rtId, offerId, matrix.requestedId, matrix.restrictions, bookingAdapter);
	} else {
		matrix.reservation.hotelId = matrix.requestedId;
		matrix.reservation.ratePlanId = ratePlanId;
		matrix.reservation.ratePlanName = ratePlanName;
		matrix.reservation.rtId = rtId;
		matrix.reservation.offerId = offerId;
		matrix.reservation.restrictions = matrix.restrictions;
		matrix.reservation.bookingAdapter = bookingAdapter;
	}

    if (!matrix.reservation.book()) {
    	btn = document.getElementById(matrix.reservation.ratePlanId + "_submit");
        var xy = getXYpos(btn); 
        document.getElementById("mtx_errorMsg").innerHTML = matrix.reservation.errorMsg;
        document.getElementById("mtx_errorButton").innerHTML = '';
        // change value for default close button
        $('errMsgCloseBtn').value = 'Close';
        showDealSelectionErrorAt(xy["y"], xy["x"]); 
    }
    
}  

var tempClassName;

function showRateBlurbField(element, msgField, ev) {
    var incl = document.getElementById(msgField);
    // var xy = getXYpos(element); 
    var xy = getMOUSEpos(ev);
    document.getElementById("mtx_rateBlurbMsg").innerHTML = incl.value;
    showRateBlurbAt(xy["y"], xy["x"]);
}

function showRateBlurb(element, msg) {
    var xy = getXYpos(element); 
    document.getElementById("mtx_rateBlurbMsg").innerHTML = msg;
    showRateBlurbAt(xy["y"], xy["x"]);
}

function showPinkPopup(element, msg, ev) {
    document.getElementById("pink_popup_message").innerHTML = msg;
    showPinkPopupAt(Event.pointerY(ev), Event.pointerX(ev));
}

function hidePinkPopup() {
	document.getElementById('pink_popup').style.display = 'none';
}

function showPinkPopupAt(styleTop, styleLeft) {
  var errorMsg = document.getElementById('pink_popup');
  var padding = 0;
  var windowWidth = document.viewport.getWidth();  
  var objWidth = $("pink_popup").getWidth();
  if (styleLeft+objWidth-padding+15 > windowWidth)
  {
      styleLeft = styleLeft-objWidth-15;
  }
  
  var windowHeight = document.viewport.getHeight();
  var objHeight = $('pink_popup').getHeight();
  var offsetTop = document.viewport.getScrollOffsets().top;
  if ((styleTop+objHeight+15) > (windowHeight+offsetTop)) {
	  styleTop = styleTop-objHeight-15;
  }
  if (styleTop < 0) {
      styleTop = 0;
  }
  
  styleLeft += 15;
  styleTop += 15;

  errorMsg.style.top		= styleTop + 'px';
  errorMsg.style.left		= styleLeft + 'px';
  errorMsg.style.margin		= '0';
  errorMsg.style.display	= 'block';
}

function hideRateBlurb(element) {
	document.getElementById('mtx_rateBlurb').style.display = 'none';
}

function toggleOnRequest(checkbox) {
    matrix.showOnRequest = !checkbox.checked;
    matrix.loadMatrix();  
}


var rateBlurbMessageWidth = 160;

function showRateBlurbAt(styleTop, styleLeft) {
  var errorMsg = document.getElementById('mtx_rateBlurb');
  var padding = 0;
  dealSelectionErrorMessageWidth = $('mtx_rateBlurb').getWidth();
  var windowWidth = document.viewport.getWidth();
  if (styleLeft + dealSelectionErrorMessageWidth+ 15 - padding > windowWidth)
  {
	  styleLeft = styleLeft-dealSelectionErrorMessageWidth-15;
  }
  
  var windowHeight = document.viewport.getHeight();
  var objHeight = $('mtx_rateBlurb').getHeight();
  var offsetTop = document.viewport.getScrollOffsets().top;
  if ((styleTop+objHeight+15) > (windowHeight+offsetTop)) {
	  styleTop = styleTop-objHeight-15;
  }
  if (styleTop < 0) {
	  styleTop = 0;
  }
  
  styleLeft += 15;
  styleTop += 15;

  errorMsg.style.margin		= '0';
  errorMsg.style.top 		= styleTop + 'px';
  errorMsg.style.left		= styleLeft + 'px';
  errorMsg.style.zIndex		= '100';
  errorMsg.style.display	= 'block';
}

var dealSelectionErrorMessageWidth = 230;

function showDealSelectionErrorAt(styleTop, styleLeft) {
  var errorMsg = document.getElementById('dealSelectionError');
  var padding = 20;
  var windowWidth = (document.body) ? document.body.offsetWidth : window.innerWidth;
  if (styleLeft + dealSelectionErrorMessageWidth - padding > windowWidth)
  {
      styleLeft = windowWidth - dealSelectionErrorMessageWidth - padding;
  }
  if (styleTop < 0) {
      styleTop = 0;
  }
  
  styleLeft = (windowWidth/2) - padding;

  errorMsg.style.width = dealSelectionErrorMessageWidth + 'px';
  errorMsg.style.top = styleTop + 'px';
  errorMsg.style.left = styleLeft + 'px';
  errorMsg.style.display = 'block';
  
  // hack to prevent matrix disappear on IE6
  $('outerdiv').style.display = 'none';
  $('outerdiv').style.display = 'block';
}

function hideDealSelectionError() {
	document.getElementById('dealSelectionError').style.display = 'none';
	
	// hack to prevent matrix disappear on IE6
	$('outerdiv').style.display = 'none';
	$('outerdiv').style.display = 'block';
}

function toggleRatePlanBlurb(toggleBtn) {
	var ratePlanBlurb = document.getElementById('ratePlanBlurb');
	
	if (ratePlanBlurb.style.display == "none") {
		toggleBtn.innerHTML = "&#9650;";
		ratePlanBlurb.style.display = "block";
		toggleBtn.title = "Hide offer information";	
	} else {
		toggleBtn.innerHTML = "&#9660;";
		ratePlanBlurb.style.display = "none";
		toggleBtn.title = "Show offer information";
	}
	
}

function setDateSelects(checkIn, checkOut) {
	setSelectedByIndex("mtx_checkInDate", (parseInt(checkIn.substring(6, 8), 10) - 1));
	setSelectedByIndex("mtx_checkInMonth", (parseInt(checkIn.substring(4, 6), 10) - 1));
	setSelectedByValue("mtx_checkInYear", checkIn.substring(0, 4));
	updateCheckAvailAllShort('sDate');
	setSelectedByIndex("mtx_checkOutDate", (parseInt(checkOut.substring(6, 8), 10) - 1));
	setSelectedByIndex("mtx_checkOutMonth", (parseInt(checkOut.substring(4, 6), 10) - 1));
	setSelectedByValue("mtx_checkOutYear", checkOut.substring(0, 4));
	updateCheckAvailAllShort('eDate');
}	

function _f_set_mtx_s_ChangeMY()
{
	if (typeof(matrix) == "undefined") return false;
	if (typeof(matrix.startDate) == "undefined") return false;
	var _cYearMonth = matrix.startDate;
	_cYearMonth = _cYearMonth.substring(0, 6);

	var select = document.getElementById("mtx_s_ChangeMY");
	if(select!=null)
	{
		for (var i = select.options.length - 1; i >= 0; i--) {
			if (select.options[i].value == _cYearMonth) {
				select.selectedIndex = i;
				break;
			}
		}
	}
}

/**** UTILITY FUNCTIONS *****/
  
  /**
   * @purpose            : Get the (x,y) coordinate of a DOM element
   * @param  object elem : a DOM element or null
   * @return object      : an associative array, where indicies "x"
   *                       and "y" hold their respective coordinates
   * @note               : function is recursive
   */
function getXYpos(elem) {
    if (!elem) {
	    return {"x":0,"y":0};
	}
 	var xy={"x":elem.offsetLeft,"y":elem.offsetTop}
    var par=getXYpos(elem.offsetParent);
    for (var key in par) {
        xy[key]+=par[key];
    }

    return xy;
}

 /*
 ******************************************************
 */
 function getScrollXY()
{
  var scrOfX = 0, scrOfY = 0;
  if( typeof( window.pageYOffset ) == 'number' ) {
    //Netscape compliant
    scrOfY = window.pageYOffset;
    scrOfX = window.pageXOffset;
  } else if( document.body && ( document.body.scrollLeft || document.body.scrollTop ) ) {
    //DOM compliant
    scrOfY = document.body.scrollTop;
    scrOfX = document.body.scrollLeft;
  } else if( document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop ) ) {
    //IE6 standards compliant mode
    scrOfY = document.documentElement.scrollTop;
    scrOfX = document.documentElement.scrollLeft;
  }
  return {x:scrOfX, y:scrOfY};
}

function mouseCoords(ev) {
	var oScroll = getScrollXY();
	if (ev.pageX || ev.pageY) {
		return {x:ev.pageX, y:ev.pageY};
	}
	return {
		x:(ev.clientX + document.body.scrollLeft - document.body.clientLeft)+oScroll.x,
		y:(ev.clientY + document.body.scrollTop  - document.body.clientTop)+oScroll.y
	};
}

 function getMOUSEpos(ev)
{
	var mousePos = mouseCoords(ev);
	var xy = new Array();
	xy['x'] = mousePos.x;
	xy['y'] = mousePos.y;
	// alert(mousePos.y);
	return xy;
}
 /*
 ******************************************************
 */        

function highlightRow(tr) {
   var tds = tr.getElementsByTagName('td');
   var total = tds.length;
  
   $(tds[0]).addClassName('expanded_row_left');
   $(tds[total - 1]).addClassName('expanded_row_right');

   for (var i = 0; i < total; i++) {
      if (tds[i].parentNode == tr) {
    	  $(tds[i]).addClassName('expanded_row');
      }
   }
}
function lowLightRow(row_id) {
	   var tds = $(row_id).getElementsByTagName('td');
	   var total = tds.length;
	  
	   $(tds[0]).removeClassName('expanded_row_left');
	   $(tds[total - 1]).removeClassName('expanded_row_right');

	   for (var i = 0; i < total; i++) {
    	  $(tds[i]).removeClassName('expanded_row');
	   }
	
}
   
   
function incDateStr(startDateStr, numDays) {
    var d = strToDate(startDateStr); 
    d.setDate(d.getDate() + numDays);
    return formatDate(d);
}

/* YYYYMMDD */
function formatDate(date) {
    var dateStr = date.getFullYear();
    var m = date.getMonth() + 1;
    dateStr = dateStr + ((m < 10)?"0" + m: "" + m);
    var d = date.getDate();
    dateStr = dateStr + ((d < 10)?"0" + d: "" + d);  
    return dateStr;  
}

/* YYYYMMDD */
function strToDate(dateStr) {
    return new Date(dateStr.substring(0, 4),(parseInt(dateStr.substring(4, 6), 10) - 1), parseInt(dateStr.substring(6, 8), 10))
}

function incrementDate(date, numDays) {
    return new Date(date.getTime() + (numDays * 86400000));
}

function setSelectedByValue(selectId, value) {
	select = document.getElementById(selectId);
	if (select) {
		for (i = select.options.length - 1; i >= 0; i--) {
			if (select.options[i].innerHTML == value) {
				select.selectedIndex = i;
				break;
			}
		}
	}
	return select;
}

function setSelectedByIndex(selectId, index) {
	select = document.getElementById(selectId);
	if (select) select.selectedIndex = index;
	return select;
}

function setSortFields(field) {
	$('sortHotelName').style.fontWeight = 'normal';   	
    $('sortCategory').style.fontWeight = 'normal';
    $('sortHotelName').style.textDecoration = 'underline';
    $('sortCategory').style.textDecoration = 'underline';
    $('arrowHotelName').style.visibility = 'hidden';   	
    $('arrowCategory').style.visibility = 'hidden';
    $('sort' + field).style.fontWeight = 'bold';
    $('sort' + field).style.textDecoration = 'none';
    $('arrow' + field).style.visibility = 'visible';
}

function toggleSort(field, fieldName) {
	var arrowField = $('arrow' + field);
	if (fieldName == matrix.curSortBy) {
		/* Is upsidedown because searchResults.sortDirection is yet to be toggled */
    	if (matrix.sortDirection[fieldName] == 1) {
    		arrowField.update('&darr;');
    	} else {
    		arrowField.update('&uarr;');
    	}
    	
    } else {
    	setSortFields(field);    
    }

}

function doSortBy(field) {
	toggleSort(field, field);
    matrix.sortBy(field);
}
function adjustStars(min, max) {
    for (i = 5; i > 0; i--) {
        minStar = $('min' + i);
        maxStar = $('max' + i);
        
        if  (i > min) {
        	minStar.style.visibility = 'hidden';
        	minStar.style.width = 0;
        } else {
        	minStar.style.width = '11px';
        	minStar.style.visibility = 'visible';
        }
        
        if  (i > max) {
        	maxStar.style.visibility = 'hidden';
        	maxStar.style.width = 0;
        } else {
        	maxStar.style.width = '11px';
        	maxStar.style.visibility = 'visible';
        }
        
    }
}

/**
 * Class for search sliders.
 */
/*
function SearchSliders() {
	if (!$('minCatHandle')) return;
	
	this.searchEnabled = true;
    this.catHandles = ['minCatHandle', 'maxCatHandle'];
    this.catSlider = new Control.MtxSlider(this.catHandles, 'catSlider', {
	    range: $R(1, 5),
	    values: [1,2,3,4,5],
	    sliderValue: [1, 5],
	    spans: ["catSliderSpan"],
	    restricted: true
	});

	// Setting the callbacks later on
	var minCategory = $('minCategory');
	var maxCategory = $('maxCategory');
	  
	this.catSlider.options.onSlide = function(value) {
	  minCategory.update(value[0]);
	  maxCategory.update(value[1]);
	  adjustStars(value[0], value[1]);
	};
	
	this.catSlider.options.onChange = function(value) {
	  doFilter();
	};

}

SearchSliders.prototype.setSearchEnabled = function(value) {
    this.searchEnabled = value;
}

SearchSliders.prototype.setValue = function(minValue, maxValue) {
	var onSlide = this.catSlider.options.onSlide;
	var onChange = this.catSlider.options.onChange;
	this.catSlider.options.onSlide = function() {};
	this.catSlider.options.onChange = function() {};
    this.catSlider.setValue(minValue, 0);
    this.catSlider.setValue(maxValue, 1);
    this.catSlider.options.onSlide = onSlide;
    this.catSlider.options.onChange = onChange;
}
*/

//Copyright (c) 2005 Marty Haught, Thomas Fuchs 
//
// See http://script.aculo.us for more info
// 
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

if(!Control) var Control = {};
Control.MtxSlider = Class.create();

// options:
//  axis: 'vertical', or 'horizontal' (default)
//
// callbacks:
//  onChange(value)
//  onSlide(value)
Control.MtxSlider.prototype = {
  initialize: function(handle, track, options) {
    var slider = this;
    
    if(handle instanceof Array) {
      this.handles = handle.collect( function(e) { return $(e) });
    } else {
      this.handles = [$(handle)];
    }
    
    this.track   = $(track);
    this.options = options || {};

    this.axis      = this.options.axis || 'horizontal';
    this.increment = this.options.increment || 1;
    this.step      = parseInt(this.options.step || '1');
    this.range     = this.options.range || $R(0,1);
    this.value     = 0; // assure backwards compat
    this.values    = this.handles.map( function() { return 0 });
    this.spans     = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false;
    this.options.startSpan = $(this.options.startSpan || null);
    this.options.endSpan   = $(this.options.endSpan || null);

    this.restricted = this.options.restricted || false;

    this.maximum   = this.options.maximum || this.range.end;
    this.minimum   = this.options.minimum || this.range.start;
    // Will be used to align the handle onto the track, if necessary
    this.alignX = parseInt(this.options.alignX || '0');
    this.alignY = parseInt(this.options.alignY || '0');
    
    this.trackLength = this.maximumOffset() - this.minimumOffset();
    this.handleLength = this.isVertical() ? this.handles[0].offsetHeight : this.handles[0].offsetWidth;

    this.active   = false;
    this.dragging = false;
    this.disabled = false;

    if(this.options.disabled) this.setDisabled();

    // Allowed values array
    this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false;
    if(this.allowedValues) {
      this.minimum = this.allowedValues.min();
      this.maximum = this.allowedValues.max();
    }

    this.eventMouseDown = this.startDrag.bindAsEventListener(this);
    this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
    this.eventMouseMove = this.update.bindAsEventListener(this);

    // Initialize handles in reverse (make sure first handle is active)
    this.handles.each( function(h,i) {
      i = slider.handles.length-1-i;
      slider.setValue(parseFloat(
        (slider.options.sliderValue instanceof Array ? 
          slider.options.sliderValue[i] : slider.options.sliderValue) || 
         slider.range.start), i);
      Element.makePositioned(h); // fix IE
      Event.observe(h, "mousedown", slider.eventMouseDown);
    });
    
    Event.observe(this.track, "mousedown", this.eventMouseDown);
    Event.observe(document, "mouseup", this.eventMouseUp);
    Event.observe(document, "mousemove", this.eventMouseMove);
    
    this.initialized = true;
  },
  dispose: function() {
    var slider = this;    
    Event.stopObserving(this.track, "mousedown", this.eventMouseDown);
    Event.stopObserving(document, "mouseup", this.eventMouseUp);
    Event.stopObserving(document, "mousemove", this.eventMouseMove);
    this.handles.each( function(h) {
      Event.stopObserving(h, "mousedown", slider.eventMouseDown);
    });
  },
  setDisabled: function(){
    this.disabled = true;
  },
  setEnabled: function(){
    this.disabled = false;
  },  
  getNearestValue: function(value){
    if(this.allowedValues){
      if(value >= this.allowedValues.max()) return(this.allowedValues.max());
      if(value <= this.allowedValues.min()) return(this.allowedValues.min());
      
      var offset = Math.abs(this.allowedValues[0] - value);
      var newValue = this.allowedValues[0];
      this.allowedValues.each( function(v) {
        var currentOffset = Math.abs(v - value);
        if(currentOffset <= offset){
          newValue = v;
          offset = currentOffset;
        } 
      });
      return newValue;
    }
    if(value > this.range.end) return this.range.end;
    if(value < this.range.start) return this.range.start;
    return value;
  },
  setValue: function(sliderValue, handleIdx){
    if(!this.active) {
      this.activeHandle    = this.handles[handleIdx];
      this.activeHandleIdx = handleIdx;
      this.updateStyles();
    }
    handleIdx = handleIdx || this.activeHandleIdx || 0;
    if(this.initialized && this.restricted) {
      if((handleIdx>0) && (sliderValue<this.values[handleIdx-1]))
        sliderValue = this.values[handleIdx-1];
      if((handleIdx < (this.handles.length-1)) && (sliderValue>this.values[handleIdx+1]))
        sliderValue = this.values[handleIdx+1];
    }
    sliderValue = this.getNearestValue(sliderValue);
    this.values[handleIdx] = sliderValue;
    this.value = this.values[0]; // assure backwards compat
    
    this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = 
      this.translateToPx(sliderValue, handleIdx);
    
    this.drawSpans();
    if(!this.dragging || !this.event) this.updateFinished();
  },
  setValueBy: function(delta, handleIdx) {
    this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, 
      handleIdx || this.activeHandleIdx || 0);
  },
  translateToPx: function(value, handleIdx) {
    // Hack GR to allow two sliders show the same value without overlapping
    if (this.handles.length == 2 && handleIdx != null) {
      var offset = (value - this.range.start) / (this.range.end-this.range.start) * (this.trackLength - 2 * this.handleLength);
	  if (handleIdx > 0) {
	    return Math.round(offset + this.handleLength) + 'px';
	  }
	  else {
	    return Math.round(offset) + 'px';
	  }
	}
    else {
      return Math.round(
      ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * 
      (value - this.range.start)) + "px";
    }
  },
  translateToValue: function(offset) {
    // Hack GR to allow two sliders show the same value without overlapping
    var percent = 0;
    if (this.handles.length == 2) {
	  if (this.activeHandleIdx > 0) {
	  	percent = (offset - 1.5 * this.handleLength)/(this.trackLength - 2 * this.handleLength)
	  }
	  else {
    	percent = (offset + 0.5 * this.handleLength)/(this.trackLength - 2 * this.handleLength)
	  }
	  var value = percent * (this.range.end-this.range.start) + this.range.start; 
	  if (value < this.range.start) {
	    value = this.range.start;
	  }
	  else if (value > this.range.end) {
	    value = this.range.end;
	  }
	  return value;
	}
    else {
      return ((offset/(this.trackLength-this.handleLength) * 
        (this.range.end-this.range.start)) + this.range.start);
    }
  },
  getRange: function(range) {
    var v = this.values.sortBy(Prototype.K); 
    range = range || 0;
    return $R(v[range],v[range+1]);
  },
  minimumOffset: function(){
    return(this.isVertical() ? this.alignY : this.alignX);
  },
  maximumOffset: function(){
    return(this.isVertical() ?
      this.track.offsetHeight - this.alignY : this.track.offsetWidth - this.alignX);
  },  
  isVertical:  function(){
    return (this.axis == 'vertical');
  },
  drawSpans: function() {
    var slider = this;
    if(this.spans)
      $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) });
    if(this.options.startSpan)
      this.setSpan(this.options.startSpan,
        $R(0, this.values.length>1 ? this.getRange(0).min() : this.value ));
    if(this.options.endSpan)
      this.setSpan(this.options.endSpan, 
        $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum));
  },
  setSpan: function(span, range) {
    if(this.isVertical()) {
      span.style.top = this.translateToPx(range.start, null);
      span.style.height = this.translateToPx(range.end - range.start + this.range.start, null);
    } else {
      span.style.left = this.translateToPx(range.start, null);
      span.style.width = this.translateToPx(range.end - range.start + this.range.start, null);
    }
  },
  updateStyles: function() {
    this.handles.each( function(h){ Element.removeClassName(h, 'selected') });
    Element.addClassName(this.activeHandle, 'selected');
  },
  startDrag: function(event) {
    if(Event.isLeftClick(event)) {
      if(!this.disabled){
        this.active = true;
        
        var handle = Event.element(event);
        var pointer  = [Event.pointerX(event), Event.pointerY(event)];
        if(handle==this.track) {
          var offsets  = Position.cumulativeOffset(this.track); 
          this.event = event;
          this.setValue(this.translateToValue( 
           (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2)
          ));
          var offsets  = Position.cumulativeOffset(this.activeHandle);
          this.offsetX = (pointer[0] - offsets[0]);
          this.offsetY = (pointer[1] - offsets[1]);
        } else {
          // find the handle (prevents issues with Safari)
          while((this.handles.indexOf(handle) == -1) && handle.parentNode) 
            handle = handle.parentNode;
          this.activeHandle    = handle;
          this.activeHandleIdx = this.handles.indexOf(this.activeHandle);
          this.updateStyles();
          var offsets  = Position.cumulativeOffset(this.activeHandle);
          this.offsetX = (pointer[0] - offsets[0]);
          this.offsetY = (pointer[1] - offsets[1]);
        }
      }
      Event.stop(event);
    }
  },
  update: function(event) {
   if(this.active) {
      if(!this.dragging) this.dragging = true;
      this.draw(event);
      // fix AppleWebKit rendering
      if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
      Event.stop(event);
   }
  },
  draw: function(event) {
    var pointer = [Event.pointerX(event), Event.pointerY(event)];
    var offsets = Position.cumulativeOffset(this.track);
    pointer[0] -= this.offsetX + offsets[0];
    pointer[1] -= this.offsetY + offsets[1];
    this.event = event;
    this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] ));
    if(this.initialized && this.options.onSlide)
      this.options.onSlide(this.values.length>1 ? this.values : this.value, this);
  },
  endDrag: function(event) {
    if(this.active && this.dragging) {
      this.finishDrag(event, true);
      Event.stop(event);
    }
    this.active = false;
    this.dragging = false;
  },  
  finishDrag: function(event, success) {
    this.active = false;
    this.dragging = false;
    this.updateFinished();
  },
  updateFinished: function() {
    if(this.initialized && this.options.onChange) 
      this.options.onChange(this.values.length>1 ? this.values : this.value, this);
    this.event = null;
  }
}
function toggleSubSortPanel() {
	if ($('searchPanel').style.display == "none") {
		$('searchPanel').style.display = "block";
		$('subsortBtn').value = "Hide hotel preferences";
		if (typeof(searchSliders)=="undefined") searchSliders = new SearchSliders();
	} else {
		$('searchPanel').style.display = "none";
		$('subsortBtn').value="Show hotel preferences";
	}
}
function doFilter() {
	window.matrix.doFilter();
	if (isFilterOn()) {
		$('showAll').style.visibility = "";
	} else {
		$('showAll').style.visibility = "hidden";
	}
}

function isFilterOn() {
	if ($("restaurant").checked || $("kitchenette").checked || $("pool").checked || $("fitnessCentre").checked || $("broadbandInternet").checked ||$("satelliteCableTV").checked) {
		return true;
	}
	if ($('minCategory').innerHTML!="1" || $('maxCategory').innerHTML!="5") {
		return true;
	}
	for (i=0; i<window.matrix.data.accomList.length; i++) {
    	if ($("mtx_fltr_accom_"+i).checked) return true;
    }
}

function resetFilter() {
	if (typeof(searchSliders) != "undefined") {
		searchSliders.setSearchEnabled(false);
		searchSliders.catSlider.setValue(5, 1);
	    searchSliders.catSlider.setValue(1, 0);
	    $('minCategory').update(1);
	    $('maxCategory').update(5);
	    adjustStars(1,5);
	    searchSliders.setSearchEnabled(true);
	}
	$("restaurant").checked = false;
    $("kitchenette").checked = false;
    $("pool").checked = false;
    $("fitnessCentre").checked = false;
    $("broadbandInternet").checked = false;
    $("satelliteCableTV").checked = false;
    for (i=0; i<window.matrix.data.accomList.length; i++) {
    	$("mtx_fltr_accom_"+i).checked = false;
    }
   	window.matrix.doFilter();
   	$('showAll').style.visibility = "hidden";
}

function replaceImage(image, imagePath) {
	if (!imagePath) {
		image.src = "http://rates.asiawebdirect.com/asahi/images/space.gif";
		} else {
		image.src = imagePath;
	}
} 

function MatrixFilter() {
	this.showFilterPanel = false;
	this.minCat = 1;
	this.maxCat = 5;
	this.restaurant = false;
    this.kitchenette = false;
    this.pool = false;
    this.fitnessCentre = false;
    this.broadbandInternet = false;
    this.satelliteCableTV = false;
    this.accommodation = new Array();
    
    // sort field
    this.sort_field = "Popular";
    this.sort_direction = 1;
}
    
MatrixFilter.prototype.KeepCurrent = function() {
	if (!$('div_mtx_filter')) return;
	this.minCat = $('minCategory').innerHTML;
	this.maxCat = $('maxCategory').innerHTML;
	this.restaurant = $("restaurant").checked
    this.kitchenette = $("kitchenette").checked;
    this.pool = $("pool").checked;
    this.fitnessCentre = $("fitnessCentre").checked;
    this.broadbandInternet = $("broadbandInternet").checked;
    this.satelliteCableTV = $("satelliteCableTV").checked;
    this.accommodation = new Array();
    for (i=0; i<window.matrix.accomList.length; i++) {
    	if ($("mtx_fltr_accom_"+i).checked) this.accommodation.push(window.matrix.accomList[i]);
    }
    this.showFilterPanel = true;
    if ($('searchPanel').style.display == "none") this.showFilterPanel = false
    this.sort_field = window.matrix.curSortBy;
    this.sort_direction = window.matrix.sortDirection[window.matrix.curSortBy];
}
    
MatrixFilter.prototype.Restore = function() {
	if (!$('div_mtx_filter')) return;
	$('searchPanel').style.display = "block";
	$('subsortBtn').value = "Hide hotel preferences";
	$("restaurant").checked = this.restaurant; 
	$("kitchenette").checked = this.kitchenette;
	$("pool").checked = this.pool;
	$("fitnessCentre").checked = this.fitnessCentre;
	$("broadbandInternet").checked = this.broadbandInternet;
	$("satelliteCableTV").checked = this.satelliteCableTV;
    $('minCategory').update(this.minCat);
    $('maxCategory').update(this.maxCat);
    adjustStars(this.minCat,this.maxCat);
    
    if (window.matrix.data) {
    	if (window.matrix.data.accomList) {
	    	for (var i=0; i<window.matrix.data.accomList.length; i++) {
	        	for (var j = 0; j < this.accommodation.length; j++) {
	        		if (window.matrix.data.accomList[i] == this.accommodation[j]) $("mtx_fltr_accom_"+i).checked = true;
	        	}
		    }
    	}
    }

	if (isFilterOn()) {
		$('showAll').style.visibility = "";
		//window.matrix.doFilter();
	} else {
		$('showAll').style.visibility = "hidden";
	}
	
    $('mtx_loading').style.display = "none";
    searchSliders = null;
	searchSliders = new SearchSliders();
	searchSliders.setSearchEnabled(false);
	searchSliders.setValue(this.minCat, this.maxCat);
    searchSliders.setSearchEnabled(true);
    if (this.showFilterPanel) {
    	$('subsortBtn').value = "Hide hotel preferences";
    } else {
    	$('searchPanel').style.display = "none";
    	$('subsortBtn').value = "Show hotel preferences";
    }
    
    // sorting
    if (this.sort_field!="Popular") {
    	//if (this.sort_field == window.matrix.curSortBy) this.sort_direction *= -1;
    	window.matrix.sortDirection[this.sort_field] = this.sort_direction;
    	//doSortBy(this.sort_field);
    	var arrowField = $('arrow' + this.sort_field);
    	if (matrix.sortDirection[this.sort_field] != 1) {
    		arrowField.update('&darr;');
    	} else {
    		arrowField.update('&uarr;');
    	}
    	arrowField.style.visibility = "visible";
    }
}

MatrixFilter.prototype.Reset = function() {
	if (typeof(searchSliders) != "undefined") {
		searchSliders.setSearchEnabled(false);
		searchSliders.setValue(1, 5);
	    $('minCategory').update(1);
	    $('maxCategory').update(5);
	    adjustStars(1,5);
	    searchSliders.setSearchEnabled(true);
	}
	$("restaurant").checked = false;
    $("kitchenette").checked = false;
    $("pool").checked = false;
    $("fitnessCentre").checked = false;
    $("broadbandInternet").checked = false;
    $("satelliteCableTV").checked = false;
    for (i=0; i<window.matrix.data.accomList.length; i++) {
    	$("mtx_fltr_accom_"+i).checked = false;
    }
   	$('showAll').style.visibility = "hidden";
    window.matrix.doFilter();
}

function hilightRow(oRow) {
	oRow.className = oRow.className + ' hover';
}

function unHilightRow(oRow) {
	oRow.className = oRow.className.replace(' hover', '');
	oRow.className = oRow.className.replace(' hover', '');
	oRow.className = oRow.className.replace(' hover', '');
}

function getCookie(name) {
	var dcookie = document.cookie;
	var cname = name + "=";
	var clen = dcookie.length;
	var cbegin = 0;
	while (cbegin < clen) {
		var vbegin = cbegin + cname.length;
		if (dcookie.substring(cbegin, vbegin) == cname) {
			var vend = dcookie.indexOf(";", vbegin);
			if (vend == -1)
				vend = clen;
			return unescape(dcookie.substring(vbegin, vend));
		}
		cbegin = dcookie.indexOf(" ", cbegin) + 1;
		if (cbegin == 0)
			break;
	}
	return null;
}

function setCookie(name, value, expires) {
	if (!expires)
		expires = new Date();
	document.cookie = name + "=" + escape(value) + "; expires="
			+ expires.toGMTString() + "; path=/";
}

function delCookie(name) {
	var expireNow = new Date();
	document.cookie = name + "=" + "; expires=Thu, 01-Jan-70 00:00:01 GMT"
			+ "; path=/";
}

function preLoadImages() {
	var preFix = 'http://rates.asiawebdirect.com/asahi/images/';
	var imagesArray = new Array('book.png', 'book-over.png', 'bg_selecteddatetip.gif', 'next-7-yellow.png', 'previous-7-yellow.png', 'request.png', 'request-over.png');
	for (var i=0; i<imagesArray.length; i++) {
		var img = new Image();
		img.src = preFix + imagesArray[i];
	}
}

function addComma(nStr) {
	  nStr += '';
	  x = nStr.split('.');
	  x1 = x[0];
	  x2 = x.length > 1 ? '.' + x[1] : '';
	  var rgx = /(\d+)(\d{3})/;
	  while (rgx.test(x1)) {
	    x1 = x1.replace(rgx, '$1' + ',' + '$2');
	  }
	  return x1 + x2;
}


function lookupMonth(number) {
	var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
	return months[number];
}

;
//Simple JavaScript Templating
//John Resig - http://ejohn.org/ - MIT Licensed
(function(){	
  var cache = {};
 
  this.tmpl = function tmpl(str, data){
      str = document.getElementById(str).value;
      str = '/*st*/\'' + str + '\'/*en*/';	  
      var functionBody = "var p=[],print=function(){p.push.apply(p,arguments);};" +
      
      // Introduce the data as local variables using with(){}
      "with(obj){p.push(" +
        
      // Convert the template into pure JavaScript

      str
        .replace(/[\r\t\n]/g, " ")
        .split("<%").join("\t")
        .replace(/\t=(.*?)%>/g, "'/*en*/,$1,/*st*/'")
        .split("\t").join("'/*en*/);")
        .split("%>").join("p.push(/*st*/'")
        .replace(/\/\*st\*\/'(.*?)'\/\*en\*\//g, function (match, d) {
        	return "'" + d.replace(/'/g, '\\\'') + "'";
        })
        
      + ");}return p.join('');";
      
      var fn = new Function("obj",functionBody);

      return data ? fn( data ) : fn;
  };
})();

(function(){	
	  var cache = {};
	 
	  this.tmpl_str = function tmpl_str(str, data){
		  
	      str = '/*st*/\'' + str + '\'/*en*/';	  
	      var functionBody = "var p=[],print=function(){p.push.apply(p,arguments);};" +
	      
	      // Introduce the data as local variables using with(){}
	      "with(obj){p.push(" +
	        
	      // Convert the template into pure JavaScript

	      str
	        .replace(/[\r\t\n]/g, " ")
	        .split("<%").join("\t")
	        .replace(/\t=(.*?)%>/g, "'/*en*/,$1,/*st*/'")
	        .split("\t").join("'/*en*/);")
	        .split("%>").join("p.push(/*st*/'")
	        .replace(/\/\*st\*\/'(.*?)'\/\*en\*\//g, function (match, d) {
	        	return "'" + d.replace(/'/g, '\\\'') + "'";
	        })
	        
	      + ");}return p.join('');";
	      
	      var fn = new Function("obj",functionBody);

	      return data ? fn( data ) : fn;
	  };
	})();
;
function Currency(isoCode, symbol, name, shortName, relativeRate) {
    this.isoCode      = isoCode;
    this.symbol       = symbol;
    this.name         = name;
    this.shortName    = shortName;
    this.relativeRate = relativeRate;
};

function setCurrency(select) {
	if (!window.allCurrencies) {
		extractCurrencies(select);
    }
	var newCurrency = select.value.split('|')[0];
	currencyConverter.convert(window.allCurrencies, newCurrency);
	document.fire("matrix:currencyChanged", newCurrency);
}

function extractCurrencies(select) {
	window.allCurrencies = {};
	for (var i = 0; i < select.options.length; i++) {
		var values = select.options[i].value.split('|');
		var code = values[0];
		var rate = values[1];
		var symbol = values[2];
		var name = select.options[i].textContent;
		
		window.allCurrencies[code] = new Currency(code, symbol, name, name, rate);
	}	
}

/**
 * A 'class' representing generic currency conversion functionality for deal matrices.
 *
 * Follows a convention based approach for identifying cells that require conversion.
 * Rather than a single synchronous conversion, the approach taken is to split the work required up into
 * logical sections (known henceforth as 'deal blocks') and returning control to the browser momentarily between
 * deal block conversions.
 *
 * The convention is as follows:
 *
 *           _________________________________________________________
 *       ___|______________________________________________________   |
 *   ___|_______________________________________________________   |  |
 *  |                                                           |  |  |
 *  | div: id=currencyGroup                                     |  |  |
 *  |      name=currencyGroup                                   |  |  |
 *  |      isoCode=CODE                                         |  |  |
 *  |      index=indexNumber                                    |  |  |
 *  |                                                           |  |  |
 *  |    ____________________________                           |  |  |
 *  |   | div: name=dealBlock        |                          |  |  |
 *  |   |                            |                          |  |  |
 *  |   | span, name=drc             |                          |  |  |
 *  |   | span, name=drc             |                          |  |  |
 *  |   | span, name=drc             |                          |  |  |
 *  |   |                            |                          |  |  |
 *  |   |____________________________|                          |  |  |
 *  |    ____________________________                           |  |  |
 *  |   | div: name=dealBlock        |                          |  |  |
 *  |   |                            |                          |  |  |
 *  |   | span, name=drc             |                          |  |  |
 *  |   | span, name=drc             |                          |  |  |
 *  |   | span, name=drc             |                          |  |  |
 *  |   |                            |                          |  |__|
 *  |   |____________________________|                          |__|
 *  |___________________________________________________________|
 *
 *
 * Blocks that relate to the same currency are encapsulated in DIV elements with an ID of 'currencyGroup'
 * and a name of 'currencyGroup'. Cells within a 'currencyGroup' are further subdivided into logical units known
 * as 'deal blocks'. These are denoted by DIV elements with a name of 'dealBlock'. Each 'deal block' is processed
 * synchronously. After processing a deal block, the next block is scheduled for processing at a later stage
 * (denoted by the TIME_BETWEEN_DEAL_BLOCKS parameter defined below). This approach is taken so that control can be
 * returned to the browser between conversions, allowing continual response to the user for large pages.
 *
 * Each rate cell within a deal block is expected to contain semi-structured data:
 *
 *   ---> <span name="drc">[currencySymbol]RATE</span>
 *  (the currencySymbol is optional, but cannot contain digits).
 *
 * To provide further flexibility, users of this class can schedule callbacks for various phases in the lifecycle:
 *
 * before any conversions take place: addPreConversionCallback(function() { ... } );
 *
 * before each currency group: addPreCurrencyGroupCallback(function(...) { ... } );
 *
 * after each currency group: addPostCurrencyGroupCallback(function(...) { ... } );
 *
 * before performing cell conversions on each deal block: addPreDealBlockCallback(function(...) { ... } );
 *
 * after performing cell conversions on each deal block: addPostDealBlockCallback(function(...) { ... } );
 *
 * after entire conversion: addPostConversionCallback(function() { ... } );
 *
 * These callbacks can be useful in performing various random tasks (i.e. updating messages pertaining to currency
 * codes).
 *
 */
function CurrencyConverter() {
	this.preConversionCallbacks     = new Array();
    this.postConversionCallbacks    = new Array();
    this.preCurrencyGroupCallbacks  = new Array();
    this.postCurrencyGroupCallbacks = new Array();
    this.preDealBlockCallbacks      = new Array();
    this.postDealBlockCallbacks     = new Array();
    
    this.currentTimeout = null;
    this.convertIsoCode = false;
};

// DEFINE 'CLASS' level constants.
CurrencyConverter.prototype.DEAL_RATE_REGEX           = /name="?drc?"?>([\d,]+)<[^>]+>([\d\.]+)(?::)?(\w{3})?<\/\S+>\s*([^<]*)?<\/[Ss]/g;
CurrencyConverter.prototype.DEAL_RATE_SYMBOL_REGEX    = /name="?ccs"?>(\S*)<\/span/ig;
CurrencyConverter.prototype.TIME_BETWEEN_DEAL_BLOCKS  = 20;
CurrencyConverter.prototype.CONVERSION_TYPE_SINGLE    = 1;
CurrencyConverter.prototype.CONVERSION_TYPE_MULTI     = 2;
CurrencyConverter.prototype.CURRENCY_CODE_ATTR        = 'isoCode';
CurrencyConverter.prototype.CURRENCY_GROUP_NAME       = 'currencyGroup';
CurrencyConverter.prototype.DEAL_BLOCK_NAME           = 'dealBlock';
CurrencyConverter.prototype.CURRENCY_COOKIE           = 'ccCodePersist';
CurrencyConverter.prototype.COOKIE_EXPIRY             = 90;

/**
 * Specify that the given function should be called once before any conversions take place.
 *    ---> callBack(currencyConverter);
 *    
 * currencyConverter --> this CurrencyConverter instance
 * 
 */
CurrencyConverter.prototype.addPreConversionCallback = function(cb) {
	this.preConversionCallbacks.push(cb);
};

/**
 * Specify that the given function should be called when all conversions are complete.
 */
CurrencyConverter.prototype.addPostConversionCallback = function(cb) {
    this.postConversionCallbacks.push(cb);
};

/**
 * Specify that the given function should be called before applying conversions to a currencyGroup DIV.
 *    --> callBack(divElement, fromCurrency, toCurrency, conversionType);
 *
 * divElement     --> the 'currencyGroup' element
 * fromCurrency   --> a Currency object representing the default currency for the group
 * toCurrency     --> a Currency object representing the indicative currency for the group
 * conversionType --> The convserion type
 *                ------> CONVERSION_TYPE_SINGLE (only displaying one currency, i.e. turning off display, or default == indicative)
 *                ------> CONVERSION_TYPE_MULTI  (displaying two currencies in the cell, implies default != indicative)
 */
CurrencyConverter.prototype.addPreCurrencyGroupCallback = function(cb) {
    this.preCurrencyGroupCallbacks.push(cb);
};

/**
 * Specify that the given function should be called after applying conversions to a currencyGroup DIV.
 *    --> callBack(divElement, fromCurrency, toCurrency, conversionType);
 *
 * divElement     --> the 'currencyGroup' element
 * fromCurrency   --> a Currency object representing the default currency for the group
 * toCurrency     --> a Currency object representing the indicative currency for the group
 * conversionType --> The convserion type
 *                ------> CONVERSION_TYPE_SINGLE (only displaying one currency, i.e. turning off display, or default == indicative)
 *                ------> CONVERSION_TYPE_MULTI  (displaying two currencies in the cell, implies default != indicative)
 */
CurrencyConverter.prototype.addPostCurrencyGroupCallback = function(cb) {
    this.preCurrencyGroupCallbacks.push(cb);
};


/**
 * Specify that the given function should be called before applying conversions to a deal block DIV.
 *    --> callBack(divElement, fromCurrency, toCurrency, conversionType);
 *
 * divElement     --> the 'dealBlock' element
 * fromCurrency   --> a Currency object representing the default currency for the current currency group
 * toCurrency     --> a Currency object representing the indicative currency
 * conversionType --> The convserion type
 *                ------> CONVERSION_TYPE_SINGLE (only displaying one currency, i.e. turning off display, or default == indicative)
 *                ------> CONVERSION_TYPE_MULTI  (displaying two currencies in the cell, implies default != indicative)
 */
CurrencyConverter.prototype.addPreDealBlockCallback = function(cb) {
    this.preDealBlockCallbacks.push(cb);
};

/**
 * Specify that the given function should be called after applying conversions to a deal block DIV.
 *    --> callBack(divElement, fromCurrency, toCurrency, conversionType);
 *
 * divElement     --> the 'dealBlock' element
 * fromCurrency   --> a Currency object representing the default currency for the current currency group
 * toCurrency     --> a Currency object representing the indicative currency
 * conversionType --> The convserion type
 *                ------> CONVERSION_TYPE_SINGLE (only displaying one currency, i.e. turning off display, or default == indicative)
 *                ------> CONVERSION_TYPE_MULTI  (displaying two currencies in the cell, implies default != indicative)
 */
CurrencyConverter.prototype.addPostDealBlockCallback = function(cb) {
    this.postDealBlockCallbacks.push(cb);
};

/**
 * Perform a currency conversion:
 *
 * currencies is a mapping of isoCode --> Currency objects.
 *
 * indicativeCurrency is the ISO code of the currency to convert to.
 */
CurrencyConverter.prototype.convert = function(currencies, indicativeCurrency) {
	this.setCookie(CurrencyConverter.prototype.CURRENCY_COOKIE, indicativeCurrency, CurrencyConverter.prototype.COOKIE_EXPIRY);
    if (this.currentTimeout != null) {
        window.clearTimeout(this.currentTimeout);
    }
    var scopedThis          = this;
    this.turningOff         = false;
    this.longRatePresent    = false;
    this.currencies         = new CloneCurrencyList(currencies);
    this.indicativeCurrency = this.currencies[new String(indicativeCurrency)];
    this.currencyGroups     = this.findCurrencyGroups();
    this.currencyGroupNum   = 0;
    this.fireCallbacks(this, this.preConversionCallbacks);
    this.currentTimeout = window.setTimeout(function () { scopedThis.convertCurrencyGroup(); }, 1);
};

/**
 * Turn off any conversions that are currently applied.
 */
CurrencyConverter.prototype.turnOff = function() {
    if (this.currentTimeout != null) {
        window.clearTimeout(this.currentTimeout);
    }
    var scopedThis          = this;
    this.longRatePresent    = false;
    this.turningOff         = true;
    this.indicativeCurrency = null;
    this.currencyGroups     = this.findCurrencyGroups();
    this.currencyGroupNum   = 0;
    if(this.currencies) {
        /* Dont need to turn off in this case as nothing was turned on */
        this.currentTimeout = window.setTimeout(function () { scopedThis.convertCurrencyGroup(); }, 1);
    }
};

/**
 * Internal function for converting a currency group.
 */
CurrencyConverter.prototype.convertCurrencyGroup = function() {
    if (this.currencyGroupNum < this.currencyGroups.length) {
        var scopedThis       = this;
        var currencyGroup    = this.currencyGroups.item(this.currencyGroupNum++);
        this.currencyGroup   = currencyGroup;
        this.defaultCurrency = this.currencies[currencyGroup.getAttribute(this.CURRENCY_CODE_ATTR)];
        this.conversionType  = this.determineConversionType();
        this.conversionFunc  = this.determineConversionFunc();
        this.dealBlocks      = this.findDealBlocks(currencyGroup);
        this.dealBlockNum    = 0;
        this.fireCallbacks(currencyGroup, this.preCurrencyGroupCallbacks);
        this.currentTimeout = window.setTimeout(function() { scopedThis.convertDealBlock(); }, 1);
    } else {
        for (var callbackIndex = 0; callbackIndex < this.postConversionCallbacks.length; callbackIndex++) {
            this.postConversionCallbacks[callbackIndex]();
        }
    }
};

/**
 * Internal function for converting a deal block.
 */
CurrencyConverter.prototype.convertDealBlock = function() {
    var scopedThis = this;
    if (this.dealBlockNum < this.dealBlocks.length) {
        // change this deal block and schedule the next one
        var dealBlock = this.dealBlocks[this.dealBlockNum++];
        this.fireCallbacks(dealBlock, this.preDealBlockCallbacks);
        dealBlock.innerHTML = dealBlock.innerHTML.replace(this.DEAL_RATE_REGEX, function (match, displayRate, origRate, origIsoCode, isoCode) {
            return scopedThis.conversionFunc(match, displayRate, origRate, origIsoCode, isoCode);
        });
        
        dealBlock.innerHTML = dealBlock.innerHTML.replace(this.DEAL_RATE_SYMBOL_REGEX, function (match, symbol) {
            return 'name="ccs">' + scopedThis.indicativeCurrency.symbol + '</span';
        });
        
        
        this.fireCallbacks(dealBlock, this.postDealBlockCallbacks);

        this.currentTimeout = window.setTimeout(function() { scopedThis.convertDealBlock(); }, this.TIME_BETWEEN_DEAL_BLOCKS);
    } else {
        // next currency block
        this.fireCallbacks(this.currencyGroup, this.postCurrencyGroupCallbacks);
        this.currentTimeout = window.setTimeout(function() { scopedThis.convertCurrencyGroup(); }, 1);
    }
};

/**
 * Rate cell conversion function for displaying a single rate.
 */
CurrencyConverter.prototype.showOneCurrency = function(match, displayRate, origRate, origIsoCode, isoCode) {
	if (origIsoCode==undefined || origIsoCode=='') {
		var amountInt = convertCurrency(origRate, this.defaultCurrency.relativeRate, this.indicativeCurrency.relativeRate);
	} else {
		var amountInt = convertCurrency(origRate, this.currencies[origIsoCode].relativeRate, this.indicativeCurrency.relativeRate);
	}
	
	var txt = 'name="drc">' + addCommas(amountInt) + '<span class="or">' + origRate;
	if (origIsoCode!=undefined && origIsoCode!='') {
		txt += ':' + origIsoCode;
	}

	if (isoCode == undefined || isoCode == '') {
		txt += '</span></s';
	} else {
		txt += '</span> ' + this.indicativeCurrency.isoCode + '</s';
	}
	return txt;
};

/**
 * Rate cell conversion function for displaying the indicative rate as well as the default rate
 */
CurrencyConverter.prototype.showBothCurrencies = function(match, symbol, rate) {
    var indicativeSymbol = symbol == '' ? '' : this.indicativeCurrency.shortName;
    var amountInt = convertCurrency(rate, this.defaultCurrency.relativeRate, this.indicativeCurrency.relativeRate);
    if (rate.length + symbol.length >= 5 || amountInt.length + indicativeSymbol.length >=5) {
        this.longRatePresent = true;
    }
    var klass = "cc";
    if (amountInt.length >= 7) {
      klass = "ccs1";
    }
    if (amountInt.length >= 10) {
      klass = "ccs2";
    }
    return 'name="drc">' + symbol + rate + '<br/><font class="' + klass + '">' + indicativeSymbol + amountInt + '</font></s';
};

/**
 * Internal function for determining what type of conversion is being performed currently:
 * - single, or
 * - multi
 */
CurrencyConverter.prototype.determineConversionType = function() {
    //if (this.turningOff || (this.indicativeCurrency.isoCode == this.defaultCurrency.isoCode)) {
	return this.CONVERSION_TYPE_SINGLE;
    //}
    //return this.CONVERSION_TYPE_MULTI;
};

/**
 * Internal function for determining which function to use for converting deal cells.
 */
CurrencyConverter.prototype.determineConversionFunc = function() {
    if (this.conversionType == this.CONVERSION_TYPE_SINGLE) {
        return this.showOneCurrency;
    } else {
    	return this.showBothCurrencies;
    }
};

/**
 * Internal function for finding all currency groups.
 */
CurrencyConverter.prototype.findCurrencyGroups = function() {
    return document.getElementsByName(this.CURRENCY_GROUP_NAME);
};

/**
 * Internal function for finding all deal blocks inside a currency group.
 */
CurrencyConverter.prototype.findDealBlocks = function(currencyGroup) {
    return document.getElementsByName("dealBlock");
    /*var divs = currencyGroup.getElementsByTagName("table");
    var dealBlocks = new Array();
    for (var divNum = 0; divNum < divs.length; divNum++) {
        var div = divs.item(divNum);
        if (div.getAttribute('name') == this.DEAL_BLOCK_NAME) {
            dealBlocks.push(div);
        }
    }
    return dealBlocks;*/
};

/**
 * Internal function for calling all callbacks for a div based on the given callback array.
 */
CurrencyConverter.prototype.fireCallbacks = function(divElement, callbackArray) {
    for (var callbackIndex = 0; callbackIndex < callbackArray.length; callbackIndex++) {
        callbackArray[callbackIndex](divElement, this.defaultCurrency, this.indicativeCurrency, this.conversionType);
    }
};

/**
 * Get the value for the cookie with the given name, or null if it doesn't exist
 */
CurrencyConverter.prototype.getCookie = function(name) {
	var dc     = document.cookie;
	var prefix = name + "=";
	var begin  = dc.indexOf("; " + prefix);
	if (begin == -1) {
        begin = dc.indexOf(prefix);
	    if (begin != 0) {
	    	return null;
	    }
	} else {
	    begin += 2;
	}
	var end = document.cookie.indexOf(";", begin);
	if (end == -1) {
        end = dc.length;
	}
	return unescape(dc.substring(begin + prefix.length, end));
}

/**
 * Set a session cookie with the given name to the given value
 */
CurrencyConverter.prototype.setCookie = function(cookieName, cookieValue, expireDays) {
	var expiry = new Date(new Date().getTime() + (expireDays * 1000 * 60 * 60 * 24)).toGMTString()
	document.cookie = cookieName + "=" + cookieValue + ";" + "expires=" + expiry + ";path=" + "/" ;
}


/**
 * Switch the css classes for all 'elementName' elements under 'rootElement' that have a
 * className of 'fromClass' to 'toClass'.
 */
function switchClasses(rootElement, elementName, fromClass, toClass) {
    var childNodes = rootElement.getElementsByTagName(elementName);
    for (var childIndex = 0; childIndex < childNodes.length; childIndex++) {
        var childNode = childNodes.item(childIndex);
        if (childNode.className == fromClass) {
            childNode.className = toClass;
        }
    }
}

function CloneCurrencyList(source) {
    for (var field in source) {
        var c = source[field];
        this[new String(field)] = new Currency(
                new String(c.isoCode), new String(c.symbol), new String(c.name), new String(c.shortName), parseFloat(c.relativeRate));
    }
}

function convertCurrency(amount, fromRate, toRate) {
    if (amount == "n/a") { amount; }
    return new String(Math.ceil((parseInt(amount.replace(',', '')) / toRate) * fromRate));
}

function addCommas(nStr) {
    nStr += '';
    var x = nStr.split('.');
    var x1 = x[0];
    var x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
        x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }
    return x1 + x2;
}

function findCurrencySelect() {
	var dropDowns = document.getElementsByTagName("SELECT");
    for (var ddIdx = 0; ddIdx < dropDowns.length; ddIdx++) {
    	var dd = dropDowns.item(ddIdx);
    	if (dd.getAttribute('name') == 'ccSelect') return dd;
    }
    return null;
}

window.currencyConverter = new CurrencyConverter();

// update currency drop-downs
window.currencyConverter.addPostDealBlockCallback(function (dealBlock, from, to) {
	var targetCode = to.isoCode;
    var dropDowns = dealBlock.getElementsByTagName("SELECT");
    for (var ddIdx = 0; ddIdx < dropDowns.length; ddIdx++) {
    	var dd = dropDowns.item(ddIdx);
    	if (dd.getAttribute('name') != 'ccSelect') continue;
    	for (var i = 0; i < dd.options.length; i++) {
    		if (dd.options[i].value.split('|')[0] == targetCode) {
    			dd.selectedIndex = i;
    			break;
    		}
    	}
    }
});

window.currencyConverter.addPreConversionCallback(function (cc) {
	//matrix.hideRatePlanSelection();
});

window.currencyConverter.addPostConversionCallback(function () {
	//matrix.unhideRatePlanSelection();
	_f_set_mtx_s_ChangeMY();
	if ($('mtx_filterOnRequest')) $('mtx_filterOnRequest').checked = !matrix.showOnRequest;
	if (matrix.reservation) matrix.reservation.setDateSelected();
	
	if (mtxHelper) {
		mtxHelper.checkCheckboxes();
		mtxHelper.removeHoverMsg();
	}
	
	if (matrix.matrixType=='Destination' && matrix.portal != 1) {
		for (var i=0; i<shortlistedHotels.length; i++) {
			checkShortlist(shortlistedHotels[i]);
		}
	}
});

document.observe("matrix:loaded", function(e) {
	var m = e.memo;
	var isoCode = window.currencyConverter.getCookie(CurrencyConverter.prototype.CURRENCY_COOKIE);
	
	if (!window.allCurrencies) {
		var select = findCurrencySelect();
		if (!select) return; // no currency converter drop-down, we can't perform the conversion
		extractCurrencies(select);
	}
	if (isoCode && isoCode!=window.matrix.data.currency) {
		window.currencyConverter.convert(window.allCurrencies, isoCode);
	}
	window.currencyConverter.defaultCurrency = window.allCurrencies[window.matrix.data.currency];
});
;

