// JavaScript Document
function SimpleCalendar() {
		var thisRef = this;	
		//entropy ensures multiple instances of the SimpleCalendar running w/o issues
		var entropy = Math.round(Math.random() * 100000000);
		//Calendar mechanism		
		var cd = new Calendar();
		this.Calendar = cd;
		//If we want to select a date		
		this.selectedDate = null;	//Date object
		//Public functions		
		this.containerId = "cal_" + entropy;
		this.startDate = null;	//Starting value from wich calendar is enabled 	(String) mm/dd/yyyy
		this.endDate = null;	//Ending value till wich calendar is enabled	(String) mm/dd/yyyy
		this.onDateSelect;	//Assign a custom function that gets triggerd on date select
		this.inputObject;	//Assign an input object where u want values to go after selection
		this.setInput = function(id) {
			var io = getObject(id);
			if(io) { thisRef.inputObject = io; }
		}
		this.hideOnSelect = true;
		this.hide = function() { calHolder.style.display = "none"; }
		this.refresh = function() { show(false) };
		//Generic show function
		var show = function(adv) {			
			var startDtObj = null;
			var endDtObj = null;
			var inputDtObj = null;
			var selDtObj = null;
			
			var dtObj = new Date();
			if(thisRef.inputObject != null) {
				try {
					var dtStr = thisRef.inputObject.value;
					thisRef.selectedDate = (!isEmpty(dtStr))?dtStr:thisRef.selectedDate;
					inputDtObj = (isEmpty(dtStr))?null:dtObj.parseShortDate(dtStr); //Custom function
					if(!isNaN(inputDtObj)) {
						if(!adv) {
							cd.setCurrentDate(inputDtObj.getFullYear(), inputDtObj.getMonth()+1, inputDtObj.getDate());
						}
					} else {
						inputDtObj = null;
					}
				} catch(e) {
					inputDtObj = null;
				}				
			}
			if(thisRef.selectedDate != null) {
				selDtObj = dtObj.parseShortDate(thisRef.selectedDate);
				selDtObj = isNaN(selDtObj)?null:selDtObj;
				if(!adv && selDtObj) {
					cd.setCurrentDate(selDtObj.getFullYear(), selDtObj.getMonth()+1, selDtObj.getDate());
				}
			}
			if(thisRef.startDate != null) {
				startDtObj = dtObj.parseShortDate(thisRef.startDate);
				startDtObj = isNaN(startDtObj)?null:startDtObj;
			}
			if(thisRef.endDate != null) {
				endDtObj = dtObj.parseShortDate(thisRef.endDate); 
				endDtObj = isNaN(endDtObj)?null:endDtObj;
			}
			drawCalendar(selDtObj, startDtObj, endDtObj);			
			calHolder.style.display = "block";
		}		
		
		//Div to hold calendar
		var calHolder = document.createElement("div");
			calHolder.setAttribute("id", thisRef.containerId);
			calHolder.className = "calendarHolder";
			calHolder.style.display = "none";
			
		this.showIn = function(id) {
			thisRef.containerId = id;
			calHolder = getObject(id);
			drawCalendarStructure(false);
			show(false);
		}
		//Will show a calendar at specified position offset from the clicked object
		// obj - clicked object
		// x - X-Axis offset
		// y - Y-Axis offset
		this.showAt = function(obj, x, y) {
			var objHeight = obj.clientHeight;
			var pos = findPos(obj);
			
			show(false);
			calHolder.style.left = (pos[0] + x) + "px";
			calHolder.style.top = (pos[1] + y) + "px";			
		}
		//Will show a calendar below an object
		this.showBelow = function(obj) {
			var objHeight = obj.clientHeight;
			var pos = findPos(obj);
			
			show(false);
			calHolder.style.left = pos[0] + "px";
			calHolder.style.top = (pos[1] + objHeight + 2) + "px";			
		}
		//Will show a calendar above an object
		this.showAbove = function(obj) {
			var objHeight = obj.clientHeight;
			var pos = findPos(obj);			
			
			show(false);
			calHolder.style.left = pos[0] + "px";
			calHolder.style.top = (pos[1] - (calHolder.clientHeight + 2)) + "px";			
		}
		//Will show a calendar to the right of an object
		this.showToRight = function(obj) {
			var objWidth = obj.clientWidth;			
			var pos = findPos(obj);
			
			show(false);
			calHolder.style.left = (pos[0] + objWidth + 3) + "px";
			calHolder.style.top = pos[1] + "px";			
		}
		//Will show a calendar to the left of an object
		this.showToLeft = function(obj) {
			var objWidth = obj.clientWidth;			
			var pos = findPos(obj);
			
			show(false);
			calHolder.style.left = (pos[0] - (calHolder.clientWidth+2)) + "px";
			calHolder.style.top = pos[1] + "px";			
		}
		//Write a calendar to HTML body
		document.body.appendChild(calHolder);
		
		//Define events speciffic to each instance
		this.gotoNextYear = window["nextYear_" + entropy] = function() {
			cd.advanceYears(1);
			show(true);
		}
		this.gotoPrevYear = window["prevYear_" + entropy] = function() {
			cd.advanceYears(-1);
			show(true);
		}
		this.gotoNextMonth = window["nextMonth_" + entropy] = function() {
			cd.advanceMonths(1);
			show(true);
		}
		this.gotoPrevMonth = window["prevMonth_" + entropy] = function() {
			cd.advanceMonths(-1);
			show(true);
		}		
		//Goes to today callendar day
		this.gotoToday = window["gotoToday_" + entropy] = function() {
			cd.gotoToday();
			show(true);
		}		
		//Cell hover over effect
		window["cellOver_" + entropy] = function(cellObj) {
			cellObj.className = "calendarDayOver";
		}
		//Cell hover over effect
		window["hide_" + entropy] = function() {
			thisRef.hide();
		}		
		//Cell hover out effect
		window["cellOut_" + entropy] = function(cellObj) {
			var isToday = (cellObj.getAttribute("today") == "yes")?true:false;
			var isSelected = (cellObj.getAttribute("selected") == "yes")?true:false;			
			if(!isSelected) {
				cellObj.className = "calendarDay";
			} else {
				cellObj.className = "calendarDaySelected";
			}			
			if(!isToday) {
				if(!isSelected) {
					cellObj.className = "calendarDay";
				}
			} else {
				cellObj.className = "calendarDayToday";
			}			
		}
		//Pick date		
		window["pickDate_" + entropy] = function(cellObj) {
			var dd = cellObj.getAttribute("dd");
			var mm = cellObj.getAttribute("mm");
			var yy = cellObj.getAttribute("yy");
			if(thisRef.onDateSelect != null) {								
				thisRef.onDateSelect(mm, dd, yy);
				if(thisRef.hideOnSelect) {
					thisRef.hide();
				}
			}
			if(thisRef.inputObject != null) {			
				dd = (parseInt(dd) < 10)?"0"+dd:dd;
				mm = (parseInt(mm) < 10)?"0"+mm:mm;
								
				thisRef.inputObject.value = mm + "/" + dd + "/" + yy;
				if(thisRef.hideOnSelect) {
					thisRef.hide();
				}
			}
			if(thisRef.hideOnSelect) {				
				cellObj.setAttribute("selected", "yes");
				cellObj.className = "calendarDaySelected";
			} else {
				var nDate = new Date(yy, mm, dd);
				thisRef.selectedDate = nDate;
				thisRef.refresh();				
			}
		}
		
		function drawCalendarStructure(hasClose) {
			//Create a calendar box w/nav controls
			var calStruc = new SimpleTable(1, 4);
			calStruc.width = "100%"
			calStruc.border = 0;
			calStruc.spacing = 1;
			calStruc.padding = 0;
			
			var hdrBar = new SimpleTable(2, 1);
			var yrSelector = new SimpleTable(3, 1);
			var moSelector = new SimpleTable(3, 1);
			
			//Header
			var tdy = hdrBar.Cell(0, 0);
			tdy.value = new SimpleLink("javascript: gotoToday_" + entropy + "()", "Today").toHTML();
			tdy.setAttribute("class", "calendarToolbar");
			
			var cls = hdrBar.Cell(1, 0);
			if(hasClose) {
				cls.value = new SimpleLink("javascript: hide_" + entropy + "()", "X").toHTML();
				cls.setAttribute("title", "Close calendar");
			} else {
				cls.value = "&nbsp;"
			}
			cls.setAttribute("width", "16");
			cls.setAttribute("align", "right");
			cls.setAttribute("class", "calendarToolbar");
			
			//year Nav
			yrSelector.id = "calendarYrSelector";
			var pYr = yrSelector.Cell(0, 0);
			pYr.value = new SimpleLink("javascript: prevYear_" + entropy + "()", "&laquo;").toHTML();
			pYr.setAttribute("class", "calendarNav");
			pYr.setAttribute("title", "Go to Previous Year");
			
			var cYr = yrSelector.Cell(1, 0);
			cYr.setAttribute("id", entropy + "_fldYear");
			cYr.value = cd.Year;
			cYr.setAttribute("class", "curPos");
			
			var nYr = yrSelector.Cell(2, 0);
			nYr.value = new SimpleLink("javascript: nextYear_" + entropy + "()", "&raquo;").toHTML();
			nYr.setAttribute("class", "calendarNav");
			nYr.setAttribute("title", "Go to Next Year");
			
			//Month Nav
			var pMo = moSelector.Cell(0, 0);
			pMo.value = new SimpleLink("javascript: prevMonth_" + entropy + "()", "&laquo;").toHTML();
			pMo.setAttribute("class", "calendarNav");
			pMo.setAttribute("title", "Go to Previous Month");
			
			var cM = moSelector.Cell(1, 0);
			cM.setAttribute("id", entropy + "_fldMonth");
			cM.value = cd.getMonthName(cd.Month);
			cM.setAttribute("class", "curPos");
			
			var nMo = moSelector.Cell(2, 0)
			nMo.value = new SimpleLink("javascript: nextMonth_" + entropy + "()", "&raquo;").toHTML();
			nMo.setAttribute("class", "calendarNav");
			nMo.setAttribute("title", "Go to Next Month");
					
			calStruc.Cell(0, 0).value = hdrBar.toHTML();
			calStruc.Cell(0, 1).value = yrSelector.toHTML();
			calStruc.Cell(0, 2).value = moSelector.toHTML();		
			calStruc.Cell(0, 3).setAttribute("id", entropy + "_divCalendar");
	
			//Render Nav Controls
			calHolder.innerHTML = calStruc.toHTML();
		}//Render Calendar itself
		
		drawCalendarStructure(true);
		drawCalendar();
		//Renders an active/inactive day
		function renderCalendarDay(cellObj, dd, mm, yy, start, end) {
			var flg = true;
			if(start) {
				var tempDt = new Date(yy, mm-1, dd);
				if(tempDt < start) {					
					flg = false;
					cellObj.inactive = true;
					cellObj.setAttribute("class", "calendarDayDisabled");
				}
			}
			if(end) {
				var tempDt = new Date(yy, mm-1, dd);
				if(tempDt > end) {					
					flg = false;
					cellObj.inactive = true;
					cellObj.setAttribute("class", "calendarDayDisabled");
				}
			}
			cellObj.value = dd;
			if(flg) {
				cellObj.setAttribute("dd", dd);
				cellObj.setAttribute("mm", mm);
				cellObj.setAttribute("yy", yy);
			}
		}
		//Renders a calendar grid
		function drawCalendar(selectedDay, start, end) {
			//Intialize callendar position
			cd.setCurrentDate(cd.Year, cd.Month, 1);
			//Current month		
			var thisMonth = parseInt(cd.Month);
			var thisYear = parseInt(cd.Year);
			var dt = new Date();
			var curDay = dt.getDate();
			var curMonth = dt.getMonth()+1;
			var curYear = dt.getFullYear();
				
			var mField = getObject(entropy + "_fldMonth");
				mField.innerHTML = cd.getMonthName(cd.Month);
			var yField = getObject(entropy + "_fldYear");
				yField.innerHTML = cd.Year;
									
				//Calendar weeks
				var maxDays = cd.getMaxDays(cd.Month-1, cd.Year);			
				var firstDOW = parseInt(cd.firstDayOfWeek(cd.Month, cd.Year));
				var weeks = Math.ceil((maxDays+(firstDOW-7))/7);
							
				var grd = new SimpleTable(7, weeks+2);
				grd.width = "100%";			
				grd.spacing = 1;
				
				var i = 0;
				var cCell;
				var dNames = ["S", "M", "T", "W", "T", "F", "S"];
				do {
					cCell = grd.Cell(i, 0);
					cCell.setAttribute("class", "calendarHeader");				
					cCell.value = dNames[i];
				} while(i++ < 6);
				
				var w = 0;
				var week = new Array(7);
				var d = 0;
				var cDay;
				//loop weeks
				do {
					//loop dow's
					do {					
						//First week may have less days
						cDay = grd.Cell(d, w+1);
						cDay.setAttribute("class", "calendarDay");					
						switch(true) {
							case (w==0):
								if(d < firstDOW) {
									cDay.value = "&nbsp;"									
									cDay.setAttribute("class", "calendarInactiveDay");
								} else {
									renderCalendarDay(cDay, cd.Date, thisMonth, thisYear, start, end);									
								}						
								if(d >= firstDOW) {
									cd.advanceDays(1);
								}							
								break;
							case (w == weeks):
								if(parseInt(cd.Year) == thisYear) {
									if(parseInt(cd.Month) > thisMonth) {
										cDay.value = "&nbsp;"
										cDay.setAttribute("class", "calendarInactiveDay");
									} else {										
										renderCalendarDay(cDay, cd.Date, thisMonth, thisYear, start, end);
									}						
								} else {
									cDay.value = "&nbsp;";
									cDay.setAttribute("class", "calendarInactiveDay");
								}
								if(thisMonth == parseInt(cd.Month)) {
									cd.advanceDays(1);
								}
								break;
							default:
								if(parseInt(cd.Year) == thisYear) {
									if(parseInt(cd.Month) > thisMonth) {
										cDay.value = "&nbsp;"
										cDay.setAttribute("class", "calendarInactiveDay");
									} else {
										renderCalendarDay(cDay, cd.Date, thisMonth, thisYear, start, end);
									}
								} else {
									cDay.value = "&nbsp;";
									cDay.setAttribute("class", "calendarInactiveDay");
								}
								cd.advanceDays(1);
						}
						if(cDay.value != "&nbsp;") {
							//Show selected date
							if(selectedDay != null) {
								if(parseInt(cDay.value) == selectedDay.getDate() && thisMonth == selectedDay.getMonth()+1 && thisYear == selectedDay.getFullYear()) {
									cDay.setAttribute("class", "calendarDaySelected");
									cDay.setAttribute("selected", "yes");
								}
							}
							//Today Overrides Selected Date
							if(parseInt(cDay.value) == curDay && curMonth == thisMonth && curYear == thisYear) {
								cDay.setAttribute("class", "calendarDayToday");
								cDay.setAttribute("today", "yes");
							}
							try {
								var isInactive = cDay.inactive;
								if(!isInactive) {
									cDay.setAttribute("onmouseover", "cellOver_" + entropy + "(this)");
									cDay.setAttribute("onmouseout", "cellOut_" + entropy + "(this)");
									cDay.setAttribute("onclick", "pickDate_" + entropy + "(this)");
								}
							} catch(e) {}
						}
					} while(d++ < 6);
					d = 0;
					//iterate week
				} while(w++ < weeks);
				//Intialize callendar position
				cd.setCurrentDate(thisYear, thisMonth, 1);
				//Draw it
				var calDiv = getObject(entropy + "_divCalendar");
				calDiv.innerHTML = grd.toHTML();
		}
		//Finds object position
		function findPos(obj) {
			var curleft = curtop = 0;
			if(typeof obj == "object") {
				if (obj.offsetParent) {
					curleft = obj.offsetLeft
					curtop = obj.offsetTop
					while (obj = obj.offsetParent) {
						curleft += obj.offsetLeft
						curtop += obj.offsetTop
					}
				}
			}
			return [curleft,curtop];
		}
	}
