// JavaScript Document
DatePicker = function() {
	// Private Properties
	var months = new Array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
	var dayLabel = new Array('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
	var today = new Date();
	var viewable = new Date();
	var activeDate = today;
	var writebackElement; 
	// Create Main DIV
	var calendarDiv;
	
	// Private Methods
	
	// Add Events
	function addEvent(obj, eventType, func) {
		if (obj.attachEvent) {
			var success = obj.attachEvent("on" + eventType, func);
			return success;
		} else if (obj.addEventListener) {
			obj.addEventListener(eventType, func, false);
			return true;
		} else {
			obj["on" + eventType] = func;
		}
	}
	// Remove Events
	function removeEvent(obj, eventType, func) {
		if (obj.removeEventListener) {
			obj.removeEventListener(eventType, func, false);
			return true;
		} else if (obj.detachEvent) {
			var success = obj.detachEvent('on' + eventType, func)
			return success;
		} else {
			return false;
		}
	}
	function createElement(elementType, parent, text) {
		var newElement = document.createElement(elementType);
		if (parent) {
			parent.appendChild(newElement);
		}
		if (text) {
			newElement.appendChild(document.createTextNode(text));
		}
		return newElement;
	}
	
	return {
		hide: function() {
			if (calendarDiv && calendarDiv.style) {
				calendarDiv.style.display = 'none';	
			}
		},
		getWritebackElement: function() {
			return writebackElement;
		},
		getEventTarget: function(e) {
			var el;
			if (e) {
				if (e.srcElement) el = e.srcElement;
				if (e.target) el = e.target;
			} else if (window.event) {
				if (window.event.srcElement) el = window.event.srcElement;
				if (window.event.target) el = window.event.target;
			} else {
				alert('Unable to capture and event in your browser');
			}
			
			return el;
		},
		removeClass: function(classElement, className) {
			if (!classElement || !className) {
				return;
			}
			var newClassNames = new Array();
			var classNames = classElement.className.split(' ');
			for (var i = 0; i < classNames.length; i++) {
				if (classNames[i] != className) {
					newClassNames[newClassNames.length] = classNames[i];
				}
			}
			classElement.className = newClassNames.join(' ');
		},
		appendClass: function(classElement, className) {
			if (!classElement || !className) {
				return;
			}
			classElement.className += ' ' + className;
		},
		onMouseOver: function(e) {
			var eventTarget = DatePicker.getEventTarget(e);
			DatePicker.appendClass(eventTarget, 'selected');
		},
		onMouseOut: function(e) {
			var eventTarget = DatePicker.getEventTarget(e);
			DatePicker.removeClass(eventTarget, 'selected');
		},
		onDayClick: function(e) {
		    var eventTarget = DatePicker.getEventTarget(e);
		    var day = eventTarget.getAttribute('day');
		    var month = eventTarget.getAttribute('month');
		    var year = eventTarget.getAttribute('year');
		    DatePicker.getWritebackElement().value = month + '/' + day + '/' + year; 
			DatePicker.hide();
		},
		days_in_month: function(m_month, m_year) {
			// set the month and year to the objects month and year
			var f_year = viewable.getFullYear();
			var f_month = viewable.getMonth() + 1;
			// check for a passed in month and/or year.
			if (m_month) f_month = m_month;
			if (m_year) f_year = m_year;
			// return the number of days in the defined month/year
			return 32 - new Date(f_year, f_month - 1, 32).getDate();
		},
		days_prev_month: function(m_month, m_year) {
			// set the month and year to the objects month and year
			var f_year = viewable.getFullYear();
			var f_month = viewable.getMonth() + 1;
			// check for a passed in month and/or year.
			if (m_month) f_month = m_month;
			if (m_year) f_year = m_year;
			// Check for January
			if (f_month == 1) { 
				f_month = 12;
				f_year--;
			} else {
				f_month--;
			}
			return this.days_in_month(f_month, f_year);
		},
		days_next_month: function(m_month, m_year) {
			// set the month and year to the objects month and year
			var f_year = viewable.getFullYear();
			var f_month = viewable.getMonth() + 1;
			// check for a passed in month and/or year.
			if (m_month) f_month = m_month;
			if (m_year) f_year = m_year;
			// Check for December
			if (f_month == 12) { 
				f_month = 1;
				f_year++;
			} else {
				f_month++;
			}
			return this.days_in_month(f_month, f_year);
		},
		buildCalendar: function(m_day, m_month, m_year) {
			// Remove Previous Calendar
			if (calendarDiv) {
				while( calendarDiv.hasChildNodes() ) { calendarDiv.removeChild( calendarDiv.lastChild ); }
			} else {
				calendarDiv = createElement('div');
				calendarDiv.style.display = 'none';
			}
			// set the day, month and year.
			var f_day = viewable.getDate();
			var f_month = viewable.getMonth() + 1;
			var f_year = viewable.getFullYear();
			// check for a passed in day, month and/or year.
			if (m_day) f_day = m_day;
			if (m_month) f_month = m_month;
			if (m_year) f_year = m_year;

			// create a date for current day
			var f_date = new Date(f_year, f_month - 1, 1);
			// get the last day of the month for the previous and current month.
			var f_days_prev_month = this.days_prev_month(f_month, f_year);
			var f_days_curr_month = this.days_in_month(f_month, f_year);
			// set a flag for determining which last day to use in loop, to reset the counter.
			var use_prev_month = true;
			// determines if we are rendering the current month.
			var current_month = false;
			// set the counter
			var counter = f_days_prev_month - f_date.getDay() + 1;
			if (f_date.getDay() == 0) {
				current_month = true;
				use_prev_month = false;
				counter = 1;
			}
			// Set the div to invisible.
			//calendarDiv.style.display = 'none';
			
			// Create Calendar Table
			var calendarTable = createElement('table',calendarDiv);
			calendarTable.className = 'calendar';
			
			// Create table head
			var tableHead = createElement('thead',calendarTable); 
			var tableBody = createElement('tbody',calendarTable);
			// Create the Date Row
			var headerRow = createElement('tr',tableHead); 
			// Left pad.
			var headerColumn = createElement('th',headerRow);
			headerColumn.className = 'title';
			// Date column
			headerColumn = createElement('th',headerRow, months[f_month - 1] + ', ' + f_year);  
			headerColumn.colSpan = 5;
			headerColumn.className = 'title';
			// Close button column
			headerColumn = createElement('th',headerRow, 'X');
			headerColumn.className = 'title';
			addEvent(headerColumn, 'mouseover', DatePicker.onMouseOver);
			addEvent(headerColumn, 'mouseout', DatePicker.onMouseOut);
			addEvent(headerColumn, 'click', function() { DatePicker.hide(); });
			// Navigation Row
			headerRow = createElement('tr', tableHead);
			// Previous Year
			headerColumn = createElement('th', headerRow, '\u00ab');
			addEvent(headerColumn, 'mouseover', DatePicker.onMouseOver);
			addEvent(headerColumn, 'mouseout', DatePicker.onMouseOut);
			addEvent(headerColumn, 'click', function() { DatePicker.prevYear(); });
			// Previous Month
			headerColumn = createElement('th', headerRow, "\u2039");
			addEvent(headerColumn, 'mouseover', DatePicker.onMouseOver);
			addEvent(headerColumn, 'mouseout', DatePicker.onMouseOut);
			addEvent(headerColumn, 'click', function() { DatePicker.prevMonth(); });
			// Today
			headerColumn = createElement('th', headerRow, "Today");
			headerColumn.colSpan = 3;
			addEvent(headerColumn, 'mouseover', DatePicker.onMouseOver);
			addEvent(headerColumn, 'mouseout', DatePicker.onMouseOut);
			addEvent(headerColumn, 'click', function() { DatePicker.setToday(); });
			// Next Month
			headerColumn = createElement('th', headerRow, '\u203a');
			addEvent(headerColumn, 'mouseover', DatePicker.onMouseOver);
			addEvent(headerColumn, 'mouseout', DatePicker.onMouseOut);
			addEvent(headerColumn, 'click', function() { DatePicker.nextMonth(); });
			// Next Year
			headerColumn = createElement('th', headerRow, '\u00bb');
			addEvent(headerColumn, 'mouseover', DatePicker.onMouseOver);
			addEvent(headerColumn, 'mouseout', DatePicker.onMouseOut);
			addEvent(headerColumn, 'click', function() { DatePicker.nextYear(); });
			// Day Label Row
			headerRow = createElement('tr',tableHead);

			// Generate Day Lables
			for (var i = 0; i < 7; i++) {
				var column = createElement('th',headerRow, dayLabel[i]);
				var columnClass = "day-label";
				if (i == 0 || i == 6) columnClass += " weekend-label";
				column.className = columnClass;
			}
			// Cacluate the first year and second loop year.
			// Loop fields are used to add date information to the day cells for the calendar.
			var loop_year = f_year;
			var loop_month = f_month;
			if (use_prev_month == true) {
				if (f_month == 1) { 
					loop_year = f_year - 1;
					loop_month = 12;
				} else {
					loop_month = f_month - 1;
				}
			}
			// Loop through 5 weeks for the calendar
			for (var weekLoop = 0; weekLoop < 6; weekLoop++) {
				// Create day Row.
				var row = createElement('tr',tableBody);
				// Loop through each day in the current week
				for (var dayLoop = 0; dayLoop < 7; dayLoop++) {
					// check to see if we are at the end of the previous month
					if (use_prev_month == true && counter > f_days_prev_month) {
						use_prev_month = false;
						current_month = true;
						loop_month = f_month;
						loop_year = f_year;
						counter = 1;
					// check to see if we are at the end of the current month
					} else if (use_prev_month == false && counter > f_days_curr_month) {
						counter = 1;
						loop_month = f_month + 1;
						if (loop_month == 13) {
							loop_month = 1;
							loop_year++;
						}
						current_month = false;
					}
					// Get the class for the new table element
					var columnClass = "";
					if (current_month == true) {
						columnClass="day";
						if (dayLoop == 0 || dayLoop == 6) columnClass += " weekend";
						if (counter == f_day && loop_month == (activeDate.getMonth() + 1) && loop_year == activeDate.getFullYear()) columnClass += " active";
						if (counter == today.getDate() && loop_month == (today.getMonth() + 1) && loop_year == today.getFullYear()) columnClass += " today";
					} else {
						columnClass="other-day";
						if (dayLoop == 0 || dayLoop == 6) {
							columnClass += " other-weekend";
						} 
					}
					// Create the new day cell
					var column = createElement('td',row, counter);
					column.className = columnClass;
					column.setAttribute('year', loop_year);
					column.setAttribute('month', loop_month);
					column.setAttribute('day', counter);
					addEvent(column, 'mouseover', DatePicker.onMouseOver);
					addEvent(column, 'mouseout', DatePicker.onMouseOut);
					addEvent(column, 'click', DatePicker.onDayClick);
					// Increament the counter
					counter++;
				}
			}
			// add the calendar to the body of the html page
			document.body.appendChild(calendarDiv);
		},
		display: function(displayElement, anchorElement) {
			if (!displayElement) {
				alert('Error: no display element defined.');
				return;
			}
			if (typeof(displayElement) != 'object') {
				var elementName = displayElement;
				// try by id
				displayElement = document.getElementById(elementName);
				if (!displayElement) {
					// try by name
					displayElement = document.getElementsByName(elementName)[0];
				}
			}
			if (!anchorElement) {
				anchorElement = displayElement;
			}
			if (typeof(anchorElement) != 'object') {
				var elementName = anchorElement;
				anchorElement = document.getElementById(elementName);
				if (!anchorElement) {
					// try by name
					anchorElement = document.getElementsByName(elementName)[0];
				}
			}
			writebackElement = displayElement;
			if (calendarDiv && calendarDiv.style.display != 'none') {
				calendarDiv.style.display = 'none';
				return;
			}
			var f_date = today;
			if (displayElement.value.length != 0) {
				try {
					f_date = new Date(displayElement.value);
				} catch (e) {
					f_date = today;
				}
			}
			if (!f_date) {
				f_date = today;
			}
			viewable = f_date;
			activeDate = f_date;
			this.buildCalendar();
			
			var x = anchorElement.offsetLeft;
 			var y = anchorElement.offsetTop + anchorElement.offsetHeight ;
 
			// deal with elements inside tables and such
			var parent = anchorElement;
			while (parent.offsetParent) {
				parent = parent.offsetParent;
				x += parent.offsetLeft;
				y += parent.offsetTop ;
			}
			calendarDiv.style.position = "absolute";
  			calendarDiv.style.left = x + "px";
  			calendarDiv.style.top = y + "px";
			calendarDiv.style.display = (calendarDiv.style.display == 'none' ? '' : 'none');
			calendarDiv.style.zIndex = 10000;
		},
		prevMonth: function() {
			var year = viewable.getFullYear();
			var month = viewable.getMonth();
			var viewableDate = viewable.getDate();
			if (month == 0) {
				month = 11;
				year--;
			} else {
				month--;
			}
			viewable = new Date(year, month, viewableDate);
			this.buildCalendar();
			calendarDiv.style.display == '';
		},
		nextMonth: function() {
			var year = viewable.getFullYear();
			var month = viewable.getMonth();
			var viewableDate = viewable.getDate();
			if (month == 11) {
				month = 0;
				year++;
			} else {
				month++;
			}
			viewable = new Date(year, month, viewableDate);
			this.buildCalendar();
			calendarDiv.style.display == '';
		},
		prevYear: function() {
			var year = viewable.getFullYear();
			var month = viewable.getMonth();
			var viewableDate = viewable.getDate();
			year--;
			viewable = new Date(year, month, viewableDate);
			this.buildCalendar();
			calendarDiv.style.display == '';
		},
		nextYear: function() {
			var year = viewable.getFullYear();
			var month = viewable.getMonth();
			var viewableDate = viewable.getDate();
			year++;
			viewable = new Date(year, month, viewableDate);
			this.buildCalendar();
			calendarDiv.style.display == '';
		},
		setToday: function() {
			viewable = today;
			activeDate = today;
			this.buildCalendar();
			this.getWritebackElement().value = today.getMonth() + 1 + '/' + today.getDate() + '/' + today.getFullYear();
			calendarDiv.style.display == '';
		}
	};
}();

