var months = new Array('January','February','March','April','May','June','July','August','September','October','November','December');


function Calendar()
{
	this.classPrefix = 'CAL_';
	
	this.initialMonth = -1;
	this.initialYear = -1;
	
	this.renderCalendar = function(parent,month,year,callback)
	{
		this.calDiv = document.createElement('div');
		this.calDiv.className=this.classPrefix+'cal';
		this.callback = callback;
		
		parent.appendChild(this.calDiv);
		
		this.renderMonth(month,year);
	}
	
	this.renderMonth = function(month,year)
	{
		if(this.calDiv==undefined) {alert('calDiv not found: do not call this method directly'); return;}
		
		while(this.calDiv.childNodes.length>0) this.calDiv.removeChild(this.calDiv.firstChild);
		
		var rows = new Array();
		var firstOfMonth = new Date(year,month,1);
		var firstDay = firstOfMonth.getDay();
		
		var d = this.addDay(firstOfMonth,0-firstDay);
		var startOfMonthSunday = d;
		
		var eom = new Date(firstOfMonth.getTime());
		eom.setMonth(eom.getMonth()+1);
		eom.setDate(eom.getDate()-1);
		
		var extra = (eom.getDate()%7)+firstDay;
		var numWeeks = 4 + (extra>0?1:0) + (extra>7?1:0);
		
		if(numWeeks==4) {d.setDate(d.getDate()-7);}
		
		while(rows.length<6)
		{
			var row = new Array();
			for(var n=0;n<7;n++)
			{
				row[row.length]=d.getDate();
				d.setDate(d.getDate()+1);
			}
			rows[rows.length]=row;
		}
		
		var table = document.createElement('table');
		table.cellSpacing=0;
		table.cellPadding=0;
		table.style.width='100%';
		this.calDiv.appendChild(table);
		
		var tbody = document.createElement('tbody');
		table.appendChild(tbody);
		
		var monthNameRow = document.createElement('tr');
		monthNameRow.className=this.classPrefix+'monthName';
		tbody.appendChild(monthNameRow);
		
		var prev = document.createElement('td');
		prev.className=this.classPrefix+'nav';
		monthNameRow.appendChild(prev);
		
		var prevm = month>0?month-1:11;
		var prevy = prevm==11?year-1:year;
	
		var e = document.createElement('span');
		e.targetMonth=prevm;
		e.targetYear=prevy;
		e.calendar=this;
		e.onclick=this.navCallback;
		e.innerHTML='&laquo;';
		prev.appendChild(e);
		
		e = document.createElement('td');
		e.className=this.classPrefix+'title';
		e.style.textAlign='center';
		e.colSpan=5;
		e.innerHTML=months[month]+'<br/>'+year;
		monthNameRow.appendChild(e);
		
		var next = document.createElement('td');
		next.className=this.classPrefix+'nav';
		monthNameRow.appendChild(next);
		
		var nextm = (month+1)%12;
		var nexty = nextm==0?year+1:year;
		
		e = document.createElement('span');
		e.targetMonth=nextm;
		e.targetYear=nexty;
		e.calendar=this;
		e.onclick=this.navCallback;
		e.innerHTML='&raquo;';
		next.appendChild(e);
		
		var dayNameRow = document.createElement('tr');
		dayNameRow.className=this.classPrefix+'dayNames';
		
		var days = new Array('S','M','T','W','T','F','S');
		for(var n=0;n<days.length;n++)
		{
			var dayNameCell = document.createElement('td');
			dayNameCell.innerHTML=days[n];
			dayNameRow.appendChild(dayNameCell);
		}
		
		tbody.appendChild(dayNameRow);
		
		var m = month>0?month-1:11;
		var y = m==11?year-1:year;
		var d = new Date();
		
		for(var n=0;n<6;n++)
		{
			var rowDiv = document.createElement('tr');
			rowDiv.className=this.classPrefix+'row';
			tbody.appendChild(rowDiv);
			
			if(n<rows.length)
			{
				for(var o=0;o<7;o++)
				{
					if(rows[n][o]==1)
					{
						m = (m+1)%12;
						y = m==0?y+1:y;
					}
					var dayDiv = document.createElement('td');
					dayDiv.className=this.classPrefix+'day';
					if(o==0||o==6) dayDiv.className+=' '+this.classPrefix+'weekend';
					if(m!=month) dayDiv.className+=' '+this.classPrefix+'otherMonth';
					if(y==d.getFullYear()&&m==d.getMonth()&&rows[n][o]==d.getDate()) dayDiv.className+=' '+this.classPrefix+'today';
					dayDiv.innerHTML=''+rows[n][o];
					if(this.callback!=undefined)
					{
						dayDiv.day=rows[n][o];
						dayDiv.month=m;
						dayDiv.year=y;
						dayDiv.calendar=this;
						dayDiv.onclick=this.dayCallback;
					}
					rowDiv.appendChild(dayDiv);
				}
			}
		}
	}
	
	this.navCallback = function(e)
	{
		// when called as an event handler 'this' refers to the element triggering the event, NOT the Calendar object
		
		// swallow this event so the popup isn't hidden by document's onclick handler
		if (!e) var e = window.event;
		e.cancelBubble = true;
		if (e.stopPropagation) e.stopPropagation();

		this.calendar.renderMonth(this.targetMonth,this.targetYear);
	}
	
	this.dayCallback = function()
	{
		// when called as an event handler 'this' refers to the element triggering the event, NOT the Calendar object
		if(this.calendar.callback!=undefined)
		{
			// when the callback function is executed, this will refer to the calendar associated with the trigger element
			this.calendar.callback(this.day,this.month,this.year);
		}
	}
	
	this.addDay = function(date,multiple)
	{
		if(multiple==undefined) multiple = 1;
		var d = new Date(date.getTime());
		d.setDate(date.getDate()+multiple);
		return d;
	}
	

	this.popupCalendar = function(element,callback,event)
	{
		if(window.event)
		{
			// swallow any event that triggered this in IE
			window.event.cancelBubble = true;
		}
		else
		{
			// swallow any event that triggered this in Firefox
			event.stopPropagation();
		}
		
		// hide any other calendar popups that are currently visible
		for(var n=0;n<calendars.length;n++)
		{
			if(calendars[n]!=this) calendars[n].unpopupCalendar();
		}
		
		if(this.calPopup==undefined)
		{
			// create new popup and render this calendar in it
			var wrapper = document.createElement('div');
			wrapper.style.width='180px';
			wrapper.style.height='auto';
			wrapper.style.border='solid 1px black';
			var d = new Date();
			var m = parseInt(this.initialMonth>=0?this.initialMonth:d.getMonth());
			var y = parseInt(this.initialYear>=0?this.initialYear:d.getFullYear());
			this.renderCalendar(wrapper,m,y,callback);
			this.calId = getNextCalId();
			var alignment = this.alignment?this.alignment:40;
			var hpad = this.hpad?this.hpad:0;
			var vpad = this.vpad?this.vpad:4;
			this.calPopup = showPopup(element,this.calId,wrapper,alignment,hpad,vpad);
			calendars[calendars.length]=this;
			
			if(this.calId=='cal0')
			{
				// this is the first popup on this page, so add the onclick event handler to the document
				if(document.attachEvent)
				{
					// the IE way...
					document.attachEvent('onclick',hideCalendarPopups);
				}
				else
				{
					// the rest-of-the-world way...
					document.addEventListener('click',hideCalendarPopups,false);
				}
			}
		}
		else
		{
			// popup already exists for this Calendar, so make it visible
			setPopupVisible(this.calPopup.id,true); 
			//this.calPopup.style.visibility='visible';
		}			
	}
	
	this.unpopupCalendar = function()
	{
		if(this.calPopup!=undefined)
		{
			setPopupVisible(this.calPopup.id,false);
			//this.calPopup.style.visibility='hidden';
		}
	}
	
}

function hideCalendarPopups()
{
	for(var n=0;n<calendars.length;n++)
	{
		calendars[n].unpopupCalendar();
	}
}	
	
var calCounter = 0;

var calendars = new Array();

function getNextCalId()
{
	return 'cal'+(calCounter++);
}
