var oDisplay, oValue, oCalDiv;
var sCalPath = '';
var nInput = 0;
var oCurCal;
var oCals = new Array();

var bHasCalDiv = false;
var nTimerID = 0;
var nTickerID = 0;

var dToday = dateOnly(new Date());

var sMonth = new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
var sDay = new Array("Su", "Mo", "Tu", "We", "Th", "Fr", "Sa");
var sDayLong = new Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday");

var c_LOCALE_CODE_UK = "en-gb";
var c_LOCALE_CODE_US = "en-us";

// SQLServer stores the null date as a time component, which comes back to the 
// web with a default day, month and year:
var c_NULL_DATE = "1899-12-30 00:00:00";

var oTempPopup, bTempShow;

sCalPath = getPath();


function twoDigits(n)
{
	if (n < 10)
		return "0" + n;
	else
		return n;
}

function formatDateServer(dDate, bSuppressTimeComponent)
{
	// the second parameter is optional; if this parameter is supplied 
	// then the time component of the date will be discarded

	var v_return = "";

	if (dDate) {
		v_return = dDate.getFullYear() + "-" + twoDigits(dDate.getMonth() + 1) + "-" + twoDigits(dDate.getDate()) + 
			(bSuppressTimeComponent ? 
				"" : 
				" " + twoDigits(dDate.getHours()) + ":" + twoDigits(dDate.getMinutes()) + ":" + twoDigits(dDate.getSeconds())
			);
	}

	return v_return;
}

function formatDateDisplay(dDate, bSuppressTimeComponent)
{
	// the second parameter is optional; if this parameter is not supplied 
	// then the full date and time will be displayed in the long date format 
	// for that region

	var v_return = "";

	// get the date properties
	if (dDate) {
		var v_day = dDate.getDay();
		var v_date = (dDate.getDate() < 10 ? "0" + dDate.getDate() : dDate.getDate());
		var v_month = ((dDate.getMonth() + 1) < 10 ? "0" + (dDate.getMonth() + 1) : (dDate.getMonth() + 1));
		var v_year = dDate.getYear();
		var v_hours = (dDate.getHours() < 10 ? "0" + dDate.getHours() : dDate.getHours());
		var v_minutes = (dDate.getMinutes() < 10 ? "0" + dDate.getMinutes() : dDate.getMinutes());
		var v_seconds = (dDate.getSeconds() < 10 ? "0" + dDate.getSeconds() : dDate.getSeconds());
	
		var v_month_name = sMonth[dDate.getMonth()];
		var v_day_name = sDayLong[v_day];
	
		var v_hours_12_hr = (dDate.getHours() > 12 ? dDate.getHours() - 12 : dDate.getHours());
		var v_am_pm_12_hrs = (v_hours > 12 ? "PM" : "AM");
	
	
		v_date_component_uk_format = v_date + " " + v_month_name + " " + v_year;
		v_time_component_uk_format = v_hours + ":" + v_minutes + ":" + v_seconds;
	
		v_date_component_us_format = v_day_name + ", " + v_month_name + " " + v_date + ", " + v_year;
		v_time_component_us_format = v_hours_12_hr + ":" + v_minutes + ":" + v_seconds + " " + v_am_pm_12_hrs;
	
	
		if (navigator.userLanguage == c_LOCALE_CODE_US) {
			// user has US preferences set up - use default US format
			v_return = v_date_component_us_format + 
				(bSuppressTimeComponent ? 
					"" : 
					" " + v_time_component_us_format
				);
		} else {
			// use the UK long date as the default
			v_return = v_date_component_uk_format + 
				(bSuppressTimeComponent ? 
					"" : 
					" " + v_time_component_uk_format
				);
		}
	}

	return v_return;
}

function stringToDate(sDate, bNoDefaultDate)
{
	if (sDate) {
		// check if the date string should be interpreted as null
		if (sDate == c_NULL_DATE || sDate == '0') {
			null;
		} else if (sDate.match(/^\d{2}\D\d{2}\D\d{4} \d{2}\D\d{2}\D\d{2}$/)) {
			return new Date(sDate.substr(6, 4), sDate.substr(3, 2) - 1, sDate.substr(0, 2), sDate.substr(11,2), sDate.substr(14, 2));
		} else if (sDate.match(/^\d{4}\D\d{2}\D\d{2} \d{2}\D\d{2}\D\d{2}$/)) {
			return new Date(sDate.substr(0, 4), sDate.substr(5, 2) - 1, sDate.substr(8, 2), sDate.substr(11,2), sDate.substr(14, 2));
		} else if (sDate.match(/^\d{4}\D\d{2}\D\d{2}$/)) {
			return new Date(sDate.substr(0, 4), sDate.substr(5, 2) - 1, sDate.substr(8, 2));
		}
	}
	if (bNoDefaultDate) {
		return null;
	}
	return new Date();
}

function displayDate(sDate, bSuppressTimeComponent)
{
	// the second parameter is optional; if this parameter is not supplied 
	// then the full date and time will be displayed in the long date format 
	// for that region
	document.write(formatDateDisplay(stringToDate(sDate), bSuppressTimeComponent));
}

function displayDateWithoutTime(sDate)
{
	// call the displayDate function with the suppress time boolean set to 
	// true, i.e. do not display the time component
	displayDate(sDate, true);
}

function dateOnly(dDate)
{
	if (dDate) {
		return new Date(dDate.getFullYear(), dDate.getMonth() ,dDate.getDate());
	} else {
		return null;
	}
}

function getDaysInMonth(dDate)
{
	var nMonth = dDate.getMonth() + 1;
	var nYear = dDate.getFullYear();
	if ((nMonth == 1 ) || (nMonth == 3) || (nMonth == 5) || (nMonth == 7) || (nMonth == 8) || (nMonth == 10) || (nMonth == 12))
		return 31;
	else if ((nMonth == 4 ) || (nMonth == 6) || (nMonth == 9) || (nMonth == 11))
		return 30;
	else if ((nYear % 400) == 0)
		return 29;
	else if ((nYear % 100) == 0)
		return 28;
	else if ((nYear % 4) == 0)
		return 29;
	else
		return 28;
}

function getMonthName(dDate)
{
	return sMonth[dDate.getMonth()];
}

function cal_navBackMonth()
{
	if (!(oCurCal.dDate)) {
		oCurCal.dDate = dToday;
	}

	var nMonth = oCurCal.dDate.getMonth();

	if (nMonth == 0)
		oCurCal.dDate = new Date(oCurCal.dDate.getFullYear() - 1, 11, 1);
	else
		oCurCal.dDate = new Date(oCurCal.dDate.getFullYear(), nMonth - 1, 1);
	oCurCal.drawCal();
}

function cal_navForwardMonth()
{
	if (!(oCurCal.dDate)) {
		oCurCal.dDate = dToday;
	}

	var nMonth = oCurCal.dDate.getMonth();

	if (nMonth == 11)
		oCurCal.dDate = new Date(oCurCal.dDate.getFullYear() + 1, 0, 1);
	else
		oCurCal.dDate = new Date(oCurCal.dDate.getFullYear(), nMonth + 1, 1);
	oCurCal.drawCal();
}

function cal_navBackYear()
{
	if (!(oCurCal.dDate))
		oCurCal.dDate = dToday;

	oCurCal.dDate = new Date(oCurCal.dDate.getFullYear() - 1, oCurCal.dDate.getMonth(), 1);
	oCurCal.drawCal();
}

function cal_navForwardYear()
{
	if (!(oCurCal.dDate))
		oCurCal.dDate = dToday;

	oCurCal.dDate = new Date(oCurCal.dDate.getFullYear() + 1, oCurCal.dDate.getMonth(), 1);
	oCurCal.drawCal();
}

function clearDate()
{

	oCurCal.dTime = null;
	oCurCal.dDate = null;
	oCurCal.dSelDate = null;

	oCurCal.oInput.value = ''
	oCurCal.oDisplay.value = '';
	hideCal(true);

	if (oCurCal.fOnChange && (oCurCal.dTime == null)) {
		oCurCal.fOnChange(oCurCal);
	}

}

function cal_navToday()
{
	oCurCal.setDate(dToday);
	oCurCal.drawCal();
}

function cal_choose(nDay)
{
	if (!(oCurCal.dDate)) {
		oCurCal.dDate = dToday;
	}

	oCurCal.setDate(new Date(oCurCal.dDate.getFullYear(), oCurCal.dDate.getMonth(), nDay));
	hideCal(true);
}

function cal_hourUp()
{
	if (!(oCurCal.dTime)) {
		oCurCal.dTime = new Date();
	}

	oCurCal.setTime(new Date(oCurCal.dTime.getTime() + new Date(1970, 0, 1, 1).getTime()));
	drawTime();
}

function cal_hourDown()
{
	if (!(oCurCal.dTime)) {
		oCurCal.dTime = new Date();
	}

	oCurCal.setTime(new Date(oCurCal.dTime.getTime() - new Date(1970, 0, 1, 1).getTime()));
	drawTime();
}

function cal_minuteUp()
{
	if (!(oCurCal.dTime)) {
		oCurCal.dTime = new Date();
	}

	oCurCal.dTime.setMinutes(oCurCal.dTime.getMinutes() - oCurCal.dTime.getMinutes() % 5);
	oCurCal.setTime(new Date(oCurCal.dTime.getTime() + new Date(1970, 0, 1, 0, 5).getTime()));
	drawTime();
}

function cal_minuteDown()
{
	if (!(oCurCal.dTime)) {
		oCurCal.dTime = new Date();
	}

	oCurCal.dTime.setMinutes(oCurCal.dTime.getMinutes() + 4);
	oCurCal.dTime.setMinutes(oCurCal.dTime.getMinutes() - oCurCal.dTime.getMinutes() % 5);
	oCurCal.setTime(new Date(oCurCal.dTime.getTime() - new Date(1970, 0, 1, 0, 5).getTime()));
	drawTime();
}

function startTicker(sFunction)
{
	if (nTickerID != 0)
		clearInterval(nTickerID);
	eval(sFunction + "()");
	nTickerID = setInterval(sFunction + "()", 200);
}

function stopTicker()
{
	if (nTickerID != 0)
		clearInterval(nTickerID);
	nTickerID = 0;
}


function drawTime()
{
	document.getElementById('calcontroltime').innerHTML = twoDigits(oCurCal.dTime.getHours()) + ":" + twoDigits(oCurCal.dTime.getMinutes());
}

function getOffsetLeft(o)
{
	if (o.tagName == "BODY")
		return 0;
	else
		return o.offsetLeft + getOffsetLeft(o.offsetParent);
}

function getOffsetTop(o)
{
	if (o.tagName == "BODY")
		return 0;
	else
		return o.offsetTop + getOffsetTop(o.offsetParent);
}

function setSelectVisibility(oPopup, bShow)
{
	var n;
	var oSels, oSel;
	var nPLeft, nPRight, nPTop, nPBottom;
	var nSLeft, nSRight, nSTop, nSBottom;

	if (oPopup.style.top != "") {
		if ((oPopup.offsetTop + "px") != oPopup.style.top)
		{
			oTempPopup = oPopup;
			bTempShow = bShow;
			setTimeout("setSelectVisibility(oTempPopup, bTempShow)", 0);
			return;
		}
	}

	nPLeft = getOffsetLeft(oPopup);
	nPTop = getOffsetTop(oPopup);
	nPRight = nPLeft + oPopup.offsetWidth;
	nPBottom = nPTop + oPopup.offsetHeight;

	var oSels = document.getElementsByTagName("SELECT")
	for (n = 0; n < oSels.length; n++)
	{
		oSel = oSels[n];
		nSLeft = getOffsetLeft(oSel);
		nSTop = getOffsetTop(oSel);
		nSRight = nSLeft + oSel.offsetWidth;
		nSBottom = nSTop + oSel.offsetHeight;
		if ((nSLeft < nPRight) && (nSRight > nPLeft) && (nSTop < nPBottom) && (nSBottom > nPTop)) 
			if (bShow)
				oSel.style.visibility = "visible";
			else
				oSel.style.visibility = "hidden";
	}
}

function showCal(oCal)
{
	var nTop;
	
	if (nTimerID != 0)
	{
		clearTimeout(nTimerID);
		nTimerID = 0;
	}

	if (oCal)
	{

		oCurCal = oCal;
		oCurCal.dDate = dateOnly(oCurCal.dTime);
		oCurCal.drawCal();
		nTop = getOffsetTop(oCal.oDisplay) + oCal.oDisplay.offsetHeight;
		oCalDiv.style.top = nTop + "px";
		oCalDiv.style.left = getOffsetLeft(oCal.oDisplay) + "px";
		if (nTop != oCalDiv.offsetTop) // Kludge for IE 5.0
		{
			setTimeout("showCal(oCurCal)", 0);
			return;
		}

		if (((oCalDiv.offsetTop + oCalDiv.offsetHeight) - (document.body.scrollTop + document.body.clientHeight)) > 0)
			oCalDiv.style.top = (getOffsetTop(oCal.oDisplay) - oCalDiv.offsetHeight) + "px";
	}

	if (oCalDiv.style.visibility == 'visible')
		return;
	setSelectVisibility(oCalDiv, false);
	oCalDiv.style.visibility = "visible";	
}

function hideCal(bImmediate)
{
	if (oCalDiv.style.visibility == 'hidden')
		return;

	if (!bImmediate)
	{
		nTimerID = setTimeout("hideCal(true)", 500);
		return;
	}

	setSelectVisibility(oCalDiv, true);
	oCalDiv.style.visibility = 'hidden';	
}

function getPath() {

	var sCalPath = '';
	var nSheet, n, sHref;

	for (nSheet = 0; nSheet < document.styleSheets.length; nSheet++)
	{		
		sHref = document.styleSheets[nSheet].href;		
		if ((n = sHref.lastIndexOf("/")) != -1)
			if (sHref.substr(n + 1) == "calendar.css")
				sCalPath = sHref.substr(0, n + 1);
	}
	
	return sCalPath;
}


function CCal_drawCal()
{
	var sHTML;
	var n;
	var dDay;
	var nDay = 0;

	var vCalendarDateTime = new Date();
	var vCalendarDate = new Date();
	var vSelectedDate = new Date();

	if (this.dTime) {
		vCalendarDateTime = this.dTime;
	}
	if (this.dDate) {
		vCalendarDate = this.dDate;
	}
	if (this.dSelDate) {
		vSelectedDate = this.dSelDate;
	}

	var nDayLast = getDaysInMonth(vCalendarDate);
	var nDay1 = new Date(vCalendarDate.getFullYear(), vCalendarDate.getMonth(), 1).getDay();

	sHTML = "<table border='0' cellspacing='2' cellpadding='0' width='100%'>";
	sHTML = sHTML + "<tr><td class='calnav'><a class='calnav' title='Previous month' onclick='cal_navBackMonth()'>&lt;</a></td>";
	sHTML = sHTML + "<td class='calmonth' colspan='5'>" + getMonthName(vCalendarDate) + "</td>";
	sHTML = sHTML + "<td class='calnav'><a class='calnav' title='Next month' onclick='cal_navForwardMonth()'>&gt;</a></td></tr>";
	sHTML = sHTML + "<tr><td class='calnav'><a class='calnav' title='Previous year' onclick='cal_navBackYear()'>&lt;&lt;</a></td>";
	sHTML = sHTML + "<td class='calmonth' colspan='5'>" + vCalendarDate.getFullYear() + "</td>";
	sHTML = sHTML + "<td class='calnav'><a class='calnav' title='Next year' onclick='cal_navForwardYear()'>&gt;&gt;</a></td></tr>";

	sHTML = sHTML + "<tr>";
	for (n = 0; n < 7; n++)
		sHTML = sHTML + "<td class='calweekday'>" + sDay[n] + "</td>";

	for (n = 0; n < 42; n++)
	{
		if (n % 7 == 0)
			sHTML = sHTML + "</tr><tr>";
		if ((nDay > 0) || (n == nDay1))
			dDay = new Date(vCalendarDate.getFullYear(), vCalendarDate.getMonth(), ++nDay);
		else
			dDay = new Date(0);
		if ((nDay > 0) && (nDay <= nDayLast))
		{
			if (dDay.getTime() == vSelectedDate.getTime())
				sHTML = sHTML + "<td class='calselday'>";
			else
				sHTML = sHTML + "<td class='calday'>";
			if (dDay.getTime() == dToday.getTime())
				sHTML = sHTML + "<a class='caltoday'";
			else
				sHTML = sHTML + "<a class='calnormday'"
			sHTML = sHTML + " onclick='cal_choose(" + nDay + ")'>" + nDay + "</a></td>";
		}
		else
			sHTML = sHTML + "<td class='calday'>&nbsp;</td>";
	}

	sHTML = sHTML + "</tr><tr><td class='calstd' colspan='7'><table style='width: 100%'><tr>";

	if (this.bNoTimeComponent) {
		if (!this.bIsMandatory)
			sHTML = sHTML + "<td class='calstd' align='left'><a class='calnav' onclick='clearDate()'>Clear</a></td>";		
	} else {
		sHTML = sHTML + "<td class='calstd'>"
		sHTML = sHTML + "<table class='caltimetable' onmouseout='stopTicker()'><tr>";
		sHTML = sHTML + "<td class='caltimenav'><img src='" + sCalPath + "cal_time_up.gif' onmousedown='startTicker(\"cal_hourUp\")' onmouseup='stopTicker()'></td>";
		sHTML = sHTML + "<td class='caltime' rowspan='2' id='calcontroltime'>" + twoDigits(vCalendarDateTime.getHours()) + ":" + twoDigits(vCalendarDateTime.getMinutes()) + "</td>";
		sHTML = sHTML + "<td class='caltimenav'><img src='" + sCalPath + "cal_time_up.gif' onmousedown='startTicker(\"cal_minuteUp\")' onmouseup='stopTicker()'></td>";
		sHTML = sHTML + "</tr><tr>"
		sHTML = sHTML + "<td class='caltimenav'><img src='" + sCalPath + "cal_time_down.gif' onmousedown='startTicker(\"cal_hourDown\")' onmouseup='stopTicker()'></td>";
		sHTML = sHTML + "<td class='caltimenav'><img src='" + sCalPath + "cal_time_down.gif' onmousedown='startTicker(\"cal_minuteDown\")' onmouseup='stopTicker()'></td>";
		sHTML = sHTML + "</tr></table>";
		sHTML = sHTML + "</td>";	
		if (!this.bIsMandatory)
			sHTML = sHTML + "<td class='calstd' align='center'><a class='calnav' onclick='clearDate()'>Clear</a></td>";		
	}

	sHTML = sHTML + "<td class='calstd' align='right'><a class='calnav' onclick='cal_navToday()'>Go to today</a></td>";	
	sHTML = sHTML + "</td></tr></table></td></tr></table>";

	oCalDiv.innerHTML = sHTML;
}

function CCal_setDate(dDate)
{
	if (!(this.dTime)) {
		this.dTime = new Date();
	}

	this.setTime(new Date(dDate.getFullYear(), dDate.getMonth() ,dDate.getDate(),
		this.dTime.getHours(), this.dTime.getMinutes()));
}

function CCal_setTime(dTime, bNoChange, dTimeAsString)
{	
	this.dOldTime = this.dTime;
	this.dTime = dTime;
	this.dDate = dateOnly(this.dTime);
	this.dSelDate = this.dDate;

	if (!this.bIsMandatory && dTimeAsString == '0') {
		this.oInput.value = '';
		this.oDisplay.value = '';
	}
	else {
		this.oInput.value = formatDateServer(this.dTime, this.bNoTimeComponent);
		this.oDisplay.value = formatDateDisplay(this.dTime, this.bNoTimeComponent);
	}
	if (this.fOnChange && !bNoChange) {
		this.fOnChange(this);
	}
}

function CCal(sHiddenName, sDisplayName, sImgName, sDate, fOnChange, bIsMandatory, bNoDefaultDate, bNoTimeComponent)
{
	var textCal = "Click to select a date";
	this.drawCal = CCal_drawCal;
	this.setDate = CCal_setDate;
	this.setTime = CCal_setTime;
	this.bIsMandatory = bIsMandatory ? true : false;
	this.bNoDefaultDate = bNoDefaultDate ? true : false;
	this.bNoTimeComponent = bNoTimeComponent ? true : false;
	this.fOnChange = fOnChange;

	this.nID = oCals.length;
	oCals[this.nID] = this;

	this.oInput = document.getElementById(sHiddenName);
	this.oInput.original_value = sDate;
	
	this.oDisplay = document.getElementById(sDisplayName);
	this.oDisplay.onfocus = this.oDisplay.blur;
	this.oDisplay.onclick = new Function("showCal(oCals[" + this.nID + "]); return false");
	this.oDisplay.title = textCal;
	this.oDisplay.onmouseout = hideCal;

	this.oImage = document.getElementById(sImgName);
	this.oImage.onclick = new Function("showCal(oCals[" + this.nID + "]); return false");	 
	this.oImage.title = textCal;
	this.setTime(stringToDate(sDate, bNoDefaultDate), true, sDate);

	if (!oCalDiv)
	{
		oCalDiv = document.createElement("<DIV>");
		oCalDiv.className = "calcontrol";
		oCalDiv.onmouseover = showCal;
		oCalDiv.onmouseout = hideCal;
		document.body.insertBefore(oCalDiv, document.body.childNodes[0]);
	}
}

function attachCalControl(sHiddenName, sDisplayName, sImgName, sDate, fOnChange, bIsMandatory, bNoDefaultDate, bNoTimeComponent)
{
	var oCal = new CCal(sHiddenName, sDisplayName, sImgName, sDate, fOnChange, bIsMandatory, bNoDefaultDate, bNoTimeComponent);
}
