function Calendar(id,config) {
	if (typeof config == "undefined") {
		this.config = new Calendar.Config();
	} else {
		this.config = config;
	};

	this.id = id;
	this.parent = null;
	
	this.calendarDiv = null;
	this.iframeBkg = null;
	this.hideEvent = null;
	
	this.callBack = null;
	
	this.todayDate = new Date();
	this.todayDate.setHours(0);
	this.todayDate.setMinutes(0);
	this.todayDate.setSeconds(0);
	
	if (this.config.selectDate) {
		this.selectDate = this.config.selectDate;
	}else {
		this.selectDate = new Date();
	}
	
	this.selectDate.setHours(0);
	this.selectDate.setMinutes(0);
	this.selectDate.setSeconds(0);

	this.displayMonth = this.selectDate.getMonth();
	this.displayYear = this.selectDate.getFullYear();
	
	this.MonthDays = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);

	this.init();
};

Calendar.isMSIE = (navigator.appName == "Microsoft Internet Explorer");
Calendar.isMSIE5 = Calendar.isMSIE && (navigator.userAgent.indexOf('MSIE 5') != -1);
Calendar.isMSIE5_0 = Calendar.isMSIE && (navigator.userAgent.indexOf('MSIE 5.0') != -1);
Calendar.isGecko = navigator.userAgent.indexOf('Gecko') != -1;
Calendar.isMAC = navigator.userAgent.indexOf("Mac") > -1;
Calendar.OneDay = 24 * 60 * 60 * 1000;

Calendar.Config = function () {
	this.version = '0.1';
	
	this.className = '';
	this.startDate = null;
	this.endDate = null;
	
	this.selectDate = null;

	this.width = null;
	
	this.autoHide = false;
	this.closeOnSelect = false;
	
	this.displayPosition = 'auto';
	
	this.Caption = new Array('S','M','T','W','T','F','S');

	this.MonthNames = new Array('January','February','March','April','May','June','July','August','September','October','November','December');
	this.ShortMonthNames = new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sept','Oct','Nov','Dec');
};

Calendar.prototype.init = function () {
	var obj = this;

	//Create Calendar Div
	this.calendarDiv = document.createElement("DIV");
	this.calendarDiv.id = this.id + '_div';
	this.calendarDiv.style.position = "absolute";
	this.calendarDiv.style.top = '0px';
	this.calendarDiv.style.left = '0px';
	
	if (obj.config.width) {
		this.calendarDiv.style.width = obj.config.width + "px";
	}else {
		this.calendarDiv.style.width = "auto";
	};
	this.calendarDiv.style.visibility = 'hidden';
	this.calendarDiv.style.zIndex = 5000;
	this.calendarDiv.className = this.config.className;
	this.calendarDiv.innerHTML = this.buildCalendar(this.displayMonth,this.displayYear);

	//Prepare DIV Event
	if (this.config.autoHide) {
		Calendar.addEvent(this.calendarDiv,"focus", function (event) {
					 return obj.OnFocus(Calendar.isMSIE ? window.event : event);
				 });
		Calendar.addEvent(this.calendarDiv,"blur", function (event) {
					 return obj.OnBlur(Calendar.isMSIE ? window.event : event);
				 });
	}
	
	document.body.appendChild(this.calendarDiv);

	//Initail IFrame to Fix Overlap with select
	this.iframeBkg = document.createElement("IFRAME");
	this.iframeBkg.id = this.id + '_frame';
	this.iframeBkg.src = 'javascript:false';
	this.iframeBkg.style.position = "absolute";
	this.iframeBkg.style.top = '0px';
	this.iframeBkg.style.left = '0px';
	this.iframeBkg.style.border = 0;

	if (obj.config.width) {
		this.iframeBkg.style.width = obj.config.width + "px";
	}else {
		this.iframeBkg.style.width = this.txt.offsetWidth + "px";
	};

	this.iframeBkg.style.display = 'none';

	document.body.appendChild(this.iframeBkg);
	
	Calendar.addEvent(window,"resize", function (event) {
				 return obj.OnResize(Calendar.isMSIE ? window.event : event);
			 });
}

Calendar.prototype.OnFocus = function (e) {
	var obj = this;
	
	clearTimeout(obj.hideEvent);
};

Calendar.prototype.OnBlur = function (e) {
	var obj = this;

	obj.hideEvent = setTimeout("Calendar.hide('" + obj.id + "');",500);
};

Calendar.prototype.OnResize = function (e){
    if (this.calendarDiv.style.visibility != 'hidden')
	    this.setPosition();
};

Calendar.previousMonth = function(objCal) {
	objCal.displayMonth--;
	if (objCal.displayMonth < 0) {
		objCal.displayMonth = 11;
		objCal.displayYear--;
	}
	
	objCal.calendarDiv.innerHTML = objCal.buildCalendar();
	objCal.iframeBkg.style.height = objCal.calendarDiv.style.height;
};

Calendar.nextMonth = function(objCal) {
	objCal.displayMonth++;
	if (objCal.displayMonth > 11) {
		objCal.displayMonth = 0;
		objCal.displayYear++;
	}
	
	objCal.calendarDiv.innerHTML = objCal.buildCalendar();
	objCal.iframeBkg.height = objCal.calendarDiv.offsetHeight;
};

Calendar.pickedDate = function (source,objCal,iDay,iMonth,iYear) {
	objCal.selectDate = new Date(iYear,iMonth,iDay);
	
	//alert(source.parentNode.parentNode.parentNode.childNodes.length);
	
	if (source.parentNode.parentNode.parentNode.tagName == 'TBODY') {
	    for (var i = 0;i < source.parentNode.parentNode.parentNode.childNodes.length;i++) {
	        for (var j = 0;j < source.parentNode.parentNode.parentNode.childNodes[i].childNodes.length;j++ ) {
	            if (source.parentNode.parentNode.parentNode.childNodes[i].childNodes[j].className == 'select')
	                source.parentNode.parentNode.parentNode.childNodes[i].childNodes[j].className = '';
	        }
	    }
	}
	
	source.parentNode.className = 'select';
	
	if (objCal.config.callBack) {
		objCal.config.callBack(iDay,iMonth,iYear);
	}
	
	if (objCal.config.closeOnSelect)
    	Calendar.hide(objCal.id);
};

Calendar.prototype.buildCalendar = function() {
	var strCalendar = '';
	var i,j;
	var monthStart = new Date(this.displayYear,this.displayMonth,1);
	var monthEnd = new Date(this.displayYear,this.displayMonth,this.MonthDays[this.displayMonth]);
	var currentDate;
	var prevMonth,nextMonth;
	
	var FirstDate = new Date(this.displayYear, this.displayMonth, 1);

	var Rows = 6;
	//if (((this.MonthDays[this.displayMonth] == 31) && (FirstDate.getDay() > 4)) || ((this.MonthDays[this.displayMonth] == 30) && (FirstDate.getDay() == 6))) Rows = 6;
	//else if ((this.MonthDays[this.selectDate.getMonth()] == 28) && (FirstDate.getDay() == 0)) Rows = 4;

	strCalendar += '<table width="100%" cellpadding="0" cellspacing="0" border="0"';
	if (this.config.autoHide) {
		strCalendar += ' onmouseover="Calendar.cancelHide(\'' + this.id + '\');" onmouseout="Calendar.setAutoHide(\'' + this.id + '\');"';
	}
	
	prevMonth = (this.displayMonth - 1) >= 0?this.displayMonth - 1:11;
	nextMonth = (this.displayMonth + 1)%12;
	
	strCalendar += '>';
	strCalendar += '<tr><th colspan="3" align="left">';
	
	if (this.config.startDate) {
		if ((this.config.startDate - monthStart) < 0) {
			strCalendar += '&laquo;&nbsp;<a href="#" onclick="Calendar.previousMonth(eval(' + this.id + '));return false;">' + this.config.ShortMonthNames[prevMonth] + '</a></th>';
		}else {
			strCalendar += '&nbsp;';
		}
	}else {
		strCalendar += '&laquo;&nbsp;<a href="#" onclick="Calendar.previousMonth(eval(' + this.id + '));return false;">' + this.config.ShortMonthNames[prevMonth] + '</a></th>';
	}
	
	strCalendar += '<th colspan="3">' + this.config.MonthNames[this.displayMonth] + '&nbsp;' + this.displayYear + '</th><th colspan="3" align="right">';
	
	if (this.config.endDate) {
		if ((monthEnd - this.config.endDate) < 0) {
			strCalendar += '<a href="#" onclick="Calendar.nextMonth(eval(' + this.id + '));return false;">' + this.config.ShortMonthNames[nextMonth] + '</a>&nbsp;&raquo;';
		}else {
			strCalendar += '&nbsp;';
		}
	}else {
		strCalendar += '<a href="#" onclick="Calendar.nextMonth(eval(' + this.id + '));return false;">' + this.config.ShortMonthNames[nextMonth] + '</a>&nbsp;&raquo;';
	}

	strCalendar += '</th></tr>';
	
	//Generate Calendar Header
	strCalendar += '<tr><td></td>';
	for (i = 0;i < 7;i++) {
		strCalendar += '<td>' + this.config.Caption[i] + '</td>';
	}
	strCalendar += '<td></td></tr>';
	
	//Generate Calendar Body
   for (j=0;j<Rows;j++) {
      strCalendar += '<tr><td></td>';
      for (i=1;i<=7;i++) {
         var Day = (j * 7) + (i - FirstDate.getDay());
         if ((Day >= 1) && (Day <= this.MonthDays[this.displayMonth])) {
			currentDate = new Date(this.displayYear,this.displayMonth,Day,0,0,0);
			
		 	if (Math.round((currentDate - this.selectDate)/Calendar.OneDay) == 0) {
	            strCalendar += '<td class="select">';
			}else if (Math.round((currentDate - this.todayDate)/Calendar.OneDay) == 0){
	            strCalendar += '<td class="today">';
			}else {
				strCalendar += '<td>';
			}
			
			if ((currentDate - this.config.startDate >= 0) && (this.config.endDate - currentDate >= 0)) {
				strCalendar += '<a href="#" onclick="Calendar.pickedDate(this,eval(\'' + this.id + '\'),\'' + currentDate.getDate() + '\',\'' + currentDate.getMonth() + '\',\'' + currentDate.getFullYear() + '\');return false;">' + Day + '</a>';
			}else {
				strCalendar += Day;
			}
			
			strCalendar += '&nbsp;</td>';
         }
         else strCalendar += '<td>&nbsp;</td>';
      }
      strCalendar += '<td></td></tr>';
   }
	
	strCalendar += '<tr><td colspan="9" class="close"><a href="#" onclick="Calendar.hide(\'' + this.id + '\');return false;">Close</a></td></tr>';
	strCalendar += '</table>';
	
	return strCalendar;
} 

Calendar.setAutoHide = function(id) {
	var obj = eval(id);
	obj.hideEvent = setTimeout("Calendar.hide('" + id + "');",100);
}

Calendar.cancelHide = function(id) {
	clearTimeout(eval(id + '.hideEvent'));
};

Calendar.hide = function(id) {
	document.getElementById(id + '_div').style.visibility = 'hidden';
	document.getElementById(id + '_frame').style.display = 'none';
};

Calendar.prototype.display = function (obj) {
	if (obj) {
		this.parent = obj;
	}	

	this.calendarDiv.innerHTML = this.buildCalendar();
	
	this.iframeBkg.height = this.calendarDiv.offsetHeight;
	
	this.setPosition();

	this.calendarDiv.style.visibility = 'visible';
	if (Calendar.isMSIE && !Calendar.isMAC) this.iframeBkg.style.display = 'block';
};

Calendar.prototype.setPosition = function () {
	var xPos,yPos;
	
	xPos = this.findPosX();
	yPos = this.findPosY();
	
	if (this.config.displayPosition == 'auto') {
	    this.calendarDiv.style.top = yPos + this.parent.offsetHeight + 'px';
	    this.iframeBkg.style.top = yPos + this.parent.offsetHeight + 'px';

	    if ((xPos + this.calendarDiv.offsetWidth) > document.body.clientWidth) {
		    xPos = document.body.clientWidth - this.calendarDiv.offsetWidth - (Calendar.isMSIE?20:5);
	    };

	    this.calendarDiv.style.left = xPos + 'px';
	    this.iframeBkg.style.left = xPos + 'px';
	}else if (this.config.displayPosition == 'right') {
	    this.calendarDiv.style.top = yPos + 'px';
	    this.iframeBkg.style.top = yPos + 'px';

	    this.calendarDiv.style.left = xPos + this.parent.offsetWidth + 'px';
	    this.iframeBkg.style.left = xPos + this.parent.offsetWidth + 'px';
	}
};

Calendar.prototype.findPosX = function () {
	var obj = this.parent;

    var curleft = 0;
    if (obj.offsetParent) {
        while (obj.offsetParent) {
            curleft += obj.offsetLeft;
            obj = obj.offsetParent;
        };
    } else if (obj.x) {
        curleft += obj.x;
    };
    return curleft;
};

Calendar.prototype.findPosY = function () {
	var obj = this.parent;

    var curtop = 0;
    if (obj.offsetParent) {
        while (obj.offsetParent) {
            curtop += obj.offsetTop;
            obj = obj.offsetParent;
        };
    } else if (obj.y) {
        curtop += obj.y;
    };
    return curtop;
};

Calendar.addEvent = function (obj, name, handler) {
	// Browser check
	if (Calendar.isMSIE)
		if (!Calendar.isMAC) {
			obj.attachEvent("on" + name, handler);
		} else {
			switch (name) {
				case 'load':obj.onload = handler;break;
				case 'focus':obj.onfocus = handler;break;
				case 'blur':obj.onblur = handler;break;
				case 'resize':obj.onresize = handler;break;
			}
		}
	else
		obj.addEventListener(name, handler, false);
};
