
Date.prototype.getFirstDayOfYear = function () {
	return new Date(this.getFullYear(),0,1);
}

Date.prototype.getWeekDay = function () {
	return (this.getDay()==0) ? 7 : this.getDay();
}
Date.prototype.isLeapYear = function () {
	return new Date(this.getFullYear(),2-1,29).getDate()==29;
}
Date.prototype.getDaysFromNewYear = function () {
	var newYear = new Date(this.getFullYear(),0,0);
	return (this - newYear) / 86400000;
}
Date.prototype.getWeek = function() {
	var onejan = new Date(this.getFullYear(),0,1);
	return Math.ceil((((this - onejan) / 86400000) + onejan.getDay())/7);
}
Date.prototype.getLastDayInMonth = function () {
	return 32 - new Date(this.getFullYear(), this.getMonth(), 32).getDate();
}
Date.prototype.getFirstWeekOfMonth = function () {
	var day = new Date (this.getFullYear(),this.getMonth(),1);
	return day.getWeek();
}
Date.prototype.getLastWeekOfMonth = function () {
	var day = new Date (this.getFullYear(),this.getMonth(),this.getLastDayInMonth());
	return day.getWeek();
}


var dCurrentDate = new Date(0);


function JSCalendar (dDate) {

	if (typeof dDate == 'undefined') dDate = new Date();
	if (typeof JSCalendarTarget == 'undefined') return;

	var mDay	= 0;
	var mMonth	= 0;
	var mYear	= 0;

	var mDaysMonth;
	var mDayNames;

	var mOutput	= "";



	function _date_navigation () {

		mOutput += '<tr class="calendar-navigation">';
		mOutput += '<td colspan="2" class="calendar-prev-month"><a unselectable="on" onclick="JSCalendar(new Date ('+(mYear)+','+(mMonth-1)+','+(mDay)+'));">&#139; Previous Month</a></td>'
				+ '<td colspan="3" class="calendar-current-month">'
      			+ mMonthNames[mDate.getMonth()]
      			+ ' '
      			+ mDate.getFullYear()
      			+ '</td>';
		mOutput += '<td colspan="2" class="calendar-next-month"><a unselectable="on" onclick="JSCalendar(new Date ('+(mYear)+','+(mMonth+1)+','+(mDay)+'));">Next Month &#155;</a></td>';
		mOutput += "</tr>";
	}

	function _table_open () {

		mOutput += '<table cellpadding="0" cellspacing="0">';

		_date_navigation ();

		for (var i=1; i<=7; i++) {
			mOutput += '<td class="calendar-weekday" unselectable="on">'+mDayNames[i]+'</td>';
		}
		mOutput += '</tr>';
	}

	function _table_close () {

		mOutput += "</table>";
	}

	function _new_cell (calDay) {

		var cellClass = "";

		if (calDay.getWeekDay()==6 || calDay.getWeekDay()==7) {
			if (calDay.getMonth()==mMonth) {
				cellClass = "calendar-weekend";
			} else {
				mOutput += '<td><a>&nbsp;</a></td>';
				return;
				cellClass = "calendar-weekend-not-in-month";
			}
		} else {
			if (calDay.getMonth()==mMonth) {
				cellClass = "calendar-workday";
			} else {
				mOutput += '<td><a>&nbsp;</a></td>';
				return;
				cellClass = "calendar-workday-not-in-month";
			}
		}

		var dToday = new Date();
		if (calDay.getDate()==dToday.getDate() && calDay.getFullYear()==dToday.getFullYear() && calDay.getMonth()==dToday.getMonth()) {
			cellClass = "calendar-today";
		}

		if (typeof dCurrentDate != 'undefined') {
			if (calDay.getDate()==dCurrentDate.getDate() && calDay.getFullYear()==dCurrentDate.getFullYear() && calDay.getMonth()==dCurrentDate.getMonth()) {
				cellClass = "calendar-selected";
			}
		}

		var bDateEvent = false;
		var aDateEvents = new Array();
		for (var i=0; i<aEvents.length; i++) {
			if(aEvents[i][0] <= calDay.getTime()/1000 && aEvents[i][1] >= calDay.getTime()/1000) {
				cellClass = cellClass + " calendar-event";
				bDateEvent = true;
				aDateEvents[aDateEvents.length] = aEvents[i][2];
			}
		}

		var sDateOnclickEvent = 'calendar_show_events(\''+aDateEvents.join(',')+'\');';
		var sDateOnClick = 'onclick="dCurrentDate=new Date('+calDay.getFullYear()+','+calDay.getMonth()+','+calDay.getDate()+');JSCalendar(new Date('+calDay.getFullYear()+','+calDay.getMonth()+','+calDay.getDate()+'));'+sDateOnclickEvent+'return false;"';
		var sDateOnHover = '';
		var sDateOnMouseOut = '';
		var sDateTitle = (bDateEvent) ? 'title="Click to view events for this date"' : '';

		mOutput += '<td class="'+cellClass+' calendar-valid-day"><a href="#" '+sDateOnClick+' '+sDateOnHover+' '+sDateOnMouseOut+' '+sDateTitle+' unselectable="on">' + calDay.getDate() + "</a></td>";
	}



	if (typeof dDate == 'undefined') {
		dDate = new Date ();
	}

	var mDate	= dDate;

	var mDay 	= mDate.getDate();
	var mMonth 	= mDate.getMonth();
	var mYear 	= mDate.getFullYear();

	var mDayNames = Array ("","M","T","W","T","F","S","S");
	var mMonthNames = Array ("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");

	// find any date in specific month
	var dateInMonth	= new Date(mYear,mMonth,15);
	// find first and last week in month
	var firstWeek	= dateInMonth.getFirstWeekOfMonth();
	var lastWeek	= dateInMonth.getLastWeekOfMonth();
	// find out how many days are in year
	var daysInYear	= (dateInMonth.isLeapYear()) ? 366 : 365;
	// find out a first and last year day position in week
	var firstDayPosInWeek = new Date(mYear,0,1).getWeekDay();
	var lastDayPosInWeek = new Date(mYear,11,31).getWeekDay();

	// initiate table
	_table_open ();

	// draw days from the previous year and the same week as first of this year
	for (var i=-firstDayPosInWeek+2; i<=0 && 0==mMonth; i++) {

		calDay = new Date (mYear, 0, i);
		// week number - always 1
		// cell with date
		_new_cell (calDay);
	}

	// draw days only from specific month
	for (var i=1; i<=daysInYear; i++) {

		var calDay = new Date (mYear, 0, i);
		// draw day if it belongs in specific month or first or last week of month
		if (calDay.getMonth()==mMonth || calDay.getWeek()==firstWeek || calDay.getWeek()==lastWeek) {
			// week number
			if (calDay.getWeekDay()==1) mOutput += '<tr class="calendar-days">'
			// cell with date
			_new_cell (calDay);
			// begin new row after Sunday
			if (calDay.getWeekDay()==7) mOutput += '</tr>';
		}
	}

	// draw days from the next year and the same week as first of this year
	for (var i=1; i<=7-lastDayPosInWeek && 11==mMonth; i++) {

		calDay = new Date (mYear+1, 0, i);
		// cell with date
		_new_cell (calDay);
	}

	// close table
	_table_close ();

	JSCalendarTarget.innerHTML = mOutput;
}
