// JavaScript Document for Calendars

function modulus(number, divisor) {
	result=number-Math.floor(number/divisor)*divisor;
	return result;
}

// Returns a new Date object
// Set to midnight of the stored day
Date.prototype.getMidnight=function() {
	result=new Date(this.getFullYear(), this.getMonth(), this.getDate());
	return result;
}

// Returns a new Date object
// Set to the first day (Sunday) of the current value's week.
Date.prototype.getStartOfWeek=function() {
	return new Date(this.getFullYear(), this.getMonth(), this.getDate()-this.getDay());
}

// Returns a new Date object
// Set to the last day (Sunday) of the current value's week.
Date.prototype.getEndOfWeek=function() {
	return new Date(this.getFullYear(), this.getMonth(), this.getDate()+(6-this.getDay()));
}

// Returns a new Date object
// Set to the first day of the current value's month.
Date.prototype.getStartOfMonth=function() {
	result=new Date(this.getFullYear(), this.getMonth(), 1);
	return result;
}

// Returns a new Date object
// Set to the last day of the current value's month.
Date.prototype.getEndOfMonth=function() {
	return new Date(this.getFullYear(), this.getMonth()+1, 0);
}

// Returns an English version of the month as a String
Date.prototype.getMonthString=function() {
	months=["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
	return months[this.getMonth()];
}

// Checks whether a passed date object has the same year/month/day (but not h:m:s:ms) as the current value
Date.prototype.sameDay=function(compareTo) {
	if (this.getMidnight().getTime()==compareTo.getMidnight().getTime()) {
		return true;
	}
	return false;
}

// Calendar Object Constructor
// containerObj is where the HTML is written to
// hiddenFieldObj is where the value gets updated.
function Calendar(containerObj, hiddenFieldObj) {
	if (typeof containerObj=="string") containerObj=document.getElementById(containerObj);
	this.containerObj=containerObj;
	
	this.dateStored=null;
	this.dateShown=new Date();
	
	if (typeof hiddenFieldObj=="string") hiddenFieldObj=document.getElementById(hiddenFieldObj);
	this.hiddenFieldObj=hiddenFieldObj;
	if (typeof this.hiddenFieldObj != "undefined") {
		if (this.hiddenFieldObj.value.toString()!="") {
			parts=this.hiddenFieldObj.value.toString().split("/");
			if (parts.length==3) {
				this.dateStored=new Date(parseInt(parts[2]), parseInt(parts[0]-1), parseInt(parts[1]));
			}
		}
	}
	
	this.render();
}

// Renders all of the HTML for the calendar
Calendar.prototype.render=function() {
	startDate=this.dateShown.getStartOfMonth().getStartOfWeek();
	endDate=this.dateShown.getEndOfMonth().getEndOfWeek();
	numDays=Math.floor(endDate.getTime()-startDate.getTime())/86400000;
	
	tableoutput="<table class='calendar' cellspacing='0'><thead><tr><th>S</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th></tr></thead><tfoot><tr><th>S</th><th>M</th><th>T</th><th>W</th><th>T</th><th>F</th><th>S</th></tr></tfoot><tbody>";
	for (i=0; i<=numDays; i++) {
		currentDate=new Date(startDate.getTime()+i*86400000);
		
		if (modulus(i, 7)==0) {
			tableoutput+="<tr>";
		}
		
		isCurrent=false;
		if (this.dateStored!=null) {
			if (currentDate.sameDay(this.dateStored)) {
				isCurrent=true;
			}
		}
		
		isSameMonth=false;
		if (this.dateShown.getMonth()==currentDate.getMonth()) {
			isSameMonth=true;
		}
		
		tableoutput+="<td";
		if (isCurrent) {
			tableoutput+=" class='current'";
		} else if (!isSameMonth) {
			tableoutput+=" class='different_month'";
		}
		tableoutput+="><a href='#' onclick='this.calendarRef.setDate("+currentDate.getTime()+"); return false;'>"+(currentDate.getDate())+"</a></td>";
		
		if (modulus(i, 7)==6) {
			tableoutput+="</tr>";
		}
	}
	tableoutput+="</tbody></table>";
	
	controlleroutput="<a href='#' onclick='this.calendarRef.addMonth(-1); return false;'>&lt;</a><span class='calendar_month'>"+this.dateShown.getMonthString()+"</span><a href='#' onclick='this.calendarRef.addMonth(1); return false;'>&gt;</a><span class='calendar_year'>"+this.dateShown.getFullYear()+"</span>";
	
	this.containerObj.innerHTML="<div class='calendar_table'>"+tableoutput+"</div><div class='calendar_controller'>"+controlleroutput+"</div>";
	
	allAs=this.containerObj.getElementsByTagName("a");
	for (i=0; i<allAs.length; i++) {
		allAs[i].calendarRef=this;
	}
}

// Adds a given number of months (can be negative) to the shown date, then re-renders
// This lets you move the calendar forward and backwards.
Calendar.prototype.addMonth=function(increment) {
	this.dateShown=new Date(this.dateShown.getFullYear(), this.dateShown.getMonth()+increment, 1);
	this.render();
}

// Sets the stored date
// Re renders
// Updates the hiddenFieldObj and notifies the collapsible menu it has been updated.
Calendar.prototype.setDate=function(timeStamp) {
	this.dateStored=new Date(timeStamp);
	this.render();
	this.hiddenFieldObj.value=(this.dateStored.getMonth()+1)+"/"+this.dateStored.getDate()+"/"+this.dateStored.getFullYear();
	this.hiddenFieldObj.focus();
}