	
	var bodyClickHideEventRegistered = false;
	var currentCalendarControl = null;
	var monthsNameArray = new Array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
	var dayNamesArray = new Array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
	var numDaysInMonthArray = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
	
	function initializeCalendarPopup(callee) {
		callee.textBox = convertToObject(callee.getAttribute("parentID"));
		callee.textBox.onchange = function() { textBox_OnChange(this); };
		callee.currentDate = callee.textBox.value == "" ? new Date() : new Date(callee.textBox.value);
		callee.minimumDate = callee.getAttribute("minimumDate") == null ? new Date("01/01/1990") : new Date(callee.getAttribute("minimumDate"));
		callee.maximumDate = callee.getAttribute("maximumDate") == null ? new Date("12/31/2100") : new Date(callee.getAttribute("maximumDate"));
		callee.currentDate.setHours(0);
		callee.currentDate.setMinutes(0);
		callee.currentDate.setSeconds(0);
		callee.currentDate.setMilliseconds(0);

		callee.dateFormat = callee.getAttribute("dateFormat") == null ? "MM/dd/yyyy" : callee.getAttribute("dateFormat");
		callee.calendarAppearance = callee.getAttribute("calendarAppearance") == null ? "OverImage" : callee.getAttribute("calendarAppearance");
		callee.dayNameFormat = callee.getAttribute("dayNameFormat") == null ? "Short" : callee.getAttribute("dayNameFormat");
		callee.showGridLines = callee.getAttribute("showGridLines") == null ? false : (callee.getAttribute("showGridLines") == "True" ? true : false);

		if (callee.getAttribute("bodyStyle") == null) callee.setAttribute("bodyStyle", "background-color:white;border:silver 1px solid;");
		if (callee.getAttribute("dayHeaderStyle") == null) callee.setAttribute("dayHeaderStyle", "background-color:silver;");
		if (callee.getAttribute("dayStyle") == null) callee.setAttribute("dayStyle", "");
		if (callee.getAttribute("selectedDayStyle") == null) callee.setAttribute("selectedDayStyle", "background-color:silver;color:white;");
		
		callee.displayPanel = document.createElement("div");
		callee.displayPanel.isCalendarControl = true;
		callee.displayPanel.style.cssText = callee.getAttribute("bodyStyle");
		callee.displayPanel.style.position = "absolute";
		callee.displayPanel.style.visibility = "hidden";
		callee.displayPanel.style.width = "175px";
		callee.style.position = "absolute";
		
		switch (callee.calendarAppearance) {
			case "OverImage":
				callee.displayPanel.style.left = (callee.offsetLeft + 5) + "px";
				callee.displayPanel.style.top = callee.offsetTop + "px";
				break;
			case "OverTextBox":
				callee.displayPanel.style.left = (callee.offsetLeft - callee.textBox.offsetWidth) + "px";
				callee.displayPanel.style.top = callee.offsetTop + "px";
				break;
			case "BelowTextBox":
				callee.displayPanel.style.left = (callee.offsetLeft - callee.textBox.offsetWidth) + "px";
				callee.displayPanel.style.top = (callee.offsetTop + callee.textBox.offsetHeight) + "px";
				break;
		}
		callee.style.position = "static";
		callee.offsetParent.appendChild(callee.displayPanel);

		if (!bodyClickHideEventRegistered) {
			registerNonIEFocusSetActiveElement();
			registerNonIEClickSetActiveElement();
			hookupEvent(document.body, "onclick", "hideCalendarPopup()", true);
			bodyClickHideEventRegistered = true;
		}
	}
	
	function showCalendarPopup(callee) {
		//trace(new Date(2007, 0, 1));
		//hideCalendarPopup is registered on the body which in turns causes the calendar to be hidden,
		//solution, delay the call on show, let the body call hide the calendar, which fires off first
		//before showCalendarPopupDelayed is fired
		setTimeout("showCalendarPopupDelayed('" + callee.id + "');", 0);
	}
	
	function showCalendarPopupDelayed(callee) {
		callee = convertToObject(callee);
		initializeCalendarPopup(callee);
		currentCalendarControl = callee;
		displayCalendar(callee);
		callee.displayPanel.style.visibility = "visible";
	}
	
	function hideCalendarPopup(caller) {
		if (typeof(caller) == "undefined") {
			if (document.activeElement) {
				if (document.activeElement.isCalendarControl) return;
			}
			if (caller == null) if (!document.activeElement) return;
			caller = currentCalendarControl;
		}
		
		if (caller != null && typeof(caller) != "undefined") {
			caller = convertToObject(caller);
			caller.displayPanel.style.visibility = "hidden";
			currentCalendarControl = null;
		}
	}
	
	function displayCalendar(callee) {		
		if (callee.displayPanel.childNodes.length == 0) createCalendar(callee);
		callee.displayPanel.monthsList.selectedIndex = callee.currentDate.getMonth();
		callee.displayPanel.yearsList.selectedIndex = callee.currentDate.getFullYear() - callee.minimumDate.getFullYear();
		setMonthYear(callee);
	}
	
	function createCalendar(callee) {
		var table = document.createElement("table");
		table.cellPadding = 3;
		table.cellSpacing = 0;
		table.width = "100%";
		table.isCalendarControl = true;
		if (callee.showGridLines) {
			table.rules = "all";
			table.border = 1;
		}
		else table.rules = "none";
		
		var row0 = table.insertRow(0);
		var row1 = table.insertRow(1);
		var row2 = table.insertRow(2);
		
		var cell00 = row0.insertCell(0);
		var cell01 = row0.insertCell(1);
		
		var ddlMonth = document.createElement("select");
		ddlMonth.onchange = function() { setMonthYear(callee); };
		ddlMonth.isCalendarControl = true;
		for (var i=0; i<monthsNameArray.length; i++) {
			var option = document.createElement("option");
			option.value = i;
			option.text = monthsNameArray[i];
			if (isExplorer) ddlMonth.add(option);
			else ddlMonth.appendChild(option);
		}
		
		var ddlYears = document.createElement("select");
		ddlYears.isCalendarControl = true;
		ddlYears.onchange = function() { setMonthYear(callee); };
		for (var i=callee.minimumDate.getFullYear(); i<=callee.maximumDate.getFullYear(); i++) {
			var option = document.createElement("option");
			option.value = i;
			option.text = i.toString();
			if (isExplorer) ddlYears.add(option);
			else ddlYears.appendChild(option);
		}
		
		callee.displayPanel.monthsList = ddlMonth;
		callee.displayPanel.yearsList = ddlYears;
	
		setStyle(callee, row0, "dayHeader");
		
		cell00.align = "left";
		cell00.colSpan = 4;
		cell00.style.padding = "2px 1px 2px 1px";
		cell00.appendChild(ddlMonth);
		cell01.align = "right";
		cell01.colSpan = 3;
		cell01.style.padding = "2px 1px 2px 1px";
		cell01.appendChild(ddlYears);
		
		var divDaysBar = document.createElement("div");
		for (var i=0; i<7; i++) {
			var cell = row1.insertCell(i);
			cell.style.padding = "2px 1px 2px 1px";
			switch (callee.dayNameFormat) {
				case "FirstLetter": cell.innerHTML = dayNamesArray[i].substring(0, 1); break;
				case "FirstTwoLetters": cell.innerHTML = dayNamesArray[i].substring(0, 2); break;
				case "Full": cell.innerHTML = dayNamesArray[i]; break;
				default: cell.innerHTML = dayNamesArray[i].substring(0, 3); break;
			}
		}
		
		callee.displayPanel.layoutTable = table;
		callee.displayPanel.appendChild(table);
	}
	
	function setStyle(callee, obj, tag) {
		if (callee.getAttribute(tag + "Style") != null) obj.style.cssText = callee.getAttribute(tag + "Style");
		if (callee.getAttribute(tag + "CssClass") != null) obj.className = callee.getAttribute(tag + "CssClass");
	}
	
	function setMonthYear(callee) {		
		var monthIndex = callee.displayPanel.monthsList.selectedIndex;
		var year = parseInt(callee.displayPanel.yearsList.value);
		var numDaysInMonth = numDaysInMonthArray[monthIndex];
		
		if (monthIndex == 1 && (year % 4) == 0) numDaysInMonth++;
		
		var firstDay = 0;
		var lastDay = numDaysInMonth -1;
		var tempDate = new Date(callee.currentDate);
		tempDate.setMonth(monthIndex);
		tempDate.setYear(year);
		tempDate.setDate(1);
		var firstDayIndex = tempDate.getDay();
		tempDate.setDate(numDaysInMonth);
		var lastDayIndex = tempDate.getDay();
		
		if (firstDayIndex != 0) firstDay = -firstDayIndex;
		if (lastDayIndex != 6) lastDay += (6 - lastDayIndex);
		
		var table = callee.displayPanel.layoutTable;
		
		if (table.rows.length > 2) {
			for (var i=table.rows.length-1; i> 2; i--) table.deleteRow(i);
		}
		
		var row = callee.displayPanel.layoutTable.insertRow(table.rows.length);
		for (var i=firstDay; i<=lastDay; i++) {			
			if (row.cells.length == 7) {
				row = table.insertRow(table.rows.length);
			}
			var cell = row.insertCell(row.cells.length);
			cell.align = "center";
			if (i < 0 || i >= numDaysInMonth) cell.innerHTML = "";
			else {
				var cellDay = (i + 1);
				var cellDate = new Date(year, monthIndex, cellDay);
				var anchor = document.createElement("a");
				setStyle(callee, cell, (callee.currentDate.getDate() == cellDate.getDate() && callee.currentDate.getMonth() == cellDate.getMonth() && callee.currentDate.getFullYear() == cellDate.getFullYear() ) ? "selectedDay" : "day");
				anchor.innerHTML = cellDay;
				anchor.href = "javascript:void(0);";
				anchor.style.color = cell.style.color;
				anchor.isCalendarControl = true;
				anchor.date = cellDate;
				anchor.onclick = function () { setDate(callee, this) };
				cell.appendChild(anchor);
			}
		}
	}
	
	function setDate(callee, anchor) {
		callee.currentDate = anchor.date;
		callee.textBox.value = formatDate(callee.currentDate, callee.dateFormat);
		hideCalendarPopup(callee);
	}
	
	function formatDate(date, format) {
		var result = format;
		if (format == "d") result = "MM/dd/yyyy";
		else if (format == "D") result = "MMMM dd, yyyy";

		if (result.indexOf("MMMM") > -1) result = result.replace("MMMM", monthsNameArray[date.getMonth()]);
		if (result.indexOf("MMM") > -1) result = result.replace("MMM", monthsNameArray[date.getMonth()].substring(0, 3));
		if (result.indexOf("MM") > -1) {
			var month = date.getMonth() + 1;
			result = result.replace("MM", month.toString().length == 2 ? month : "0" + month);
		}
		if (result.indexOf("M") > -1) result = result.replace("M", date.getMonth() + 1);

		if (result.indexOf("dddd") > -1) result = result.replace("dddd", dayNamesArray[date.getDay()]);
		if (result.indexOf("ddd") > -1) result = result.replace("ddd", dayNamesArray[date.getDay()].substring(0, 3));
		if (result.indexOf("dd") > -1) {
			var day = date.getDate();
			result = result.replace("dd", day.toString().length == 2 ? day : "0" + day);
		}

		if (result.indexOf("yyyy") > -1) result = result.replace("yyyy", date.getFullYear());
		if (result.indexOf("yy") > -1) result = result.replace("yy", date.getFullYear().substring(2, 2));

		return result;
	}
	
	function deriveDate(date) {
		if (typeof(date) == "string") {
			return new Date(date);
		}
	}
	
	function textBox_OnChange(callee) {
		callee.currentDate = deriveDate(callee.textBox.value);
	}
	
	function zendTo(str) {
		
	}