function Calendar (container, showdate, showtime, title) {
    this._varname = null;
    $Lib.createGlobalVarName(this);
    
	this.Months = new Array("January", "February", "March", "April", "May", "June",
			"July", "August", "September", "October", "November", "December");
	this.MonthsMax = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
	this.WeekDays = new Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
			"Saturday");
	this.original = new Array(0, 1, 1, 0, 0, 0);
	//this.original = new Array(2006, 10, 27, 0, 0, 0);
	
	this.year = this.original[0]; this.month = this.original[1]; this.day = this.original[2];
	this.hours = this.original[3]; this.minutes = this.original[4]; this.seconds = this.original[5];
	this.weekday = 1; //Sunday
	
	this._HTMLControls = new Object();
	
	this.dateObj = null;
	this.MonthData = null;
	this.container = container; //String Format	will be converted to needed one later
	this.shown = false;
	
	this.showdate = showdate; //Show Date
	this.showtime = showtime; //Show Time
	
    this.hasDate = false;
	this.hasTime = false;
	
	this.title = title;
	this.vstore = null; /*Set vstore to an hidden field in a Form: i.e. FormName.FieldName*/
	this._cbData = new Array(); this._cbKinds = new Object();
	
	//ID's
	this.clitems = new Array();
	this.__datetime = null;
	this._HTMLControls.Title = null;
	this.__datectl = null;
	this.__calendar = null;
	this._HTMLControls.Year = null;
	this._HTMLControls.Month = null;
	this.__timectl = null;
	this._HTMLControls.Hours = null;
	this._HTMLControls.Minutes = null;
	this._HTMLControls.Seconds = null;
	this._HTMLControls.AMPM = null;
	this._HTMLControls.Value = null;
	
	this._leapYear = function (yr) {
		return ((yr % 4 == 0) && (yr % 100 != 0)) || (yr % 400 == 0);
	}	
	this._calculateWeekDay = function () {		
		if (!this.hasDate) return;
		this.weekday = this.dateObj.getDay() + 1; //1 sunday, 7 saturday
	}
	this._GenerateDateObj = function () {
	    this.dateObj = null;
	    if (this.hasDate && this.hasTime) {
	        this.dateObj = new Date(this.year, this.month - 1, this.day, this.hours, this.minutes, this.seconds);
        }
        else if (this.hasDate) {
            this.dateObj = new Date(this.year, this.month - 1, this.day);
        }
        else if (this.hasTime) {
            var dt = new Date();
            this.dateObj = new Date(dt.getFullYear(), dt.getMonth(), dt.getDate(), this.hours, this.minutes, this.seconds);
        }
    };
	this._GenerateMonthData = function () {
		this.MonthData = new Array();				
		var cnt, wday, pmonth, nmonth, pyear, nyear, pdays, acount, a, b;
		var _dy, _mnt, _yr;
		cnt = 0;
		
		wday = (this.day - 1) % 7;
		wday = this.weekday - wday;
		if (wday < 1) wday += 7;
		else if (wday > 7) wday -= 7;
		
		pmonth = (this.month - 1) < 1 ? (12 + this.month - 1) : (this.month - 1);
		pyear = (this.month - 1) < 1 ? this.year - 1 : this.year;
		
		nmonth = (this.month + 1) > 12 ? (this.month + 1 - 12) : (this.month + 1);
		nyear = (this.month + 1) > 12 ? this.year + 1 : this.year;
		
		pdays = this.MonthsMax[pmonth - 1] - wday + 2;
		
		acount = 0;
		for (a = 1; a <= 6; a++) {
			if (cnt >= this.MonthsMax[this.month - 1]) break;
					
			for (b = 1; b <= 7; b++) {
				acount++;
				_dy = _mnt = _yr = 0;
				
				if (pdays <= this.MonthsMax[pmonth - 1]) {
					_dy = pdays; _mnt = pmonth; _yr = pyear;				
					pdays++;
				}
				else {
					cnt++;
					if (cnt > this.MonthsMax[this.month - 1]) {
						_dy = (cnt - this.MonthsMax[this.month - 1]); _mnt = nmonth; _yr = nyear;
					}
					else {
						_dy = cnt; _mnt = this.month; _yr = this.year;
					}
				}
				this.MonthData[acount] = new Array(_yr, _mnt, _dy);
			}
		}		
	}
	//1900 through 1999
	this.getYear = function () { return this.year >= 1900 && this.year <= 1999 ? (this.year - 1900) : this.year; };
	this.getFullYear = function () { return this.year; };
	this.getMonth = function () { return this.month; }; //Month starts from 1
	this.getDate = function () { return this.day; };
	this.getHours = function () { return this.hours; };
	this.getMinutes = function () { return this.minutes; };
	this.getSeconds = function () { return this.seconds; };
	this.getDay = function () { return this.weekday; }; //Starts from 1
	this.getDayStr = function () { return this.WeekDays[this.weekday - 1]; };
	this.getDateObj = function () { return this.dateObj; };
	this.getDatePart = function () { return this.hasDate ? $Lib.LPad(this.year, 4) + "-" +
			$Lib.LPad(this.month, 2) + "-" + $Lib.LPad(this.day, 2) : null;
	};
	this.getTimePart = function () { return this.hasTime ? $Lib.LPad(this.hours, 2) + ":" +
			$Lib.LPad(this.minutes, 2) + ":" + $Lib.LPad(this.seconds, 2) : null;
	};
	this.toString = function () {
		var s = "";
		if (this.hasDate) s += $Lib.LPad(this.year, 4) + "-" + $Lib.LPad(this.month, 2)
				 + "-" + $Lib.LPad(this.day, 2);
		if (this.hasDate && this.hasTime) s += " ";
		if (this.hasTime) s += $Lib.LPad(this.hours, 2) + ":" + $Lib.LPad(this.minutes, 2)
				 + ":" + $Lib.LPad(this.seconds, 2);
		return s;
	}
	this.getWeekOfYear = function () {
		var a, b, days, dt, add_days, sum = 0;
		dt = new Date(this.year, 1, 1);
		add_days = dt.getDay();
		
		for (a = 1; a < this.month; a++) sum += this.MonthsMax[a - 1];
		sum += this.day;
		sum += add_days;
		return Math.ceil(sum / 7);
	}
	this.setCallBacks = function (callback, callbackobj, vstore) {
		var x = $Lib.createCallBack(this, 'changenotify', callback, callbackobj);
		this.vstore = vstore;
		return x;
	}
	this.changeTitle = function (title) {
		this.title = title;
		if (this._HTMLControls.Title) {
			this._HTMLControls.Title.innerHTML = title || "";
			
			if (this.title) {
				try {
					this._HTMLControls.Title.style.display = "table-cell";
				}
				catch (e) {
					try {
						this._HTMLControls.Title.style.display = "block";
					}
					catch (e) {}
				}
			}
			else {
				this._HTMLControls.Title.style.display = "none";
			}
		}
	}
	this.setStatus = function (stext) {
	    this._HTMLControls.Value.innerHTML = stext;
    }	
	this.pickDate = function (yr, mnt, dy /*, userselect*/) {
		var yr, _yr, mnt, _mnt, dy, _dy, cb, dt;
		
		yr = $Lib.parseInt(yr); mnt = $Lib.parseInt(mnt); dy = $Lib.parseInt(dy);
		_yr = this.year; _mnt = this.month; _dy = this.day;
		cb = new this.CallBackObj(this);
		
		if (arguments.length > 3 && arguments[3])
			cb.userSelect = arguments[3];
		
		dt = new Date(yr, mnt - 1, dy);
		if (dt) {
		    var mmax, leapyr = this._leapYear(yr);
		    if (leapyr) {
		        if (mnt == 2) mmax = 29;
		        else mmax = this.MonthsMax[mnt - 1];
            }
            else {
                if (mnt == 2) mmax = 28;
		        else mmax = this.MonthsMax[mnt - 1];
            }
		
		    if (dy > mmax) {
		        dy = mmax;
		        cb.dayrollback = true;
            }
            
            dt = new Date(yr, mnt - 1, dy);
            if (yr == dt.getFullYear() && mnt == (dt.getMonth() + 1) && dy == dt.getDate()) {
                cb.putDate(yr != _yr, mnt != _mnt, dy != _dy);
                this.year = yr; this.month = mnt; this.day = dy;
                
                if (mnt == 2) this.MonthsMax[1] = mmax; //February
                
                this.hasDate = true;
                this._GenerateDateObj();
                this._calculateWeekDay();									
				
                if (this.showdate && this.shown) this.showCalendar();
				
				if (this.vstore) document.getElementById(this.vstore).value = this.toString();
				$Lib.callMultipleCallBack(this, 'changenotify', cb);
				return true;
		    }
        }
	}
	this.pickTime = function (hrs, mins, secs /*, userselect*/) {
		var _hrs, hrs, _mins, mins, _secs, secs, cb, d;
		
		_hrs = this.hours; _mins = this.minutes; _secs = this.seconds;		
		hrs = $Lib.parseInt(hrs); mins = $Lib.parseInt(mins); secs = $Lib.parseInt(secs);		
		cb = new this.CallBackObj(this);
        cb.putTime(hrs != _hrs, mins != _mins, secs != _secs);
		
		if (arguments.length > 3 && arguments[3]) 
			cb.userSelect = arguments[3];
		
        d = new Date();
		t1 = new Date(d.getFullYear(), d.getMonth(), d.getDate(), hrs, mins, secs);			
		if (hrs == t1.getHours() && mins == t1.getMinutes() && secs == t1.getSeconds()) {	
            this.hours = hrs; this.minutes = mins; this.seconds = secs;

            this.hasTime = true;
            this._GenerateDateObj();
            
			if (this.showtime && this.shown) {						
				if (this.hours > 11) {
					this._HTMLControls.Hours.value = this.hours - 12;
					this._HTMLControls.AMPM.value = "PM";
				}
				else {
					this._HTMLControls.Hours.value = this.hours;
					this._HTMLControls.AMPM.value = "AM";
				}
				this._HTMLControls.Minutes.value = this.minutes;
				this._HTMLControls.Seconds.value = this.seconds;
				this.setStatus("{ " + this.toString() + " }");	
			}					
			
			if (this.vstore) document.getElementById(this.vstore).value = this.toString();					
			$Lib.callMultipleCallBack(this, 'changenotify', cb);
			
			return true;
		}
	}
	this.showCalendar = function () {
		var op, acount, color, hcolor, a, b, cell, wn, s;		
		
		if (this.showdate) {
			this._GenerateMonthData();
			op = '';
			op += '<table align=center cellspacing=1 border=0 width="173px" style="font-family: Verdana; font-size: 11px;">';
			
			op += '<tr>'; //Generate the Header
			for (b = 0; b < 7; b++) {
				op += '<td height="13" width="22" align="center" bgcolor="#AECDAD">';
				op += this.WeekDays[b].substr(0, 3);
				op += '</td>';
			}
			op += '</tr>'; //End Generating the Header	
			acount = 0;
			color = "";
			hcolor = "#70A76E";
			
			for (a = 1; a <= 6; a++) {
				if (acount == (this.MonthData.length - 1)) break;
				op += '<tr>';
				for (b = 1; b <= 7; b++) {
					acount++;
					cell = this.MonthData[acount];
					
					if (cell[1] < this.month || cell[1] > this.month) color = "#F7FCF8";
					else if (cell[2] == this.day) color = "#70A76E";
					else color = "transparent";
					
					op += '<td height=13 style="cursor: pointer; background-color: ' + color + ';';				
					if (cell[1] == this.month && cell[2] == this.day) op += ' font-weight: bold;';					
					op += '" align=center';					
					
					
					op += ' onClick="' + this._varname + '.pickDate(' + cell[0] + ', ' +
					cell[1] + ', ' + cell[2] + ', 3)"' +
					' onMouseOver="this.style.backgroundColor=\'' + hcolor + '\';"' +
					' onMouseOut="this.style.backgroundColor=\'' + color + '\';">';
					
					wn = this.WeekDays[b - 1].substr(0, 3).toLowerCase();
					
					if (wn == "sun" || wn == "sat") op += '<font color="#FF0000">';
					op += cell[0] < 0 ? "*" : cell[2];
					if (wn == "sun" || wn == "sat") op += '</font>';	
					
					op += '</td>\n';
				}
				op += '</tr>\n';
			}
			op += '</table>\n';
		}
		
		if (!this.shown) {
			this.container = document.getElementById(this.container);
			op1 = '<table width=175 cellspacing=0 cellpadding=0 style="border: 1px solid #CADDC9;">';
			op1 += '<tr><td align=center height=15 style="border-bottom: 1px solid #CADDC9;' +
			' background-color: #CADDC9; font-size: 11px; font-family: Verdana; font-weight: ' +
			'bold;">&nbsp;</td></tr>'; //Title Store
			
			if (this.showdate) {				
				op1 += '<tr><td align=center>' +
				'<a style="color: #0000FF" href="javascript:;" onClick="' + this._varname + '.UpdYear(-1);"><b>&laquo;</b></a> ' +
				'<input type=text maxlength=4 size=5' +
				' style="text-align: center; font-family: Verdana; font-size:11px; border: 1px solid #000000"' +
				' onBlur="' + this._varname + '.YearEvent();" title="Type and Click Outside">' +
				' <a style="color: #0000FF" href="javascript:;" onClick="' + this._varname + '.UpdYear(1);"><b>&raquo;</b></a>' +				
				'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' +				
				'<a style="color: #0000FF" href="javascript:;" onClick="' + this._varname +
				'.UpdMonth(-1);"><b>&laquo;</b></a> ' +
				'<select style="font-family: ' +
				'Verdana; font-size:11px;" onChange="' + this._varname + '.MonthEvent();">';
				
				for (a = 1; a <= 12; a++)
					op1 += '<option value="' + a + '">' + this.Months[a - 1].substr(0, 3);
				
				op1 += '</select>' +
				' <a style="color: #0000FF" href="javascript:;" onClick="' + this._varname +
					'.UpdMonth(1);"><b>&raquo;</b></a>' +
				
				'</td></tr>' +
				'<tr><td align=center>&nbsp;</td></tr>';
			}
			if (this.showtime) {
				op1 += '<tr><td align=center height=15 style="border-bottom: 1px solid #CADDC9;' +
				' border-top: 1px solid #CADDC9;' +
				' background-color: #CCCCCC; font-size: 10px; font-family: Verdana;">' +
				'Time (hh:mm:ss am/pm)</td></tr>' +
				
				'<tr><td align=center height=28>' +
				
				'<select style="font-family: Verdana; font-size:11px; width: 42px;"' +
				' onChange="' + this._varname + '.TimeEvent(1);">';
				
				for (a = 0; a <= 11; a++) op1 += '<option value="' + a + '">' + a;
				op1 += '</select>' +
				
				'<select style="font-family: Verdana; font-size:11px; width: 42px;"' +
				' onChange="' + this._varname + '.TimeEvent(2);">';
				
				for (a = 0; a <= 59; a++) op1 += '<option value="' + a + '">' + a;
				op1 += '</select>' +				
				'<select style="font-family: Verdana; font-size:11px; width: 42px;"' +
				' onChange="' + this._varname + '.TimeEvent(3);">';
				
				for (a = 0; a <= 59; a++) op1 += '<option value="' + a + '">' + a;
				op1 += '</select>' +
				'<select style="font-family: Verdana; font-size:11px; width: 42px;"' +
				' onChange="' + this._varname + '.TimeEvent(1);">' +
				'<option value="AM">AM' +
				'<option value="PM">PM' + 				
				'</select>' +								
				'</td></tr>';
			}
			
			op1 += '<tr><td align=center height=15 style="border-top: 1px solid #CADDC9;' +
				' background-color: #CADDC9; font-size: 11px; font-family: Verdana;">' +
				'{ Date Value }</td></tr></table>';
			
			this.container.innerHTML = op1; // + '<hr align="center" width="175" />';
			this.__datetime = this.container.getElementsByTagName("TABLE")[0];//childNodes[0];
			this.Show();
			
			var offset = 0;
			this._HTMLControls.Title = this.__datetime.getElementsByTagName("TR")[offset].getElementsByTagName("TD")[0];
			this.changeTitle(this.title);
			offset++;
			
			if (this.showdate) {
				this.__datectl = this.__datetime.getElementsByTagName("TR")[offset].getElementsByTagName("TD")[0];
				this._HTMLControls.Year = this.__datectl.getElementsByTagName("INPUT")[0];
				this._HTMLControls.Month = this.__datectl.getElementsByTagName("SELECT")[0];				
				offset++;
				
				this.__calendar = this.__datetime.getElementsByTagName("TR")[offset].getElementsByTagName("TD")[0];
				offset++;				
			}
			
			if (this.showtime) {
				offset++;
				this.__timectl = this.__datetime.getElementsByTagName("TR")[offset].getElementsByTagName("TD")[0];
				this._HTMLControls.Hours = this.__timectl.getElementsByTagName("SELECT")[0];
				this._HTMLControls.Minutes = this.__timectl.getElementsByTagName("SELECT")[1];
				this._HTMLControls.Seconds = this.__timectl.getElementsByTagName("SELECT")[2];
				this._HTMLControls.AMPM = this.__timectl.getElementsByTagName("SELECT")[3];
				offset++;				
			}
			this._HTMLControls.Value = this.__datetime.getElementsByTagName("TR")[offset].getElementsByTagName("TD")[0];
						
			this.shown = true;
			this.pickTime(this.hours, this.minutes, this.seconds);
		}		
		
		if (this.showdate) {				
			this.__calendar.innerHTML = op;
			this._FillTds();
			
			this._HTMLControls.Year.value = $Lib.LPad(this.year, 4);
			this._HTMLControls.Month.selectedIndex = this.month - 1;
			
			s = this.toString();
			if (this.vstore) document.getElementById(this.vstore).value = s; 
			this.setStatus("{ " + s + " }");
		}		
	}
	this._FillTds = function () {
		var acount, a;
		var cal_tds = this.__calendar.getElementsByTagName("TABLE")[0].getElementsByTagName("TR");
		this.clitems = new Array();
		
		acount = 0;
		for (a = 1; a < cal_tds.length; a++) {
			var cal_td = cal_tds[a].getElementsByTagName("TD");
			for (b = 0; b < 7; b++) {
				acount++;
				this.clitems[acount] = cal_td[b];
			}
		}
	}
	this.useClientTime = function () {
		var dt;
		dt = new Date();
		this.pickDate(dt.getFullYear(), dt.getMonth() + 1, dt.getDate());
		this.pickTime(dt.getHours(), dt.getMinutes(), dt.getSeconds());  
	}
	this.loadDate = function (d) {
		d = d.split("-");
		return this.pickDate(d[0], d[1], d[2]);
	}
	this.loadTime = function (t) {
		t = t.split(":");
		return this.pickTime(t[0], t[1], t[2]);
	}
	this.loadDateTime = function (dt) {
		dt = dt.split(" ");
		return (this.loadDate(dt[0]) && this.loadTime(dt[1]));
	}
	this.Hide = function () {
		try {this.__datetime.style.visibility = "hidden";} catch (e) { }
		try {this.__datetime.style.display = "none";} catch (e) { }
	}
	this.Show = function () {
		try {this.__datetime.style.visibility = "visible";} catch (e) { }
		try {this.__datetime.style.display = "block";} catch (e) { }
	}
	this.Visible = function () {
		return this.__datetime.style.display.toLowerCase() == "block" &&
			this.__datetime.style.visibility.toLowerCase() == "visible";
	}	
	this.YearEvent = function () {	
		if ($Lib.isNaN(this._HTMLControls.Year.value)) {
			alert("Invalid Year");
			return false;
		}
		this.pickDate(this._HTMLControls.Year.value, this._HTMLControls.Month.value, this.day, 1);
	}
	this.UpdYear = function (val) {
		if ($Lib.isNaN(this._HTMLControls.Year.value)) {
			alert("Invalid Year");
			return false;
		}
		this._HTMLControls.Year.value = $Lib.parseInt(this._HTMLControls.Year.value) + val;
		if (this._HTMLControls.Year.value < 0) this._HTMLControls.Year.value = 0;
		this.YearEvent();
	}
	this.MonthEvent = function () {
		this.pickDate(this._HTMLControls.Year.value, this._HTMLControls.Month.value, this.day, 2);
	}
	this.UpdMonth = function (val) {
		if ( (val > 0 && this._HTMLControls.Month.value != 12 ) ||
			(val < 0 && this._HTMLControls.Month.value != 1 ) ) this._HTMLControls.Month.selectedIndex += val;
		this.MonthEvent();
	}
	this.TimeEvent = function (how) {
		this.pickTime(this._HTMLControls.AMPM.value == "AM" ? this._HTMLControls.Hours.value : $Lib.parseInt(this._HTMLControls.Hours.value) + 12,
			this._HTMLControls.Minutes.value, this._HTMLControls.Seconds.value, how);
	}
	this.CallBackObj = function (Obj) {
	    this.clObj = Obj;
	    this.userSelect = 0; /*selected option by user?*/
    	
        this.time = false;
        this.date = false;

        this.putDate = function (year, month, day) {
            this.date = true;
            this.year = year;
	        this.month = month;
	        this.day = day;
	        this.dayrollback = false; /*day changed by month select i.e. jun && dy == 31?*/
        }
        this.putTime = function (hrs, mins, secs) {
            this.time = true;
            this.hrs = hrs;
	        this.mins = mins;
	        this.secs = secs;
        }
    }
	this.Close = function () {
		try {
		    var i;
		    try { this.container.innerHTML = ""; } catch (e) { }
		    $Lib.deleteGlobalVarName(this);		
            $Lib.deleteCallBacks(this);

		    for (i in this) {
		        try {
		            delete this[i];
		        }
		        catch (e) {}
		    }
		}
		catch (e) { }
		this.Close = new Function("return;");
	}
}
