﻿function Calendar(containerID)
{
	this.containerID = containerID;
	this.outerTableID = "Calendar";
	this.innerTableID = "CalendarInner";
	this.headerTableID = "HeaderTable";
		
	this.outerTable = null;
	this.innerTable = null;
	this.calendarContainer = null;
	
	this.previousMonthCell = null;
	this.monthNameCell = null;
	this.nextMonthCell = null;
	this.headerLeftCell = null;
	this.headerRightCell = null;

	this.currentDate = new Date();
	this.previousDate = new Date();
	this.previousDate.setTime(1);
	this.monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
	this.dayNames = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
	this.clickRefs = new Array(35);
	this.changedDateListeners = new Array();
	this.changedMonthListeners = new Array();
	this.enablePreviousDates = true;
	this.showDatesFromOtherMonths = false;

	this.noBackground = false;
	this.showTopHeader = false;
}

Calendar.prototype.initialize = function()
{
	var container = S.Get(this.containerID);

	// Add outer table
	var outerTable = document.createElement("table");
	outerTable.id = this.outerTableID;
	outerTable.setAttribute("cellPadding", "0");
	outerTable.setAttribute("cellSpacing", "0");
	outerTable.className = this.noBackground ? "Calendar CalendarNoBg" : "BoxRound Calendar";

	var tableContainer = null;

	if (blnIE)
	{
		var tbody = document.createElement("tbody");
		outerTable.appendChild(tbody);

		tableContainer = tbody;
	}
	else
		tableContainer = outerTable;

	var row = document.createElement("tr");
	var cell = document.createElement("td");

	if (this.showTopHeader)
	{
		row.id = "Header";

		cell.setAttribute("colSpan", "5");
		cell.id = "HeaderCell";
		row.appendChild(cell);

		tableContainer.appendChild(row);

		// Add header table
		var headerTable = document.createElement("table");
		headerTable.setAttribute("cellPadding", "0");
		headerTable.setAttribute("cellSpacing", "0");
		headerTable.id = this.headerTableID;

		var headerTableContainer = null;

		if (blnIE)
		{
			var tbody = document.createElement("tbody");
			headerTable.appendChild(tbody);

			headerTableContainer = tbody;
		}
		else
			headerTableContainer = headerTable;		

		var headerRow = document.createElement("tr");

		var leftCell = document.createElement("td");
		leftCell.id = "HeaderLeftCell";
		this.headerLeftCell = leftCell;

		var rightCell = document.createElement("td");
		rightCell.id = "HeaderRightCell";
		this.headerRightCell = rightCell;

		headerRow.appendChild(leftCell);
		headerRow.appendChild(rightCell);

		headerTableContainer.appendChild(headerRow);

		cell.appendChild(headerTable);

		// Prepare next row and cell
		row = document.createElement("tr");
		cell = document.createElement("td");
	}

	row.id = "Top";

	cell.className = "Left";
	row.appendChild(cell);

	cell = document.createElement("td");
	cell.setAttribute("colSpan", "3");
	row.appendChild(cell);

	cell = document.createElement("td");
	cell.className = "Right";
	row.appendChild(cell);

	tableContainer.appendChild(row);

	row = document.createElement("tr");
	row.id = "Content";

	cell = document.createElement("td");
	cell.className = "Left";
	row.appendChild(cell);

	cell = document.createElement("td");
	cell.id = "PreviousMonthCell";
	var p = document.createElement("div");
	cell.appendChild(p);
	this.previousMonthCell = cell;
	S.Event.add(this.previousMonthCell, "click", this.gotoPreviousMonth.bind(this));
	row.appendChild(cell);

	cell = document.createElement("td");
	cell.id = "MonthNameCell";
	this.monthNameCell = cell;
	row.appendChild(cell);

	cell = document.createElement("td");
	cell.id = "NextMonthCell";
	p = document.createElement("div");
	cell.appendChild(p);
	this.nextMonthCell = cell;
	S.Event.add(this.nextMonthCell, "click", this.gotoNextMonth.bind(this));
	row.appendChild(cell);

	cell = document.createElement("td");
	cell.className = "Right";
	row.appendChild(cell);

	tableContainer.appendChild(row);

	row = document.createElement("tr");

	cell = document.createElement("td");
	cell.setAttribute("colSpan", "5");
	cell.className = "Spacer";
	row.appendChild(cell);

	tableContainer.appendChild(row);

	row = document.createElement("tr");
	row.id = "Inner";

	cell = document.createElement("td");
	cell.setAttribute("colSpan", "5");
	cell.id = "CalendarContainer";
	this.calendarContainer = cell;
	row.appendChild(cell);

	tableContainer.appendChild(row);

	row = document.createElement("tr");
	row.id = "Bottom";

	cell = document.createElement("td");
	cell.className = "Left";
	row.appendChild(cell);

	cell = document.createElement("td");
	cell.setAttribute("colSpan", "3");
	row.appendChild(cell);

	cell = document.createElement("td");
	cell.className = "Right";
	row.appendChild(cell);

	tableContainer.appendChild(row);

	this.updateCalendar(true);

	container.appendChild(outerTable);
	this.outerTable = S.Get(this.outerTableID);
	this.innerTable = S.Get(this.innerTableID);
}

Calendar.prototype.updateCalendar = function(addElements, dontNotifyListeners)
{
	var tableContainer;
	var innerTable;

	if (addElements)
	{
		// Add inner table
		innerTable = document.createElement("table");
		innerTable.id = this.innerTableID;
		innerTable.setAttribute("cellPadding", "0");
		innerTable.setAttribute("cellSpacing", "0");
		innerTable.className = this.noBackground ? "CalendarInner CalendarInnerNoBg" : "CalendarInner";

		if (blnIE)
		{
			var tbody = document.createElement("tbody");
			innerTable.appendChild(tbody);

			tableContainer = tbody;
		}
		else
			tableContainer = innerTable;
	}

	var previousMonthDate = this.getPreviousMonth();
	var daysInPreviousMonth = this.getDaysInMonth(this.currentDate);
	var daysInCurrentMonth = this.getDaysInMonth(this.currentDate);
	var tempDate = new Date();
	tempDate.setTime(this.currentDate.getTime());
	tempDate.setDate(1);

	var firstDayInCurrentMonth = tempDate.getDay();
	var previousMonthShownDaysCount = firstDayInCurrentMonth == 0 ? 6 : firstDayInCurrentMonth;

	var onlyDayChanged = this.previousDate.getMonth() == this.currentDate.getMonth() && this.previousDate.getFullYear() == this.currentDate.getFullYear();

	var firstRow = true;
	var dayCounter = 1;
	var dateCounter = 0;
	var nextMonthDateCounter = 0;
	var outerCellCounter = 0;

	if (this.showTopHeader)
	{
		this.headerLeftCell.innerHTML = this.dayNames[this.currentDate.getDay()];
		this.headerRightCell.innerHTML = parseInt(this.currentDate.getDate()) > 9 ? this.currentDate.getDate() : "0" + this.currentDate.getDate();
	}

	for (var rowCounter = 1; rowCounter < 7; rowCounter++)
	{
		if (addElements)
			var row = document.createElement("tr");

		for (var cellCounter = 1; cellCounter < 8; cellCounter++)
		{
			var td;
			var text = "";
			var cellID = "Cell" + rowCounter + "-" + cellCounter;
			outerCellCounter++;

			if (addElements)
			{
				td = document.createElement("td");
				td.innerHTML = cellCounter;
				td.id = cellID;
			}
			else
			{
				td = S.Get(cellID);
			}

			if (firstRow && cellCounter <= previousMonthShownDaysCount-1)
			{
				td.className = "Inactive";

				if (this.showDatesFromOtherMonths)
				{
					text = (daysInPreviousMonth - cellCounter);
				}
			}
			else
			{
				if (nextMonthDateCounter > 0 || (dateCounter + 1) > daysInCurrentMonth)
				{
					nextMonthDateCounter++;
					td.className = "Inactive";

					if (this.showDatesFromOtherMonths)
					{
						text = nextMonthDateCounter;
					}
				}
				else
				{
					dateCounter++;

					var clickRef = this.clickRefs[outerCellCounter];

					if (clickRef)
					{
						S.Event.remove(td, "click", clickRef);
					}

					var cellDate = new Date();
					cellDate.setTime(this.currentDate.getTime());
					cellDate.setDate(dateCounter);

					if (!this.enablePreviousDates && this.dateIsPassed(cellDate))
					{
						td.className = "Inactive";
					}
					else
					{
						clickRef = this.gotoDay.bind(this, dateCounter);
						S.Event.add(td, "click", clickRef);
						this.clickRefs[outerCellCounter] = clickRef;

						td.className = this.currentDate.getDate() == dateCounter ? "Active" : "";
					}

					text = dateCounter;
				}
			}

			td.innerHTML = text;

			if (addElements)
				row.appendChild(td);
		}

		firstRow = false;

		if (addElements)
			tableContainer.appendChild(row);
	}

	if (addElements)
		this.calendarContainer.appendChild(innerTable);

	this.monthNameCell.innerHTML = this.currentMonthName() + " " + this.currentYear();

	if (!addElements && !dontNotifyListeners)
	{
		for (var i = 0; i < this.changedDateListeners.length; i++)
			this.changedDateListeners[i](this.currentDate);
	}
}

Calendar.prototype.addChangedDateListener = function(functionRef)
{
	this.changedDateListeners.push(functionRef);
}

Calendar.prototype.addChangedMonthListener = function(functionRef)
{
	this.changedMonthListeners.push(functionRef);
}

Calendar.prototype.getPreviousMonth = function()
{
	var previousMonthDate = new Date();
	previousMonthDate.setTime(this.currentDate.getTime());
	
	if (previousMonthDate.getMonth() > 0)
	{
		previousMonthDate.setMonth(previousMonthDate.getMonth() - 1);
	}
	else
	{
		previousMonthDate.setYear(previousMonthDate.getFullYear() - 1);
		previousMonthDate.setMonth(11);
	}
	
	return previousMonthDate;
}

Calendar.prototype.getNextMonth = function()
{
	var previousMonthDate = new Date();
	previousMonthDate.setTime(this.currentDate.getTime());
	
	if (previousMonthDate.getMonth() < 11)
	{
		previousMonthDate.setMonth(previousMonthDate.getMonth() + 1);
	}
	else
	{
		previousMonthDate.setYear(previousMonthDate.getFullYear() + 1);
		previousMonthDate.setMonth(0);
	}
	
	return previousMonthDate;
}

Calendar.prototype.gotoNextMonth = function()
{
	this.previousDate.setTime(this.currentDate.getTime());
	this.currentDate = this.getNextMonth();
	this.currentDate.setDate(1);
	this.updateCalendar(false, true);

	for (var i = 0; i < this.changedMonthListeners.length; i++)
		this.changedMonthListeners[i](this.currentDate);
}

Calendar.prototype.gotoPreviousMonth = function()
{
	var checkDate = new Date();
	checkDate.setTime(this.currentDate.getTime());
	checkDate.setDate(1);
	checkDate.setHours(0,0,0,0);
	
	var date = new Date();
	date.setDate(1);
	date.setHours(0,0,0,0);
	
	var diff = (date.getTime() - checkDate.getTime());
	
	if (diff == 0)
		return;
		
	this.previousDate.setTime(this.currentDate.getTime());
	this.currentDate = this.getPreviousMonth();
	
	var currentMonth = (this.currentDate.getMonth() == date.getMonth());			
	var day = 1;
	
	if (currentMonth)
	{
		date = new Date();
		day = date.getDate();
	}
	
	this.currentDate.setDate(day);
	this.updateCalendar(false, true);

	for (var i = 0; i < this.changedMonthListeners.length; i++)
		this.changedMonthListeners[i](this.currentDate);	
}

Calendar.prototype.gotoDay = function(day)
{
	this.previousDate.setTime(this.currentDate.getTime());
	this.currentDate.setDate(day);
	this.updateCalendar(false);
}

Calendar.prototype.gotoDate = function(time)
{
	this.previousDate.setTime(this.currentDate.getTime());
	this.currentDate.setTime(time);
	this.updateCalendar(false);
}

Calendar.prototype.getDaysInMonth = function(date)
{
	return[31,(this.isLeapYear(date.getFullYear())?29:28),31,30,31,30,31,31,30,31,30,31][date.getMonth()];
}

Calendar.prototype.isLeapYear = function(year)
{
	return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
}

Calendar.prototype.dateIsPassed = function (checkDate)
{
	checkDate.setHours(0, 0, 0, 0);
	
	var date = new Date();
	date.setHours(0, 0, 0, 0);	
	
	var diff = (date.getTime() - checkDate.getTime());
	
	return diff > 0;
}

Calendar.prototype.currentDay = function()
{
	return this.currentDate.getDate();
}

Calendar.prototype.currentMonthName = function()
{
	return this.monthNames[this.currentDate.getMonth()];
}

Calendar.prototype.currentYear = function()
{
	return this.currentDate.getFullYear();
}