// (based on CodeProject contribution by Karl Agius)
//Example --
//	<div id="mycal"></div>
//	-- inline script after div (var name much match div id) --
//	var mycal = new Calendar("mycal", new Date());
//	mycal.eventDates = new Array("2006/4/1", "2006/4/2", "2006/4/8", "2006/5/15");
//	mycal.onclickevent = function(eventDate) { do something };
//	renderCalendar(mycal);

function Calendar(varName, date)
{
	// Read-only calendar
	this.viewOnly = false;
	
	// Allows the user to select Sundays
	this.allowSundays = true;
	
	// Allows the user to select weekends
	this.allowWeekends = true;
	
	// Allows the user to select weekdays
	this.allowWeekdays = true;
	
	// The minimum date that the user can select (inclusive)
	this.minDate = "--";
	
	// The maximum date that the user can select (exclusive)
	this.maxDate = "--";
	
	// Allow the user to scroll dates
	this.scrolling = true;
	
	// The variable name of this calendar object
	this.name = varName;
	
	// The first day of the week in the calendar (0-Sunday, 6-Saturday)
	this.firstDayOfWeek = 0;
	
	// Sets the date and strips out time information
	this.calendarDate = date;
	this.calendarDate.setUTCHours(0);
	this.calendarDate.setUTCMinutes(0);
	this.calendarDate.setUTCSeconds(0);
	this.calendarDate.setUTCMilliseconds(0);
	
	// The left and right month control icons
	this.controlLeft = "&#171;";
	this.controlRight = "&#187;";
		
	// The left and right month control icons (when disabled)
	this.controlLeftDisabled = "";
	this.controlRightDisabled = "";
	
	// The css classes for the calendar and header
	this.calendarStyle = "font-size:10pt;font-family:verdana;padding:0px;margin:0px;border:none; border-collapse:collapse;";
	this.headerStyle = "background-color:#bbbbbb;padding:0px;margin:0px;border:none; border-collapse:collapse;";
	this.headerCellStyle = "padding:2px;margin:1px;text-align:center;width:4ex;cursor:pointer;";
	this.headerCellStyleLabel = "padding:2px;margin:1px;text-align:center;";
	
	// The css classes for the rows
	this.evenWeekStyle = "background-color:#eeeeee;padding:0px;margin:0px;border:none; border-collapse:collapse;cursor:pointer;";
	this.oddWeekStyle = "background-color:#dddddd;padding:0px;margin:0px;border:none; border-collapse:collapse;cursor:pointer;";
	
	// The css classes for the day elements
	this.dayStyle = "width:3ex; text-align:center; padding:0px; margin:0px; border:none; border-collapse:collapse;";
	this.disabledDayStyle = "color:#999999; width:3ex; padding:0px; margin:0px; border:none; border-collapse:collapse;";
	this.commonDayStyle = "color:black; width:3ex; padding:0px; margin:0px; border:none; border-collapse:collapse;";
	this.holidayDayStyle = "color:red; width:3ex; padding:0px; margin:0px; border:none; border-collapse:collapse;";
	this.eventDayStyle = "background-color:#333333; color:white; width:3ex; padding:0px; margin:0px; border:none; border-collapse:collapse;";
	this.todayDayStyle = "color:black; font-weight:bold; width:3ex; padding:0px; margin:0px; border:none; border-collapse:collapse;";
	this.weekendTodayDayStyle = "color:red; font-weight:bold; width:3ex; padding:0px; margin:0px; border:none; border-collapse:collapse;";
	this.eventTodayDayStyle = "background-color:#333333; color:white; font-weight:bold; width:3ex; padding:0px; margin:0px; border:none; border-collapse:collapse;";
	
	// specifies the labels for this calendar
	this.dayLabels = new Array("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat");
	this.monthLabels = new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
	
	this.eventDates = new Array();
	
	onclickevent = new Function();
	ondatechange = new Function();
}

function getFirstCalendarDate(calendar)
{
	return new Date (calendar.calendarDate.getUTCFullYear(), calendar.calendarDate.getUTCMonth(), 1);
}

function renderCalendar(calendar)
{
	var calHtml =  "<table id=\"cal_" + calendar.name + "\" style=\"" + calendar.calendarStyle +"\">";
	calHtml += (calendar.scrolling ? buildHeader(calendar) : buildStaticHeader(calendar));
	calHtml += buildCalendarTable(calendar);
	calHtml += "</table>";
	
	document.getElementById(calendar.name).innerHTML = calHtml;
}

function scrollMonthBack(calendar)
{
	calendar.calendarDate.setUTCMonth(calendar.calendarDate.getUTCMonth() - 1);
	calendar.ondatechange(calendar.calendarDate);
	renderCalendar(calendar);
}

function selectDate(calendar, day)
{
	if (!calendar.viewOnly)
	{
		calendar.calendarDate.setUTCDate(day);
		calendar.ondatechange(calendar.calendarDate);
		renderCalendar(calendar);
	}
}

function selectFullDate(calendar, year, month, day)
{
	if (!calendar.viewOnly)
	{
		calendar.calendarDate = new Date(year, month - 1, day);
		calendar.ondatechange(calendar.calendarDate);
		renderCalendar(calendar);
	}
}

function scrollMonthForward(calendar)
{
	calendar.calendarDate.setUTCMonth(calendar.calendarDate.getUTCMonth() + 1);
	calendar.ondatechange(calendar.calendarDate);
	renderCalendar(calendar);
}

function buildHeader(calendar)
{

	var enableLeft = true;
	var enableRight = true;
	
	if (calendar.minDate != "--") 
	{
		if (calendar.calendarDate.getUTCFullYear() <= calendar.minDate.getUTCFullYear())
		{
			if (calendar.calendarDate.getUTCMonth() <= calendar.minDate.getUTCMonth())
				enableLeft = false;
		}
	}

	if (calendar.maxDate != "--") 
	{
		if (calendar.calendarDate.getUTCFullYear() >= calendar.maxDate.getUTCFullYear())
		{
			if (calendar.calendarDate.getUTCMonth() >= calendar.maxDate.getUTCMonth())
				enableRight = false;
		}
	}

	var calHtml =  "<tr style=\"" + calendar.headerStyle + "\">";
	calHtml += "<td style=\"" + calendar.headerCellStyle + (enableLeft ? ("\" onclick=\"scrollMonthBack(" + calendar.name + ")") : "") + "\">" + ((enableLeft)?calendar.controlLeft:calendar.controlLeftDisabled) + "</td>";
	calHtml += "<td colspan=\"5\" style=\"font-weight:bold; " + calendar.headerCellStyleLabel + "\">" + calendar.monthLabels[calendar.calendarDate.getUTCMonth()] + "  " + calendar.calendarDate.getUTCFullYear() + "</td>";
	calHtml += "<td style=\"" + calendar.headerCellStyle + (enableRight ? ("\" onclick=\"scrollMonthForward(" + calendar.name + ")") : "") + "\">" + ((enableRight)?calendar.controlRight:calendar.controlRightDisabled) + "</td>";
	calHtml += "</tr>";
	calHtml += "<tr style=\"" + calendar.headerStyle + "\">";

	for (i = 0; i < 7; i++)
	{
		var showDay = i + calendar.firstDayOfWeek;
		if (showDay > 6) showDay = showDay - 7;
		calHtml += "<td style=\"" + calendar.headerCellStyle + "\">" + calendar.dayLabels[showDay] + "</td>";
	}

	calHtml += "</tr>";

	return calHtml;
}

function buildStaticHeader(calendar)
{
	var calHtml =  "<tr style=\"" + calendar.headerStyle + "\">";
	calHtml += "<td colspan=\"7\" style=\""+ calendar.headerCellStyleLabel + "\">" + calendar.monthLabels[calendar.calendarDate.getUTCMonth()] + ", " + calendar.calendarDate.getUTCFullYear() + "</td>";	
	calHtml += "</tr>";
	calHtml += "<tr style=\"" + calendar.headerStyle + "\">";

	for (i = 0; i < 7; i++)
	{
		var showDay = i + calendar.firstDayOfWeek;
		if (showDay > 6) showDay = showDay - 7;
		calHtml += "<td style=\"" + calendar.headerCellStyle + "\">" + calendar.dayLabels[showDay] + "</td>";
	}

	calHtml += "</tr>";

	return calHtml;
}




function RenderDayDisabled(calendar, currentDate)
{
	var calHtml = "<td>";
	calHtml += "<span style=\"" + calendar.disabledDayStyle + "\">";
	calHtml += currentDate.getUTCDate();
	calHtml += "</span>";
	calHtml += "</td>";
	
	return calHtml;
}

function RenderDayEnabled(calendar, currentDate, dayStyle)
{
	var calHtml = "<td>";
	calHtml += "<span style=\"" + dayStyle + "\" onclick=\"selectDate(" + calendar.name + ", " + currentDate.getUTCDate() + ")\">";
	calHtml += currentDate.getUTCDate();
	calHtml += "</span>";
	calHtml += "</td>";
	
	return calHtml
}

function RenderDayEvent(calendar, currentDate, dayStyle, eventDate)
{
	var calHtml = "<td>";
	calHtml += "<span style=\"" + dayStyle + "\" onclick=\"selectDate(" + calendar.name + ", " + currentDate.getUTCDate() + "); " + calendar.name + ".onclickevent('" + eventDate + "')\">";
	calHtml += currentDate.getUTCDate();
	calHtml += "</span>";
	calHtml += "</td>";
	
	return calHtml;
}

function buildCalendarTable(calendar)
{
	var currentDate = getFirstCalendarDate(calendar);
	var odd = 0;
	while (currentDate.getUTCDay() != calendar.firstDayOfWeek)
		currentDate.setUTCDate(currentDate.getUTCDate() - 1);

	var calHtml = "";
	do
	{
		odd += 1;

		calHtml += "<tr style=\"" + (((odd%2)==0) ? calendar.evenWeekStyle : calendar.oddWeekStyle) + "\">";

		for (i = 0; i < 7; i++)
		{
			var month = currentDate.getUTCMonth()+1;
			var day = currentDate.getUTCDate();
			if (month < 10)
				month = "0" + month;
			if (day < 10)
				day = "0" + day;

			var currentDateString = currentDate.getUTCFullYear() + "/" + month + "/" + day;
			var isWeekend = (currentDate.getUTCDay() == 0) || (currentDate.getUTCDay() == 6);

			if (calendar.minDate != "--" && currentDate < calendar.minDate) 
			{
				calHtml += RenderDayDisabled (calendar, currentDate);
			} 
			else if (calendar.maxDate != "--" && currentDate > calendar.maxDate) 
			{
				calHtml += RenderDayDisabled (calendar, currentDate);
			} 
			else if (currentDate.getUTCMonth() != calendar.calendarDate.getUTCMonth()) // day not in month
			{
				calHtml += RenderDayDisabled (calendar, currentDate);
			}
			else if (currentDate.getUTCDate() == calendar.calendarDate.getUTCDate()) // today's date
			{
				if (isWeekend)
				{
					if ((calendar.allowWeekends == true && calendar.allowSundays == true) ||
						(calendar.allowWeekends == true && currentDate.getUTCDay() == 6))
					{
						var style = calendar.weekendTodayDayStyle;

						for (j=0; j < calendar.eventDates.length; j++)
						{
							if (calendar.eventDates[j] == currentDateString) 
							{
								style = calendar.eventTodayDayStyle;
								calHtml += RenderDayEvent (calendar, currentDate, style, calendar.eventDates[j]);
							}
						}

						if (style == calendar.weekendTodayDayStyle)
						{
							calHtml += RenderDayEnabled (calendar, currentDate, style);
						}
					} 
					else 
					{
						calHtml += RenderDayDisabled (calendar, currentDate);	
						var month = calendar.calendarDate.getUTCMonth();
						calendar.calendarDate.setUTCDate(calendar.calendarDate.getUTCDate()+1);
						if (month != calendar.calendarDate.getUTCMonth())
						{
							renderCalendar(calendar);
						}
						calendar.ondatechange(calendar.calendarDate);
					}
				}
				else
				{
					if (calendar.allowWeekdays == true)
					{
						var style = calendar.todayDayStyle;

						for (j=0; j < calendar.eventDates.length; j++)
						{
							if (calendar.eventDates[j] == currentDateString) 
							{
								style = calendar.eventTodayDayStyle;
								calHtml += RenderDayEvent (calendar, currentDate, style, calendar.eventDates[j]);
							}
						}

						if (style == calendar.todayDayStyle)
						{
							calHtml += RenderDayEnabled (calendar, currentDate, style);
						}
					} 
					else 
					{
						calHtml += RenderDayDisabled (calendar, currentDate);	
						var month = calendar.calendarDate.getUTCMonth();
						calendar.calendarDate.setUTCDate(calendar.calendarDate.getUTCDate()+1);
						if (month != calendar.calendarDate.getUTCMonth())
						{
							renderCalendar(calendar);
						}
						calendar.ondatechange(calendar.calendarDate);
					}
				}
			}
			else if (isWeekend)
			{
				if (calendar.allowWeekends == true)
				{
				
					var style = calendar.holidayDayStyle
					
					for (j=0; j < calendar.eventDates.length; j++)
					{
						if (calendar.eventDates[j] == currentDateString) 
						{
							style = calendar.eventDayStyle;
							calHtml += RenderDayEvent (calendar, currentDate, style, calendar.eventDates[j]);
						}
					}
					
					if (style == calendar.holidayDayStyle)
					{
						calHtml += RenderDayEnabled (calendar, currentDate, style);
					}
				} 
				else 
				{
					calHtml += RenderDayDisabled (calendar, currentDate);	
				}
			}
			else
			{
				if (calendar.allowWeekdays == true)
				{
					var style = calendar.commonDayStyle

					for (j=0; j < calendar.eventDates.length; j++)
					{
						if (calendar.eventDates[j] == currentDateString) 
						{
							style = calendar.eventDayStyle;
							calHtml += RenderDayEvent (calendar, currentDate, style, calendar.eventDates[j]);
						}
					}

					if (style == calendar.commonDayStyle)
					{
						calHtml += RenderDayEnabled (calendar, currentDate, style);
					}
				} 
				else 
				{
					calHtml += RenderDayDisabled (calendar, currentDate);	
				}
			}

			currentDate.setUTCDate(currentDate.getUTCDate() + 1);	
		}
		
		calHtml += "</tr>";
		

	} while (currentDate.getUTCMonth() == calendar.calendarDate.getUTCMonth());

	return calHtml;
}
