
	function Calendar(id,currentDate,lowerDateLimit,upperDateLimit,required,showTime,hour,min,alwaysVisible,additional) {

		this.id = id;

		this.el = $(id);
		
		//dump(this.el);

		this.required = true;
		if (typeof required != 'undefined') {
			this.required = required;
		}

		this.currentDate = currentDate;
		this.currentDateCell = null;

		this.month = currentDate.month;
		this.year = currentDate.year;

		if (typeof showTime == 'undefined') {
			showTime = false;
		}
		this.hiddenInput = null;

		this.showIcon = true;
		this.showTime = showTime;

		if (typeof hour == 'undefined') {
			hour = null;
		}
		if (typeof min == 'undefined') {
			min = null;
		}
		this.hour = hour;
		this.min = min;

		if (typeof alwaysVisible == 'undefined') {
			this.alwaysVisible = false;
		} else {
			this.alwaysVisible = alwaysVisible;
		}

		this.lowerDateLimit = lowerDateLimit;
		this.upperDateLimit = upperDateLimit;

		this.onchange = null;
		this.onafterchange = null;
		this.onafterchangeclick = null;
		this.canHighlightDate = null;
		
		this.afterSetCurrentDate = null;
		
		this.canClickAny = false;

		this.useShortMonths = false;
		this.useShorterDays = false;
		this.setDateOnMouseOver = false;
		this.trySetWithoutRedraw = false;   
		this.onclickdate = new Function();   
		this.onrenderdates = new Function();
		this.nextAndPrev = true;
		if (typeof(additional) != 'undefined') {
			if (typeof(additional.useShortMonths) != 'undefined') this.useShortMonths = additional.useShortMonths;
			if (typeof(additional.useShorterDays) != 'undefined') this.useShorterDays = additional.useShorterDays;
			if (typeof(additional.setDateOnMouseOver) != 'undefined') this.setDateOnMouseOver = additional.setDateOnMouseOver;
			if (typeof(additional.onrenderdates) != 'undefined') this.onrenderdates = additional.onrenderdates;
			if (typeof(additional.trySetWithoutRedraw) != 'undefined') this.trySetWithoutRedraw = additional.trySetWithoutRedraw;
			if (typeof(additional.onclickdate) != 'undefined') this.onclickdate = additional.onclickdate;
			if (typeof(additional.nextAndPrev) != 'undefined') this.nextAndPrev = additional.nextAndPrev;
		}

		var table = document.createElement("table");
		table.id = this.id+'_calendarTable';
		table.cellSpacing = 1;
		table.cellPadding = 0;

		this.monthOptionEls = new Array();

		this.headerContainerEl = document.createElement("thead");
		this.datesContainerEl = document.createElement("tbody");
		this.datesContainerEl.className = 'calendar';

		table.appendChild(this.headerContainerEl);
		table.appendChild(this.datesContainerEl);

		this.renderControls();

		this.calendarEl.appendChild(table);


		this.updateControls(false);
		this.renderDates();

		stopHighlight(this.calendarEl);

		this.dateOfUpcomingHighlight = null;



	}

	function getCalendar(options) {

		var v = {
			id : null,
			currentDate : null,
			lowerDateLimit : null,
			upperDateLimit : null,
			required : true,
			showTime : false,
			hour : null,
			min : null,
			alwaysVisible : false,
			useShortMonths : false
		};

		for (var i in options) {
			v[i] = options[i];
		}
		//dump(v);

		var cal = new Calendar(v.id,v.currentDate,v.lowerDateLimit,v.upperDateLimit,v.required,v.showTime,v.hour,v.min,v.alwaysVisible,v);

		return cal;
	}

	Calendar.prototype.enable = function() {
		this.datesSelectEl.disabled = false;
		this.monthsSelectEl.disabled = false;
		this.yearsSelectEl.disabled = false;
		$(this.id +'Icon').src = 'onClick/Designs/Images/calendar.gif';
		$(this.id +'Icon').style.cursor = 'pointer';
		//onClick/Designs/Images/calendar.gif
	}

	Calendar.prototype.disableDates = function() {
		this.datesSelectEl.disabled = true;
		$(this.id +'Icon').src = 'onClick/Designs/Images/calendar-disabled.gif';
		$(this.id +'Icon').style.cursor = 'default';
	}
	Calendar.prototype.enableDates = function() {
		this.datesSelectEl.disabled = false;
		$(this.id +'Icon').src = 'onClick/Designs/Images/calendar.gif';
		$(this.id +'Icon').style.cursor = 'pointer';
	}


	Calendar.prototype.getCurrentDate = function() {
		if (this.isNoDate()) {
			return null;
		} else {
			return this.currentDate;
		}
	}

	Calendar.prototype.getCurrentDateString = function() {
		if (this.isNoDate()) {
			return null;
		} else {
			if (this.showTime)  {
				var hour = this.hour;
				var min = this.min;
				if (hour < 10) hour = '0'+hour;
				if (min < 10) min = '0'+min;
				return this.currentDate.toString() + ' ' + hour + ':' + min;
			}
			return this.currentDate.toString();
		}
	}

	Calendar.prototype.dateDifference = function(compareDate) {
		return this.currentDate.dateDifference(compareDate);
	}


	Calendar.prototype.disable = function() {
		this.datesSelectEl.disabled = true;
		this.monthsSelectEl.disabled = true;
		this.yearsSelectEl.disabled = true;
		$(this.id +'Icon').src = 'onClick/Designs/Images/calendar-disabled.gif';
		$(this.id +'Icon').style.cursor = 'default';
	}

	Calendar.prototype.monthsShort = new Array(null,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
	Calendar.prototype.months = new Array(null,"January","February","March","April","May","June","July","August","September","October","November","December");
	Calendar.prototype.days = new Array("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday");
	Calendar.prototype.daysShort = new Array("Su","Mo","Tu","We","Th","Fr","Sa");
	Calendar.prototype.daysShorter = new Array("S","M","T","W","T","F","S");
	Calendar.prototype.mtend = new Array(null,31,28,31,30,31,30,31,31,30,31,30,31);

	Calendar.prototype.dateIsAllowed = function(year,month,day) {
		var test = new CalendarDate(year,month,day,this);
		return (test.isBeforeOrEqualTo(this.upperDateLimit) && test.isAfterOrEqualTo(this.lowerDateLimit));
	}

	Calendar.prototype.setMonth = function(month) {
		month = parseInt(month,10);
		var year = this.year;
		updated = false;
		if (month == 0) {
			month = 12;
			year--;
			if (this.monthIsAllowed(year,month)) {
				this.month = month;
				this.year = year;
				updated = true;
			}
		} else if (month == 13) {
			month = 1;
			year++;
			if (this.monthIsAllowed(year,month)) {
				this.month = month;
				this.year = year;
				updated = true;
			}
		} else {
			if (this.monthIsAllowed(year,month)) {
				this.month = month;
				this.year = year;
				updated = true;
			}
		}
		if (updated) {
            this.renderDates();
        }
		this.updateControls(false);
	}

	Calendar.prototype.monthIsAllowed = function(year,month) {
		var testUpper = new CalendarDate(year,month,1,this);
		var testLower = new CalendarDate(year,month,this.getDaysInMonth(year,month),this);
		return (testUpper.isBeforeOrEqualTo(this.upperDateLimit) && testLower.isAfterOrEqualTo(this.lowerDateLimit));
	}


	Calendar.prototype.setYear = function(year) {
		var month = this.month;
		var testUpper = new CalendarDate(year,month,1,this);
		var testLower = new CalendarDate(year,month,this.getDaysInMonth(year,month),this);

		if (testUpper.isAfterOrEqualTo(this.upperDateLimit)) {
			// If the year is too high, set it to the maximum allowable month,year
			year = this.upperDateLimit.year;
			month = this.upperDateLimit.month;
		} else if (testLower.isBeforeOrEqualTo(this.lowerDateLimit)) {
			// If the year is too low, set it to the lowest allowable month,year
			year = this.lowerDateLimit.year;
			month = this.lowerDateLimit.month;
		}

		this.year = year;
		this.month = month;
		this.updateControls(false);
		this.renderDates();
	}

	Calendar.prototype.updateControls = function(force) {
		var i, className;

		// update the date
		var daysInMonth = this.getDaysInMonth(this.currentDate.year,this.currentDate.month);

		var selectEl = this.datesSelectEl;

		if (this.required) {
			// remove any extras
			while (selectEl.options.length > daysInMonth) selectEl.options[selectEl.options.length-1] = null;

			// add any extras
			while (selectEl.options.length < daysInMonth) {
				i = selectEl.options.length+1;
				var op = new Option(i,i);
				selectEl.options[selectEl.options.length] = op;
			}

		} else {
			// remove any extras
			while (selectEl.options.length-1 > daysInMonth) selectEl.options[selectEl.options.length-1] = null;

			// add any extras
			while (selectEl.options.length-1 < daysInMonth) {
				i = selectEl.options.length;
				var op = new Option(i,i);
				selectEl.options[selectEl.options.length] = op;
			}
		}

		// select the current one, and disable any bad ones
		for (i=0; i<selectEl.options.length; i++) {

			// grey out any unavailable
			className = 'normal';
			if (selectEl.options[i].value > 0) {
				if (this.currentDate.year == this.lowerDateLimit.year && this.currentDate.month == this.lowerDateLimit.month) {
					if (selectEl.options[i].value < this.lowerDateLimit.date) className = 'disabled';
				}
				if (this.currentDate.year == this.upperDateLimit.year && this.currentDate.month == this.upperDateLimit.month) {
					if (selectEl.options[i].value > this.upperDateLimit.date) className = 'disabled';
				}
				selectEl.options[i].className = className;


				if (selectEl.options[i].value == this.currentDate.date && (!this.isNoDate() || force)) selectEl.selectedIndex = i;
			}
		}


		// update the month
		for (i=0; i<this.calendarMonthsSelectEl.options.length; i++) {
			if (this.calendarMonthsSelectEl.options[i].value == this.month) this.calendarMonthsSelectEl.selectedIndex = i;

			// grey out any unavailable
			className = 'normal';
			if (this.year == this.lowerDateLimit.year) {
				if (this.calendarMonthsSelectEl.options[i].value < this.lowerDateLimit.month) {
					className = 'disabled';
				}
			}
			if (this.year == this.upperDateLimit.year) {
				if (this.calendarMonthsSelectEl.options[i].value > this.upperDateLimit.month) {
					className = 'disabled';
				}
			}
			this.calendarMonthsSelectEl.options[i].className = className;
		}

		// update the month, again
		for (i=0; i<this.monthsSelectEl.options.length; i++) {
			if (this.monthsSelectEl.options[i].value == this.currentDate.month && (!this.isNoDate() || force)) this.monthsSelectEl.selectedIndex = i;

			// grey out any unavailable
			className = 'normal';
			if (this.currentDate.year == this.lowerDateLimit.year) {
				if (this.monthsSelectEl.options[i].value < this.lowerDateLimit.month) {
					className = 'disabled';
				}
			}
			if (this.currentDate.year == this.upperDateLimit.year) {
				if (this.monthsSelectEl.options[i].value > this.upperDateLimit.month) {
					className = 'disabled';
				}
			}
			this.monthsSelectEl.options[i].className = className;
		}


		// update the year
		for (i=0; i<this.calendarYearsSelectEl.options.length; i++) {
			if (this.calendarYearsSelectEl.options[i].value == this.year) {
				this.calendarYearsSelectEl.selectedIndex = i;
				break;
			}
		}

		// update the year, again
		for (i=0; i<this.yearsSelectEl.options.length; i++) {
			if (this.yearsSelectEl.options[i].value == this.currentDate.year && (!this.isNoDate() || force)) {
				this.yearsSelectEl.selectedIndex = i;
				break;
			}
		}

		// fix next and prev
		if (this.nextAndPrev) {
			if ((this.year == this.lowerDateLimit.year && this.month == this.lowerDateLimit.month)) {
				addClassName(this.previousEl,'disabled');
			} else {
				removeClassName(this.previousEl,'disabled');
			}
			if ((this.year == this.upperDateLimit.year && this.month == this.upperDateLimit.month)) {
				addClassName(this.nextEl,'disabled');
			} else {
				removeClassName(this.nextEl,'disabled');
			}
		}

	}

	Calendar.prototype.setNoDate = function() {
		this.datesSelectEl.selectedIndex = 0;
		this.monthsSelectEl.selectedIndex = 0;
		this.yearsSelectEl.selectedIndex = 0;
		if (this.showTime) {
			this.hourSelectEl.selectedIndex = 0;
			this.minSelectEl.selectedIndex = 0;
		}

		if (this.hiddenInput != null && $(this.hiddenInput)) {
			$(this.hiddenInput).value = '';
		}

		this.renderDates();
	}

	Calendar.prototype.isNoDate = function() {
		return (!this.required) && (this.yearsSelectEl.selectedIndex == 0);
	}
	
	Calendar.prototype.setCurrentDate = function(newDate, hour, min) {

        var oldDate = this.currentDate;
    
		if (newDate == null && !this.required) {
			this.setNoDate();
			return true;
		}

		var canChange = true;
		if (this.onchange) {
			// onchange function is passed the new date, and should
			// return true if the new date is allowed
			canChange = this.onchange(newDate);
		}

		if (canChange) {
			this.currentDate = newDate;
			this.month = this.currentDate.month;
			this.year = this.currentDate.year;

			if (this.showTime && typeof hour != 'undefined' && typeof min != 'undefined') {
				if (hour == '00') {
					this.hour = 0;
				} else {
					hour = (hour.charAt(0)=='0'?hour.charAt(1):hour);
					this.hour = parseInt(hour);
				}
				if (min == '00') {
					this.min = 0;
				} else {
					min = (min.charAt(0)=='0'?min.charAt(1):min);
					this.min = parseInt(min);
				}

				for(var i=0; this.hourSelectEl.options.length; i++) {
					if (this.hourSelectEl.options[i].value == this.hour.toString()) {
						this.hourSelectEl.selectedIndex = i;
						break;
					}
				}
				for(var i=0; this.minSelectEl.options.length; i++) {
					if (this.minSelectEl.options[i].value == this.min.toString()) {
						this.minSelectEl.selectedIndex = i;
						break;
					}
				}
			}

            if (this.trySetWithoutRedraw && oldDate != null && oldDate.month == this.currentDate.month && oldDate.year == this.currentDate.year) {
            
                if (this.canHighlightDate && this.canHighlightDate(oldDate)) {             
                    this.currentDateCell.className = 'highlight';
                } else {
                    this.currentDateCell.className = 'normal';
                }
                
                this.currentDateCell = $('datecell_'+this.currentDate.toString());
                if (this.currentDateCell != null) {
                    this.currentDateCell.className = 'current';
                }
                
            } else {
			    this.renderDates();
			    this.updateControls(true);
            }
		} else {
			this.updateControls(true);
		}

		if (this.hiddenInput != null && $(this.hiddenInput)) {

			$(this.hiddenInput).value = this.getCurrentDateString();

		}

		if (canChange && this.onafterchange) this.onafterchange(this);
		
		return canChange;

	}
	
	Calendar.prototype.renderControls = function() {

		var i = 0;
		var divEl,selectEl;

		/* -------------------------- create the day/month/year controls --------------*/

		divEl = document.createElement("div");
		divEl.className = 'dateSelector';
		if (this.alwaysVisible) divEl.style.display = 'none';

		// create the day select list
		selectEl = document.createElement("select");
		selectEl.calendar = this;
		selectEl.onchange = function() {
			if (this.options.length) {
				if (!this.required && this.options[this.selectedIndex].value == '-123') {
					// the user chose a blank date, so set month and year too
					this.calendar.setNoDate();
				} else {
					var test = new CalendarDate(this.calendar.currentDate.year,this.calendar.currentDate.month,this.options[this.selectedIndex].value,this.calendar);
					this.calendar.setCurrentDate(test.getDateWithinRange(this.calendar.lowerDateLimit,this.calendar.upperDateLimit,this.calendar));
				}
			}
		}
		if (!this.required) {
			selectEl.options[selectEl.options.length] = new Option('','-123');
		}
		this.datesSelectEl = selectEl;
		divEl.appendChild(this.datesSelectEl);


		// create the month select list
		selectEl = document.createElement("select");
		selectEl.calendar = this;
		selectEl.onchange = function() {
			if (!this.required && this.options[this.selectedIndex].value == '-123') {
				// the user chose a blank date, so set month and year too
				this.calendar.setNoDate();
			} else {
				var test = new CalendarDate(this.calendar.currentDate.year,this.options[this.selectedIndex].value,this.calendar.currentDate.date,this.calendar);
				this.calendar.setCurrentDate(test.getDateWithinRange(this.calendar.lowerDateLimit,this.calendar.upperDateLimit,this.calendar));
			}
		}
		var op;
		if (!this.required) {
			selectEl.options[selectEl.options.length] = new Option('','-123');
		}
		for (i=1; i<=12; i++) {
			op = new Option(this.monthsShort[i],i);
			selectEl.options[selectEl.options.length] = op;
			this.monthOptionEls[i] = op;
			if (i == this.month) selectEl.selectedIndex = selectEl.options.length-1;
		}
		this.monthsSelectEl = selectEl;
		divEl.appendChild(this.monthsSelectEl);

		// create the year select list
		selectEl = document.createElement("select");
		selectEl.calendar = this;
		selectEl.onchange = function() {
			if (!this.required && this.options[this.selectedIndex].value == '-123') {
				// the user chose a blank date, so set month and year too
				this.calendar.setNoDate();
			} else {
				var test = new CalendarDate(this.options[this.selectedIndex].value,this.calendar.currentDate.month,this.calendar.currentDate.date,this.calendar);
				this.calendar.setCurrentDate(test.getDateWithinRange(this.calendar.lowerDateLimit,this.calendar.upperDateLimit,this.calendar));
			}
		}
		if (!this.required) {
			selectEl.options[selectEl.options.length] = new Option('','-123');
		}
		for (i=this.lowerDateLimit.year; i<=this.upperDateLimit.year; i++) {
			selectEl.options[selectEl.options.length] = new Option(i,i);
			if (i == this.year) selectEl.selectedIndex = selectEl.options.length-1;
		}
		this.yearsSelectEl = selectEl;
		divEl.appendChild(this.yearsSelectEl);

		// add calendar icon into span
		// add a button to show the calendar
		
		this.calendarButtonEl = document.createElement("span");
		if (this.alwaysVisible) this.calendarButtonEl.style.display = 'none';
		this.calendarButtonEl.innerHTML = '<img id="'+ this.id +'Icon" style="cursor:pointer;float:left;" src="onClick/Designs/Images/calendar.gif" width="16" height="17">';
		divEl.appendChild(this.calendarButtonEl); 

		//this.calendarButtonEl.style.cssFloat = 'left';
		//this.calendarButtonEl.style.styleFloat = 'left';

		
		// append the month and year
		this.el.appendChild(divEl);

		



		//this.calendarButtonEl.setAttribute('calendar',this);
		 this.calendarButtonEl.calendar = this; 




		this.calendarButtonEl.onclick = function() {
			if (this.calendar.datesSelectEl.disabled == false ) {
				this.calendar.calendarEl.style.top = getPageOffsetTop(this.calendar.datesSelectEl)+21;
				this.calendar.calendarEl.style.left = getPageOffsetLeft(this.calendar.datesSelectEl)-46;
				toggle(this.calendar.calendarEl);
/*				if (this.calendar.calendarEl.style.display == 'none') {
					SlideHeight(this.calendar.id+"_calendar",218,'');
					SlideTop(this.calendar.id+"_calendarTable",0,'');
				} else {
					SlideHeight(this.calendar.id+"_calendar",1,'none');
					SlideTop(this.calendar.id+"_calendarTable",-217,'none');
				}*/
			}
		}
		//this.el.appendChild(this.calendarButtonEl);


		this.calendarEl = document.createElement("div");
		this.calendarEl.id = this.id+'_calendar';
		this.calendarEl.className = 'calendar';
		if (!this.alwaysVisible) this.calendarEl.style.display = 'none';
		this.el.appendChild(this.calendarEl);


		// append the hour and minute
		if (this.showTime) {
			var divTimeEl = document.createElement("div");
			divTimeEl.className = 'timeSelector';

			// create the hour select list
			selectEl = document.createElement("select");
			selectEl.calendar = this;
			selectEl.className = 'hour';
			selectEl.onchange = function() {
				if (this.options.length) {
					if (!this.required && this.options[this.selectedIndex].value.length  == 0) {
						// the user chose a blank time
						this.calendar.hour = null;
					} else {
						this.calendar.hour = this.options[this.selectedIndex].value;
					}
				}
			}
			if (!this.required) {
				selectEl.options[selectEl.options.length] = new Option('--','');
			}
			this.hourSelectEl = selectEl;
			for (i=0; i<=23; i++) {

				op = new Option((i<10?'0'+i:i),i);
				selectEl.options[selectEl.options.length] = op;
				if (i == this.hour) selectEl.selectedIndex = selectEl.options.length-1;
			}

			divTimeEl.appendChild(this.hourSelectEl);
			var spanEl = document.createElement("span");
			spanEl.innerHTML = ': ';
			divTimeEl.appendChild(spanEl);


			// create the minute select list
			selectEl = document.createElement("select");
			selectEl.calendar = this;
			selectEl.onchange = function() {
				if (this.options.length) {
					if (!this.required && this.options[this.selectedIndex].value.length  == 0) {
						//this.calendar.setNoDate();
						this.calendar.min = null;
					} else {
						this.calendar.min = this.options[this.selectedIndex].value;
					}
				}
			}
			if (!this.required) {
				selectEl.options[selectEl.options.length] = new Option('--','');
			}
			this.minSelectEl = selectEl;
			for (i=0; i<=59; i++) {
				op = new Option((i<10?'0'+i:i),i);
				selectEl.options[selectEl.options.length] = op;
				if (i == this.min) selectEl.selectedIndex = selectEl.options.length-1;
			}

			divTimeEl.appendChild(this.minSelectEl);
			// append the time
			this.el.appendChild(divTimeEl);

		}
		/* -------------------------- create the calendar display controls --------------*/

		// create the month selection links
		var tableEl = document.createElement("table");

		var rowEl = document.createElement("tr");
		rowEl.className = 'controls';

		// add the previous
		if (this.nextAndPrev) {
			var tdEl = document.createElement("td");
			tdEl.className = 'nextAndBack';
			tdEl.innerHTML = '&lt;';
			tdEl.calendar = this;
			tdEl.onclick = function() {
				this.calendar.setMonth(parseInt(this.calendar.month,10)-1);
			}
			this.previousEl = tdEl;
			rowEl.appendChild(tdEl);
		}

		// add month and year cell
		var tdEl = document.createElement("td");
		tdEl.className = 'monthAndYear';
		if (this.nextAndPrev) {
			tdEl.colSpan = 5;
		} else {
			tdEl.colSpan = 7;
		}
		rowEl.appendChild(tdEl);


		var extraTableEl = document.createElement("table");
		extraTableEl.cellSpacing = 1;
		extraTableEl.cellPadding = 0;
		var extraBodyEl = document.createElement("tbody");
		var extraRowEl = document.createElement("tr");
		extraTableEl.appendChild(extraBodyEl);
		extraBodyEl.appendChild(extraRowEl);

		// create the month select list
		selectEl = document.createElement("select");
		selectEl.calendar = this;
		selectEl.onclick = function() {
			this.calendar.setMonth(this.options[this.selectedIndex].value);
		}
		var op;
		for (i=1; i<=12; i++) {
			if (this.useShortMonths) {
				op = new Option(this.monthsShort[i],i);
			} else {
				op = new Option(this.months[i],i);
			}
			selectEl.options[selectEl.options.length] = op;
			this.monthOptionEls[i] = op;
			if (i == this.month) selectEl.selectedIndex = selectEl.options.length-1;
		}
		this.calendarMonthsSelectEl = selectEl;

		var extraTdEl = document.createElement("td");
		extraTdEl.appendChild(selectEl);
		extraRowEl.appendChild(extraTdEl);



		// create the year select list
		selectEl = document.createElement("select");
		selectEl.calendar = this;
		selectEl.onclick = function() {
			this.calendar.setYear(this.options[this.selectedIndex].value);
		}
		for (i=this.lowerDateLimit.year; i<=this.upperDateLimit.year; i++) {
			selectEl.options[selectEl.options.length] = new Option(i,i);
			if (i == this.year) selectEl.selectedIndex = selectEl.options.length-1;
		}
		this.calendarYearsSelectEl = selectEl;
		extraTdEl = document.createElement("td");
		extraTdEl.appendChild(selectEl);
		extraRowEl.appendChild(extraTdEl);

		tdEl.appendChild(extraTableEl);


		// add the next
		if (this.nextAndPrev) {
			var tdEl = document.createElement("td");
			tdEl.className = 'nextAndBack';
			tdEl.innerHTML = '&gt;';
			tdEl.calendar = this;
			tdEl.onclick = function() {
				this.calendar.setMonth(parseInt(this.calendar.month,10)+1);
			}
			this.nextEl = tdEl;
			rowEl.appendChild(tdEl);
		}

		this.headerContainerEl.appendChild(rowEl);


		// add labels for the days of the week
		rowEl = document.createElement("tr");
		for (var i=0; i<this.daysShort.length; i++) {
			var thEl = document.createElement("th");
			if (this.useShorterDays) {
				thEl.innerHTML = this.daysShorter[i];
			} else {
				thEl.innerHTML = this.daysShort[i];
			}
			rowEl.appendChild(thEl);
		}
		this.headerContainerEl.appendChild(rowEl);



	}

	Calendar.prototype.renderDates = function() {

		var o = '';
		var empty = 0;
		var className,todayDate;
		var emptyEl,tableCellEl;

		var today = this.getDayOfWeek(this.year,this.month,1);
		var daysInMonth = this.getDaysInMonth(this.year,this.month);

		var table = this.datesContainerEl.parentNode;
		table.removeChild(this.datesContainerEl);
		this.datesContainerEl = document.createElement("tbody");
		var bodyEl = this.datesContainerEl;


//		this.datesContainerEl.innerHTML = '';

		// add some empty cells to get things started
		var tableRowEl = document.createElement("tr")
		for (empty = 0; empty < today; empty++) {
			emptyEl = document.createElement("td");
			emptyEl.className = "empty";
			tableRowEl.appendChild(emptyEl);
		}


		// draw the dates
		this.currentDateCell = null;

		this.dateOfUpcomingHighlight = null;

		for (var date = 1; date <= daysInMonth; date++) {

			tableCellEl = document.createElement("td");

			todayDate = new CalendarDate(this.year,this.month,date,this);
            tableCellEl.id = 'datecell_'+todayDate.toString();
            
			className = '';
			if (this.canHighlightDate && this.canHighlightDate(todayDate)) {
				className = 'highlight';

				if (this.dateOfUpcomingHighlight == null && todayDate.isAfterOrEqualTo(this.currentDate)) {
					this.dateOfUpcomingHighlight = todayDate;
				}
			}

			if (todayDate.isBefore(this.lowerDateLimit) || todayDate.isAfter(this.upperDateLimit)) {
				className = 'disabled';
			} else if (todayDate.isEqualTo(this.currentDate) && !this.isNoDate()) {
				className = 'current';
				this.currentDateCell = tableCellEl;
			} else {
				if (className != 'highlight') className = 'normal';
			}


			if (today == 0) {
				if (tableRowEl.childNodes.length) bodyEl.appendChild(tableRowEl);
				tableRowEl = document.createElement("tr");
			}
			tableCellEl.innerHTML = date;
			tableCellEl.className = className;
			tableCellEl.trueClassName = className;
			tableCellEl.calendar = this;
			tableCellEl.date = date;
			tableCellEl.onclick = function() {
				if ((this.calendar.canClickAny && this.className != 'disabled') || this.className == 'normal' || this.className == 'normalHover') {

					// update todays date (if we can)
                    var newDate = new CalendarDate(this.calendar.year,this.calendar.month,this.date,this.calendar);
					if (this.calendar.getCurrentDate.toString != newDate.toString() && this.calendar.setCurrentDate(newDate)) {

						// now hide the calendar if the date was set successfully
						if (!this.calendar.alwaysVisible) hide(this.calendar.calendarEl);
						if (this.calendar.onafterchangeclick) this.calendar.onafterchangeclick();

					}
				}
			}
			tableCellEl.onmouseover = function() {
				if (this.trueClassName == 'normal') this.className = 'normalHover';
				if (this.trueClassName == 'highlight') this.className = 'highlightHover';
			}
			tableCellEl.onmouseout = function() {
				this.className = this.trueClassName;
			}
            
            if (this.setDateOnMouseOver) {
                // If setting the date on mouseover, then copy from the onclick function
                // and remove the class changing stuff
                tableCellEl.onmouseover = tableCellEl.onclick;
                tableCellEl.onclick = this.onclickdate;
                tableCellEl.onmouseout = new Function();
            }
            
			tableRowEl.appendChild(tableCellEl);

			today++;
			if (today > 6) today = 0;
		}

		// add some more empty cells to finish things off, if we need it
		if (today != 0) {
			for (empty = today; empty < 7; empty++) {
				emptyEl = document.createElement("td");
				emptyEl.className = "empty";
				tableRowEl.appendChild(emptyEl);
			}
		}
		bodyEl.appendChild(tableRowEl);

		table.appendChild(bodyEl);

        this.onrenderdates();
        
	}

	Calendar.prototype.getDayOfWeek = function(year,month,day) {
		var date = new Date(year,month-1,day);
		return date.getDay();
	}

	Calendar.prototype.getDaysInMonth = function(year,month) {
		var dayCount = this.mtend[month];
		if (month == 2 && this.isLeapYear(year)) dayCount++;
		return dayCount;
	}

	Calendar.prototype.isLeapYear = function(year) {
		if (year % 4 != 0) return false;		// If its not divisible by 4, it IS NOT a leap year
		if (year % 100 != 0) return true;		// If it is divisible by 4 and not divisible by 100, it IS a leap year
		if (year % 400 == 0) return true;		// If it is divisible by 4, divisible by 100 and divisible by 400, it IS a leap year
		return false;					// If it is divisible by 4, divisible by 100 and not divisible by 400, it IS NOT a leap year
	}

	function CalendarDate(year,month,date,cal) {
		this.year = parseInt(year,10);
		this.month = parseInt(month,10);
		this.date = parseInt(date,10);

		// stop anyone being naughty :)
		if (cal && cal.getDaysInMonth(year,month) < this.date)	this.date =	cal.getDaysInMonth(year,month);

	}

	function CalendarDateFromString(date,cal) {	
			
		var p = date.split('-');
		if (p.length == 3) {
			return new CalendarDate(p[0],p[1],p[2],cal)
		}
		return null;
	}

	CalendarDate.prototype.isBefore = function(comp) {
		if (this.year < comp.year) return true;
		if (this.year > comp.year) return false;

		if (this.month < comp.month) return true;
		if (this.month > comp.month) return false;

		if (this.date < comp.date) return true;
		return false;
	}

	CalendarDate.prototype.isBeforeOrEqualTo = function(comp) {
		return (this.isBefore(comp) || this.isEqualTo(comp));
	}
	CalendarDate.prototype.isAfterOrEqualTo = function(comp) {
		return (this.isAfter(comp) || this.isEqualTo(comp));
	}


	CalendarDate.prototype.getDateWithinRange = function(lower,upper,cal) {
		if (this.isAfterOrEqualTo(lower) && this.isBeforeOrEqualTo(upper)) {
			return this;
		} else if (this.isBefore(lower)) {
			return new CalendarDate(lower.year,lower.month,lower.date,cal);
		} else if (this.isAfter(upper)) {
			return new CalendarDate(upper.year,upper.month,upper.date,cal);
		}
	}

	CalendarDate.prototype.isAfter = function(comp) {
		if (this.year > comp.year) return true;
		if (this.year < comp.year) return false;

		if (this.month > comp.month) return true;
		if (this.month < comp.month) return false;

		if (this.date > comp.date) return true;
		return false;
	}

	CalendarDate.prototype.isEqualTo = function(comp) {
		return (this.year == comp.year && this.month == comp.month && this.date == comp.date);
	}

	CalendarDate.prototype.isBetween = function(start,end,inclusive) {
		if (typeof inclusive == 'undefined') inclusive = true;
		if (inclusive) {
			return this.isBeforeOrEqualTo(end) && this.isAfterOrEqualTo(start);
		} else {
			return this.isBefore(end) && this.isAfter(start);
		}

	}



	CalendarDate.prototype.toString = function() {
		var month = this.month;
		var date = this.date;
		if (month < 10) month = '0'+month;
		if (date < 10) date = '0'+date;

		return this.year+'-'+month+'-'+date;
	}



	CalendarDate.prototype.dateDifference = function(newDate) {
		var currentDate = new Date(this.year, this.month-1, this.date);
		var compareDate = new Date(newDate.year, newDate.month-1, newDate.date);

		var one_day = 1000*60*60*24;

		return (currentDate.getTime()-compareDate.getTime())/one_day;

		//return (this.year == comp.year && this.month == comp.month && this.date == comp.date);
	}
