var ical = {
	/* http://snippets.dzone.com/posts/show/2099
	Apparently, the javascript Date function allows you to overflow the day number parameter that you pass, creating a date in the next month. Deliberately overflowing the day parameter and checking how far the resulting date overlaps into the next month is a quick way to tell how many days there were in the queried month. Here is a function that does this:
	*/
	log: function(msg) {
		//document.getElementById('log').innerHTML += msg;
		//document.write(msg);
		//alert(msg);
	}
	,log: function(funcName, msg) {
		//document.write("["+funcName+"] -"+msg+"<br/>");
		//document.getElementById('log').innerHTML += "["+funcName+"] -"+msg+"<br/>";
	}
	, getMMYYYY: function(date) {
		return (date.getMonth()+1)+'/'+date.getFullYear();
	}
	, daysInMonth: function(iMonth, iYear) {
		return 32 - new Date(iYear, iMonth, 32).getDate();
	}
	, WeekdayCSS: ["", "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"]
	, WEEKDAYS: ["", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
	, WEEKDAYS_SHORT: ["", "S", "M", "T", "W", "Th", "F", "S"]
	, MONTH: ["","January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
	, MONTH_SHORT: ["","Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
	,compactSwitchTo: function(monthYear, toWhereId) {
		if ( document.getElementById(toWhereId) ) {
			var cal = new iCalendar(monthYear);
			cal.init();
			var content = cal.genCompactTable();
			
			document.getElementById(toWhereId).innerHTML = content;
			cal.applyToday('compact');
		}
		return false;
	}
	,create: function(monthYear) {
	}
	,switchTo: function(monthYear, toWhereId) {
		if ( document.getElementById(toWhereId) ) {
			var cal = new iCalendar(monthYear);
			cal.init();
			var content = cal.generateTable();
	
			document.getElementById(toWhereId).innerHTML = content;
			cal.applyToday('ical');
		}
		attachEvents();
		return false;
	}
};

function iCalendar(monthYY) {
	
	if ( monthYY == null || monthYY === '' ) {
		var today = new Date();
		monthYY = (today.getMonth()+1)+"/"+today.getFullYear();
	}
	this.monthYY = monthYY;
	// this will hold all html content
	this.innerHTML = "";
	
	// represent calendar table
	// index is dayTH
	// value is matrix(row, col)
	// ex: [10]='2,1' mean 10th day is at row 2 column 1.
	this.positionOfDays = new Array();
	this.positionOfDays[0] = '';
	this.matrix = [];
	
	this.init = function() {
		ical.log("START init", this.monthYY);
		// create javascript date from 'MM/YYYY'
		// 7/2011 -> value of js date.getMonth() is '6'
		var v = this.monthYY.split("\/");
		this.month = v[0];
		this.year = v[1];
		// html id for calendar
		this.id = "cal_"+(this.month>9?this.month:'0'+this.month)+this.year;
		this.date = new Date(this.year, this.month-1, 1);
		var endDay = ical.daysInMonth(this.date.getMonth(), this.date.getYear()); 
		// position of first day of week between 1 - 7
		var firstPosition = this.date.getDay()+1;
		ical.log("init", "endDay="+endDay+", firstPosition="+firstPosition);
		var weeks = 1;
		// create position array
		for(var i=1; i<= endDay; ++i) {
			var remainder = (firstPosition + i - 1) % 7;
			if (remainder==1) {
				weeks++;
			}
			this.positionOfDays[i] = (weeks+",")+((remainder==0)?7:remainder);
			//ical.log("position["+i+"]="+this.positionOfDays[i]);
		}
		this.numOfWeeks = weeks;	// number of table rows
		//matrix begin
		//this.matrix.push(new Array(7));
		//this.matrix[weeks] = new Array(7); 
		//this.matrix[weeks][((remainder==0)?7:remainder)] = i;
		//matrix end
		ical.log("END init", this+"this(id, date, month, year)=("+this.id+"|"+this.date+"|"+this.month+", "+this.year+")");
		ical.log("numOfWeeks="+this.numOfWeeks);
	}
	
	this.header = function(calType) {
		var NL = '\n';
		var prev, next;
		var mm = parseInt(this.month);
		var yr = parseInt(this.year);
		if (mm == 1) {
			prev = '12/'+(yr-1);
		} else {
			prev = (mm-1)+'/'+yr;
		}
		if (mm == 12) {
			next = '1/' + (yr+1);
		} else {
			next = (mm+1)+'/'+yr;
		}
		
		if ( calType == 'compact' ) {
			var htmlCode = 
			/*'<tr><th colspan="7">Events</th></tr>'+NL+ */
			'<tr><th colspan="5">'+ical.MONTH[this.month]+" "+this.year+"</th>"+
			'<th><a href="#" title="'+prev+'" onclick="return ical.compactSwitchTo(\''+prev+'\', \'calendarDiv\');">&lt;</a></th>'+
			'<th><a href="#" title="'+next+'" onclick="return ical.compactSwitchTo(\''+next+'\', \'calendarDiv\');">&gt;</a></th>'+
			'</tr>'+NL;
			;
			return htmlCode;
		}
		else if ( calType == 'ical' ) {
			var today = new Date();
			var monthYY = (today.getMonth()+1)+"/"+today.getFullYear();
			var htmlCode = 
				'<tr><td width="90%" align="center">'+ical.MONTH[this.month]+", "+this.year+"</td>"+
				'<td width="5%"><a href="#" title="'+prev+'" onclick="return ical.switchTo(\''+prev+'\', \'calendarDiv\');">'+
				'<img src="./images/ical_left.png" border="0" style="position:relative; top:3px; width:20px; height:20px; border:0;"/></a></td>';
				if ( monthYY != (this.month+'/'+this.year)) {
				htmlCode += '<td><a href="#" title="current month" onclick="return ical.switchTo(\''+monthYY+'\', \'calendarDiv\');">'+
				'<img src="./images/circle_grey.png" border="0" style="position:relative; top:3px; width:20px; height:20px; border:0;"/></a></td>';
				}
				htmlCode +=
				'<td><a href="#" title="'+next+'" onclick="return ical.switchTo(\''+next+'\', \'calendarDiv\');">'+
				'<img src="./images/ical_right.png" border="0" style="position:relative; top:3px; width:20px; height:20px; border:0;"/></a></td>'+
				'</tr>'+NL;
				;
			return htmlCode;
		}
		else if ( calType == 'ical-sidebar' ) {
			var thisMM = parseInt(this.month);
			var thisYY = parseInt(this.year);
			var mm = thisMM;
			var yy = thisYY;
			htmlCode = 
				'<div class="ical-month">'+NL+
				'<table cellspacing="0"><tr><th></th></tr>'+NL;
			for(var n=1; n<=12; ++n) {
				if (mm+1 > 12) {
					yy = yy+1;
					mm = 1;
				} else {
					mm += 1;
				}
				next = mm + '/' + yy;
				
				htmlCode += "<tr>";
				if ( n % 2 == 1 )
					htmlCode += '<td ';
				else
					htmlCode += '<td class="pad" ';
					
				htmlCode += 'onclick="return ical.switchTo(\''+next+'\', \'calendarDiv\');">'+
				//htmlCode += '<a href="#" title="'+next+'" onclick="return ical.switchTo(\''+next+'\', \'calendarDiv\');">'+
				//htmlCode += '<a href="#" onclick="return ical.switchTo(\''+next+'\', \'calendarDiv\');">'+
				//htmlCode += '<a href="#" onclick="return ical.switchTo(\''+next+'\', \'calendarDiv\');">'+
					ical.MONTH_SHORT[mm]+", "+yy
					"</td></tr>"+NL;
					//"</a></td></tr>"+NL;
			}
			htmlCode += '</table></div>'+NL;

			return htmlCode;
		}
		
	}
	this.genCompactTable = function() {
		var NL = '\n';
		var htmlCode = 
			'<table cellspacing="0" cellspacing="0">'+NL+
			this.header('compact');
		/*
			'<table cellspacing="0" cellspacing="0">'+NL+
			'<tr><th colspan="7">Events</th></tr>'+NL+
			'<tr><th colspan="5">'+
			ical.MONTH[this.month]+" "+this.year+
			'</th><th>&lt;</th><th>&gt;</th></tr>'+NL;*/
			
			
		htmlCode += "<tr>"
		for(var i=1; i<ical.WEEKDAYS_SHORT.length; ++i) {
			htmlCode += "<td>"+ical.WEEKDAYS_SHORT[i]+"</td>";
		}
		htmlCode += "</tr>"+NL;
		
		var row = -1, col = -1;
		var rowIdx = 0, colIdx = 0; // valid index starts from 1
		var dayID = "EMPTY";
		for(var day=1; day<this.positionOfDays.length; ++day) {
			//id is "cal_mmddyyyy" 12 characters
			dayID = "cal_"+(this.month>9?this.month:'0'+this.month)+(day>9?day:'0'+day)+this.year;
			var entry = this.positionOfDays[day].split("\,");
			row = entry[0]; 
			col = entry[1];
			if ( row != rowIdx ) {	// when row chaning, add tr
				htmlCode += '<tr>';
				rowIdx = row;
			} 
			// add padding for first week/row
			if ( row==1 && day == 1) {
				//this is for larger one style
				//htmlCode += '<td class="padding" colspan="'+(col-1)+'"></td>';
				
				//this is for compact one
				for(var n=0; n<(col-1); ++n)
					htmlCode += '<td>&nbsp;</td>';
				
				colIdx = col;
			} else {
				colIdx++;
			}
			//TODO today class="today"
			//TODO events class="date_has_event"
			if ( this.isThisMonth ) {
				
			}
			htmlCode += '<td id="'+dayID+'">'+day+"</td>";
			
			//<td><a href="#" class="today">day</a></td>";
			
			
			if ( colIdx == 7 ) {
				htmlCode += '</tr>'+NL;
				rowIdx++;
				colIdx = 0;
			}
		}

		// add  rest of padding at the end
		if ( (7-col)>0 ) {
			//this is for larger one style
			//htmlCode += '<td class="padding" colspan="'+(7-col)+'"></td>';
			
			//this is for compact one
			for(var n=0; n<(7-col); ++n)
				htmlCode += '<td>&nbsp;</td>';
			
			
			htmlCode += '</tr>'+NL;
		}
		htmlCode += '</table>'+NL;
		ical.log(htmlCode);
		//alert(htmlCode);
		return htmlCode;
	}
	
	this.applyToday = function(calType) {
		var today = new Date();
		(this.month>9?this.month:'0'+this.month)
		var todayId = "cal_"+ 
			(today.getMonth()+1>9?today.getMonth()+1:'0'+(today.getMonth()+1)) + 
			(today.getDate()>9?today.getDate():'0'+today.getDate())+
			today.getFullYear();
			//alert(todayId);
		if ( calType == 'compact' ) {
			if ( document.getElementById(todayId) ) {
				document.getElementById(todayId).innerHTML = '<a href="#" class="today">'+today.getDate()+'</a>';
			}
		} else if ( calType == 'ical' ) {
			if ( document.getElementById(todayId) ) {
				document.getElementById(todayId).className += ' today';
			}
		}
		//TODO
	}
	this.applyEvents = function() {
	}
	this.generateTable = function() {
		var NL = '\n';
		

		//this.header();
		var htmlCode = 
			'<table cellspacing="0" class="ical" style="border-bottom:1px solid #9DACBE;">'+NL;
			
		/*
			'<table cellspacing="0" cellspacing="0">'+NL+
			'<tr><th colspan="7">Events</th></tr>'+NL+
			'<tr><th colspan="5">'+
			ical.MONTH[this.month]+" "+this.year+
			'</th><th>&lt;</th><th>&gt;</th></tr>'+NL;*/
			
			
		htmlCode += "<thead><tr>"
		for(var i=1; i<ical.WEEKDAYS.length; ++i) {
			htmlCode += "<th>"+ical.WEEKDAYS[i]+"</th>";
		}
		htmlCode += "</tr></thead>"+NL;
		
		var row = -1, col = -1;
		var rowIdx = 0, colIdx = 0; // valid index starts from 1
		var dayID = "EMPTY";
		var numOfWeeks = 0;
		for(var day=1; day<this.positionOfDays.length; ++day) {
			//id is "cal_mmddyyyy" 12 characters
			var eventID = (this.month>9?this.month:'0'+this.month)+(day>9?day:'0'+day)+this.year;
			dayID = "cal_"+eventID;
			var entry = this.positionOfDays[day].split("\,");
			row = entry[0]; 
			col = entry[1];
			if ( row != rowIdx ) {	// when row chaning, add tr
				htmlCode += '<tr>';
				rowIdx = row;
				
			} 
			// add padding for first week/row
			if ( row==1 && day == 1) {
				//this is for larger one style
				htmlCode += '<td class="padding" colspan="'+(col-1)+'"></td>';
				
				//this is for compact one
				//for(var n=0; n<(col-1); ++n)
				//	htmlCode += '<td>&nbsp;</td>';
				
				colIdx = col;
			} else {
				colIdx++;
			}
			//TODO today class="today"
			//TODO events class="date_has_event"
			if ( this.isThisMonth ) {
				
			}
			if ( document.getElementById(eventID) ) {
			//alert(document.getElementById(eventID).innerHTML);
				htmlCode += '<td id="'+dayID+'" class="date_has_event">'+day+
					document.getElementById(eventID).innerHTML+"</td>";
			}
			else {
				htmlCode += '<td id="'+dayID+'">'+day+"</td>";
			}
			
			//<td><a href="#" class="today">day</a></td>";
			
			
			if ( colIdx == 7 ) {
				htmlCode += '</tr>'+NL;
				numOfWeeks++;
				rowIdx++;
				colIdx = 0;
			}
		}

		// add  rest of padding at the end
		if ( (7-col)>0 ) {
			//this is for larger one style
			htmlCode += '<td class="padding" colspan="'+(7-col)+'"></td>';
			
			//this is for compact one
			//for(var n=0; n<(7-col); ++n)
			//	htmlCode += '<td>&nbsp;</td>';
			htmlCode += '</tr>'+NL;
			numOfWeeks++;
		}
		//alert('numOfWeeks='+numOfWeeks+", "+rowIdx+", col="+col);
		for(var n=numOfWeeks; n<6; ++n) {
			htmlCode += '<tr><td class="padding" colspan="7"></td></tr>';
		}
		htmlCode += '</table>'+NL;
		//ical.log(htmlCode);
		
		
		
		
		
		var outer = 
			'<table border="0" cellspacing="0" cellpadding="0">'+NL+
				'<tr><td colspan="2" width="100%">'+NL+
					'<table width="100%" class="ical-header">'+NL+
						this.header('ical')+NL+
					'</table>'+NL+
				'</td></tr>'+NL+
				'<tr>'+NL+
					'<td valign="top">'+NL+this.header('ical-sidebar')+
						/*'<div class="ical-month">'+NL+
							'<table cellspacing="0"><tr><th></th></tr><tr><td>July, 2011</td></tr><tr><td>Aug, 2011</td></tr><tr><td>Sep, 2011</td></tr><tr><td class="pad">Apri</td></tr><tr><td>May</td></tr><tr><td>June</td></tr><tr><td>Jan, 2012</td></tr><tr><td class="pad">Feb, 2012</td></tr><tr><td>September</td></tr><tr><td>October</td></tr><tr><td class="pad">November</td></tr><tr><td>December</td></tr></table>'+NL+
						'</div>'+NL+*/
					'</td>'+NL+
					'<td>'+NL+
						htmlCode+NL+
					'</td>'+NL+
				'</tr>'+NL+
			'</table>'+NL
		;
		
		return outer;
	}
}	// end iCalendar

iCalendar.prototype.toString = function() {
	return "[id="+this.id+", monthYY="+this.monthYY+"]";
}

/*
function Calendar(d) {
//	this.document = doc;
	this.date = d;
	var v = this.date.split("\/");
	this.month = v[0];
	this.year = v[1];
	// idx -> (whichWeek, weekPosition ) 
	this.position = new Array();
	this.position[0] = '';
	this.calendarEvents = new Array();
	this.codes = '';

//	alert('in constructor\n'+document.getElementById('calendarArea').id
//	+'\nin constructor\n'+this.document.getElementById('calendarArea').id);

}
Calendar.prototype.preProcess = function() {
	var v = this.date.split("\/");
	var date = new Date(this.year, this.month-1, 1);
	var firstPosition = date.getDay()+1;
	var startDay = 1;
	var endDay = daysInMonth(date.getMonth(), this.year); 

	var numOfWeeks = 1;
	// create position array
	for(var i=1; i<= endDay; ++i) {
		var remainder = (firstPosition + i - 1) % 7;
		if (remainder==1)
			numOfWeeks++;
		this.position[i] = (numOfWeeks+",")+((remainder==0)?7:remainder);
	}
} */
