var Calendar = function(targetId) {
	// Constant Variable
	var dayShortName = new Array('อา', 'จ', 'อ', 'พ', 'พฤ', 'ศ', 'ส')
	var dayName = new Array('อาทิตย์', 'จันทร์', 'อังคาร', 'พุธ', 'พฤหัสบดี', 'ศุกร์', 'เสาร์');
	var monthName = new Array('', 'มกราคม', 'กุมภาพันธ์', 'มีนาคม', 'เมษายน', 'พฤษภาคม', 'มิถุนายน', 'กรกฎาคม', 'สิงหาคม', 'กันยายน', 'ตุลาคม', 'พฤศจิกายน', 'ธันวาคม');

	// Variable
	var mode = "view"; // view or edit
	var dateFunction, monthFunction, onMouseOver, onMouseOut;
	var showing = new Array();

	var t = new Date();
	var today = new Array();
	today['date'] = t.getDate();
	today['month'] = t.getMonth() + 1;
	today['year'] = fixYear(t.getYear());
	var beginYear = today['year'] - 1;
	var endYear = today['year'] + 1;
	var hasEvent = new Array();
	for (var i = beginYear; i <= endYear; i++) {
		hasEvent[i] = new Array(13);
		for (var j = 1; j <= 12; j++) {
			hasEvent[i][j] = new Array(daysInMonth(j, beginYear + i));
			for (var k = 1; k <= daysInMonth(j, beginYear + i); k++)
				hasEvent[i][j][k] = 0;
		}
	}

	// function	
	this.setMode = function (param) {
		switch (param) {
			case 'edit': mode = 'edit'; break;
			default:  mode = 'view'; break;
		}
	}

	this.getDateString = function(date, month, year) {
		return date + ' ' + monthName[month] + ' ' + (year + 543);
	}

	this.makeCalendar = make;
	function make(month, year) {
		if ($(targetId) == null) { alert('Cannot find object ID: "'+targetId+'"'); return; }
		year = fixYear(year);
		if (year < beginYear || year > endYear) { return; }
		if (month < 1 || month > 12) { alert('Invalid month in function make()'); return; }
		
		if (monthFunction != undefined && monthFunction != '') eval(monthFunction + '('+month+', '+year+');');

		showing['date'] = 0;
		showing['year'] = year;
		showing['month'] = month;

		var htmlText = '<table class="calendar_table" cellspacing="1">';
		htmlText += '<caption><span class="prev">&lt;&lt;</span><span class="caption"> '+monthName[month]+' '+(year + 543)+' </span><span class="next">&gt;&gt;</span></caption>'; // remove chageMonthIcon if year out of range below.
		htmlText += '<tr>';
		for (var i = 0; i < 7; i++) htmlText += '<th>'+dayShortName[i]+'</th>';
		htmlText += '</tr>';
		
		var firstDay = new Date(year, month - 1, 1).getDay();
		
		var runDate = 1;
		while (runDate <= daysInMonth(month, year)) {
			htmlText += '<tr>';
			for (var i = 0; i < 7; i++) {
				if (runDate == 1 && i < firstDay || runDate > daysInMonth(month, year)) htmlText += '<td></td>';
				else {
					var className = '';
					if (hasEvent[year][month][runDate]) className = 'hasEvent';
					if (runDate == today['date'] && month == today['month'] && year == today['year']) className += ' today';
					htmlText += '<td class="'+className+'"';
					if (hasEvent[year][month][runDate]) {
						if (onMouseOver != undefined && onMouseOver != '') htmlText += ' onmouseover="javascript: '+onMouseOver+'('+runDate+', '+month+', '+year+', this);"';
						if (onMouseOut != undefined && onMouseOut != '') htmlText += ' onmouseout="javascript: '+onMouseOut+'();"';
					}
					if ((mode == 'edit' || hasEvent[year][month][runDate]) && (dateFunction != undefined && dateFunction != '')) htmlText += ' onclick="javascript: '+dateFunction+'('+runDate+', '+month+', '+year+');"';
					htmlText += '>'+runDate+'</td>';
					runDate++;
				}
			}
			htmlText += '</tr>';
		}
		
		htmlText += '</table>';
		$(targetId).update(htmlText);

		// add onclick event to previous and next month Icon
		var changeMonthIcon = $(targetId).getElementsByTagName('caption')[0].childNodes;
		Event.observe(changeMonthIcon[0], 'click', prevMonth);
		Event.observe(changeMonthIcon[2], 'click', nextMonth);

		// remove previous or next month Icon if year out of range.
		if (year < beginYear || year == beginYear && month == 1) changeMonthIcon[0].remove();
		if (year > endYear || year == endYear && month == 12) changeMonthIcon[2].remove();

	}

	function prevMonth() {
		var year = showing['year'];
		var month = showing['month'] - 1;
		if (month == 0) {
			month = 12;
			year--;
		}
		make(month, year);
	}

	function nextMonth() {
		var year = showing['year'];
		var month = showing['month'] + 1;
		if (month == 13) {
			month = 1;
			year++;
		}
		make(month, year);
	}

	function daysInMonth(month, year) {
		if (month < 1 || month > 12) { alert('Invalid Input in function daysInMonth()'); return 0; }
		var daysInMonth = new Array(0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
		if (isLeapYear(year) && month == 2) return 29;
		else return daysInMonth[month];
	}

	function isLeapYear(year) {
		if (year <= 0) { alert('Invalid Input in function isLeapYear()'); return false; }
		year = fixYear(year);
		if (year % 400 == 0) return true;
		if (year % 100 == 0) return false;
		if (year % 4 == 0) return true;
	}

	this.setEvent = function (date, month, year, value) {
		if (value != 0 && value != 1) { alert('Invalid value in function setEvent()'); return; }
		year = fixYear(year);
		if (!isValidYear(year)) { return; }
		if (month < 1 || month > 12) { alert('Invalid month in function setEvent()'); return; }
		if (date < 1 || date > daysInMonth(month, year)) {  alert('Invalid date in function setEvent()'); return; }
		
		hasEvent[year][month][date] = value;
	}
	
	this.resetEvent = function() {
		for (var i = beginYear; i <= endYear; i++) {
			for (var j = 1; j <= 12; j++) {
				for (var k = 1; k <= daysInMonth(j, beginYear + i); k++)
					hasEvent[i][j][k] = 0;
			}
		}
	}

	this.setDateFunction = function (func) {
		dateFunction = func;
	}

	this.setMonthFunction = function (func) {
		monthFunction = func;
	}

	this.setOnMouseOver = function (func) {
		onMouseOver = func;
	}

	this.setOnMouseOut = function (func) {
		onMouseOut = func;
	}

	function isValidYear(year) {
		if (year < beginYear || year > endYear) return false;
		return true;
	}

	function fixYear(year) { // becoz today.getYear() return 108 instead of 2008 in firefox (don't know why)
		if (year < 1000) return year + 1900;
		else return year;
	}
};

