var Calendar = 
{
	_private_functions:
	{
		_dateCallBack: function(event)
		{
			var target;
			if (event == undefined)
				event = window.event;

			if (event.target)
				target = event.target;
			else
				target = event.srcElement;

			if (target != undefined)
			{
				var number = parseInt(target.innerHTML);
				if (number > 0 && number < 32)
					return this.selectDateDay(number, true);
			}

			return null;
		},

		_findPos: function(elem)
		{
			var curleft = 0;
			var curtop = 0;

			if (elem.offsetParent)
			{
				do
				{
					curleft += elem.offsetLeft;
					curtop += elem.offsetTop;
				} while ( (elem = elem.offsetParent) != null);
				return [ curleft, curtop ];
			}
			return null;
		},

		_getCalendarField: function(name)
		{
			return document.getElementById(this._generateID(name));
		},

		_setSelectCallback: function (callback)
		{
			this._selectCallback = callback;
		},

		_setClass: function (elem, iClass)
		{
			elem.setAttribute("class", iClass);
			elem.setAttribute("className", iClass);
		},

		_addEventListener: function(elem, event, func, capture)
		{
			if (elem.addEventListener)
			{
				elem.addEventListener(event, func, capture);
			}
			else if (elem.attachEvent)
			{
				elem.attachEvent("on" + event, func);
			}
		},

		_generateID: function(name)
		{
			return this._random_prefix + "_" + name;
		},

		_nextMonth: function()
		{
			if (this._displayMonth == 12)
			{
				this._displayMonth = 1;
				this._displayYear += 1;
			}
			else
			{
				this._displayMonth += 1;
			}
			this._refreshCalendar();
		},

		_prevMonth: function()
		{
			if (this._displayMonth == 1)
			{
				this._displayMonth = 12;
				this._displayYear -= 1;
			}
			else
			{
				this._displayMonth -= 1;
			}
			this._refreshCalendar();
		},

		_nextYear: function()
		{
			this._displayYear += 1;
			this._refreshCalendar();
		},

		_prevYear: function()
		{
			this._displayYear -= 1;
			this._refreshCalendar();
		},

		_setCalendarMonthYear: function(year, month)
		{
			if (month >= 1 && month <= 12)
			{
				this._displayMonth = parseInt(month);
				this._displayYear = parseInt(year);
				this._refreshCalendar();
			}
		},

		_selectDateDay: function(day, interactive)
		{
			var new_date = Dates.parseDate(this._displayYear, this._displayMonth, day);
			this.selectDate(new_date, interactive);
		},

		_selectDate: function(new_date, interactive)
		{

			var cont = true;

			if (this._selectCallback != null && typeof(this._selectCallback) == "function")
				cont = this._selectCallback(new_date, interactive);


			if (cont)
			{
				this._selectedDate = new_date;

				this._displayYear = this._selectedDate.getFullYear();
				this._displayMonth = this._selectedDate.getMonth() + 1;
				this._refreshCalendar();
			
				var HIDDEN = this.getCalendarField("selectedDate");
				HIDDEN.value = Dates.DateFormat(this._selectedDate, "%Y-%m-%d");

				if (this._popup)
				{
					var div = this.getCalendarField("BASE_DIV");
					div.style.display = "none";
	
					var DATE_BOX = this.getCalendarField("DATE_BOX");
					DATE_BOX.value = Dates.DateFormat(this._selectedDate, ( this._date_format != undefined ? this._date_format : "%b %d, %Y" ) );
				}
			}

			return;
		},
			
		_openCalendarPopup : function()
		{
			var div = this.getCalendarField("BASE_DIV");

			if (div.style.display == "none")
			{
				var DATE_BOX = this.getCalendarField("DATE_BOX");
				var BASE = this.getCalendarField("BASE");

				var height = BASE.offsetHeight;

				height = parseInt(height);
				if (height <= 0)
					height = 22;

				height += 3;

				var pos = Calendar._private_functions._findPos(DATE_BOX);

				var browser_width;
				var left_pos;

				browser_width = document.body.offsetWidth;

				if ( (pos[0] + div.offsetWidth) > browser_width)
				{
					left_pos = browser_width - div.offsetWidth - 5;
				}
				else
				{
					left_pos = pos[0];
				}

				div.style.position = "absolute";
				div.style.top = (pos[1] + height) + "px";
				div.style.left = left_pos + "px";

				if (typeof(this._openCallbacks) == 'object')
				{
					var x;
					for (x = 0; x < this._openCallbacks.length; x++)
					{
						if (!this._openCallbacks[x].call(this))
							return false;
					}
				}

				div.style.display = "block";
				

			}
			else
				div.style.display = "none";

			return true;
		},

		_addOpenPopupListener: function(callback)
		{
			if (this._openCallbacks == undefined)
				this._openCallbacks = [];

			if (typeof(callback) == 'function')
				this._openCallbacks.push(callback);
		},

		_removeOpenPopupListener: function(callback)
		{
			var x;
			if (typeof(callback) != 'function')
				return;

			if (this._openCallbacks == undefined)
				return;

			for (x = 0; x < this._openCallbacks.length; x++)
			{
				if (this._openCallbacks[x] == callback)
					this._openCallbacks[x].splice(x, 1);
			}

			return;
		},

		_closeCalendarPopup: function()
		{
			var div = this.getCalendarField("BASE_DIV");

			div.style.display = "none";
		},
		
		_initializeCalendar: function()
		{
			var BASE = this.getCalendarField("BASE");

			if (BASE == undefined)
				return;

			if (BASE.tagName != "DIV" && BASE.tagName != "SPAN")
				return;

			var HIDDEN = document.createElement("INPUT");
			HIDDEN.setAttribute("id", this._generateID("selectedDate") );
			HIDDEN.setAttribute("name", this._hidden_name );
			HIDDEN.setAttribute("type", "hidden");
			HIDDEN.value = Dates.DateFormat(this._selectedDate, "%Y-%m-%d");
			BASE.appendChild(HIDDEN);

			var div = document.createElement("DIV");
			this._setClass(div, "basic-calendar-div");
			div.setAttribute("id", this._generateID("BASE_DIV"));

			var table = document.createElement("TABLE");
			this._setClass(table, "calendar-table");
			table.setAttribute("id", this._generateID("CALENDAR") );
			table.setAttribute("cellspacing", "0");
			table.setAttribute("cellpadding", "0");


			var tbody = document.createElement("TBODY");
			
			this._addHeading(tbody);
			table.appendChild(tbody);

			var MonthArray = this._generateMonthArray();

			var ROW = document.createElement("TR");
			var DATA = document.createElement("TD");
			DATA.setAttribute("colspan", "5");
			DATA.colSpan = "5";
			DATA.setAttribute("align", "center");
			DATA.appendChild(MonthArray);
			ROW.appendChild(DATA);
			tbody.appendChild(ROW);

			div.appendChild(table);

			if (this._popup)
			{
				div.style.display = "none";

				var date_table = document.createElement("TABLE");
				var date_tbody = document.createElement("TBODY");
				var date_tr = document.createElement("TR");

				var date_td_date_box = document.createElement("TD");
				var date_td_icon = document.createElement("TD");
			
				var date_img = document.createElement("IMG");
				date_img.setAttribute("style", "width: 16px; height: 16px");
				date_img.src="/js/jslib/images/calendar_icon.png";

				var b = this;
				var DATE_BOX = document.createElement("INPUT");
				DATE_BOX.type = "text";
				DATE_BOX.setAttribute("id", this._generateID("DATE_BOX") );
				DATE_BOX.readOnly = true;
				this._setClass(DATE_BOX, "date_box");

				DATE_BOX.value = Dates.DateFormat(this._selectedDate, ( this._date_format != undefined ? this._date_format : "%b %d, %Y" ) );

				var click = function () { b.openCalendarPopup.call(b) };
				this._addEventListener(DATE_BOX, "click", click, false);
				this._addEventListener(date_img, "click", click, false);

				date_td_icon.appendChild(date_img);
				date_td_date_box.appendChild(DATE_BOX);

				date_tr.appendChild(date_td_date_box);
				date_tr.appendChild(date_td_icon);
				date_tbody.appendChild(date_tr);
				date_table.appendChild(date_tbody);

				BASE.appendChild(date_table);
			}

			BASE.appendChild(div);
			this._setClass(BASE, "basic-calendar");
		},

		_setCustomSelector: function(callback)
		{
			if (typeof(callback) == 'function')
			{
				this._customSelector = callback;
			}
			else
			{
				this._customSelector == undefined;
			}
		},

		_generateMonthArray: function()
		{
			var table = document.createElement("TABLE");
			var tbody = document.createElement("TBODY");
			table.appendChild(tbody);

			this._setClass(table, "MONTH_ARRAY");
			table.setAttribute("cellspacing", "0");
			table.setAttribute("cellpadding", "0");

			table.setAttribute("id", this._generateID("MONTH_ARRAY") );

			var HEADINGS = [ "S", "M", "T", "W", "T", "F", "S" ];

			var HEADING = document.createElement("TR");
			
			for (var i in HEADINGS)
			{
				var DATA = document.createElement("TH");
				DATA.innerHTML = HEADINGS[i];
				var day = "cell-" + Dates.LongDayNames[i];
				this._setClass(DATA, day + " DAY_HEADING");
				HEADING.appendChild(DATA);
			}

			tbody.appendChild(HEADING);

			var CURRENT_ROW = document.createElement("TR");

			var currentDate = Dates.parseDate(this._displayYear, this._displayMonth, 1);
			for (var i = 0; i < currentDate.getDay(); i++)
			{
				var DATA = document.createElement("TD");
				DATA.innerHTML = "&nbsp;";

				var day = "cell-" + Dates.LongDayNames[i];
				this._setClass(DATA, day + " cell-empty");
				CURRENT_ROW.appendChild(DATA);
			}

			while (currentDate.getMonth() == this._displayMonth - 1)
			{
				if (currentDate.getDay() == 0)
				{
					tbody.appendChild(CURRENT_ROW);
					CURRENT_ROW = document.createElement("TR");
				}

				var DATA = document.createElement("TD");
				var day = "cell-" + Dates.LongDayNames[currentDate.getDay()];
				DATA.innerHTML = currentDate.getDate();

				if (this._customSelector != undefined && typeof(this._customSelector) == 'function')
				{
					if (this._customSelector(currentDate))
					{
						this._setClass(DATA, day + " cell-selected");
					}
					else
					{
						this._setClass(DATA, day + " cell-not-selected");
					}
				}
				else
				{
					if (currentDate.getFullYear() == this._selectedDate.getFullYear() &&
						currentDate.getMonth() == this._selectedDate.getMonth() &&
						currentDate.getDate() == this._selectedDate.getDate())
					{
						this._setClass(DATA, day + " cell-selected");
					}	
					else
					{
						this._setClass(DATA, day + " cell-not-selected");
					}
				}

				var b = this;
				var c = currentDate.getDate();
				var f = function (event) { b._dateCallBack.call(b, event); };

//				var str = " f = function () { b.selectDateDay.call(b, " + c + ", true); } ";
//				try
//				{
//					eval(str);
					this._addEventListener(DATA, "click", f, false);
//				} catch (ex) {}


				CURRENT_ROW.appendChild(DATA);
				currentDate = Dates.AddDays_Date(currentDate, 1);
			}

			currentDate = Dates.AddDays_Date(currentDate, -1);

			for (var i = currentDate.getDay(); i < 6; i++)
			{
				var DATA = document.createElement("TD");
				DATA.innerHTML = "&nbsp;";
				this._setClass(DATA, "cell-empty");
				CURRENT_ROW.appendChild(DATA);
			}

			tbody.appendChild(CURRENT_ROW);

			return table;
		},		

		_refreshCalendar: function()
		{
			var MonthHeading = this.getCalendarField("MONTH_HEADING");

			var formatted_date = Dates.DateFormat(Dates.parseDate(this._displayYear, this._displayMonth, 1), "%B %Y");

			if (MonthHeading.innerText != undefined)
				MonthHeading.innerText = formatted_date;
			else
				MonthHeading.innerHTML = formatted_date;

			var MonthArray = this.getCalendarField("MONTH_ARRAY");

			var parent = MonthArray.parentNode;
			parent.removeChild(MonthArray);

			var newMonthArray = this._generateMonthArray();
			parent.appendChild(newMonthArray);

		},

		_addHeading: function(table)
		{
			var MonthHeading = document.createElement("DIV");
			MonthHeading.setAttribute("id", this._generateID("MONTH_HEADING"));
			MonthHeading.innerHTML = Dates.DateFormat(Dates.parseDate(this._displayYear, this._displayMonth, 1), "%B %Y");
			
			var b = this;

			var pY_click = function(event) { b._prevYear.call(b); };
			var nY_click = function(event) { b._nextYear.call(b); };
			var pM_click = function(event) { b._prevMonth.call(b); };
			var nM_click = function(event) { b._nextMonth.call(b); };
			
			var prevYear;
			if (this._disableMovements)
			{
				prevYear = document.createElement("SPAN");
				prevYear.innerHTML = "&nbsp;";
			}
			else
			{
				prevYear = document.createElement("A");
				prevYear.setAttribute("title", "Previous Year");
				prevYear.setAttribute("alt", "Previous Year");
				prevYear.innerHTML = "&lt;&lt;";
				this._addEventListener(prevYear, "click", pY_click, false);
			}

			var prevMonth;

			if (this._disableMovements)
			{
				prevMonth = document.createElement("SPAN");
				prevMonth.innerHTML = "&nbsp;";
			}
			else
			{
				prevMonth = document.createElement("A");
				prevMonth.innerHTML = "&lt;";
				prevMonth.setAttribute("title", "Previous Month");
				prevMonth.setAttribute("alt", "Previous Month");

				this._addEventListener(prevMonth, "click", pM_click, false);
			}

			var nextMonth;
			if (this._disableMovements)
			{
				nextMonth = document.createElement("SPAN");
				nextMonth.innerHTML = "&nbsp;";
			}
			else
			{
				nextMonth = document.createElement("A");
				nextMonth.setAttribute("title", "Next Month");
				nextMonth.setAttribute("alt", "Next Month");
				nextMonth.innerHTML = "&gt;";
				this._addEventListener(nextMonth, "click", nM_click, false);
			}

			var nextYear;

			if (this._disbleMovements)
			{
				nextYear = document.createElement("SPAN");
				nextYear.innerHTML = "&nbsp;";
			}
			else
			{
				nextYear  = document.createElement("A");
				nextYear.innerHTML = "&gt;&gt;";
				nextYear.setAttribute("title", "Next Year");
				nextYear.setAttribute("alt", "Next Year");
				this._addEventListener(nextYear, "click", nY_click, false);
			}

			var HEADING_ROW = document.createElement("TR");
			this._setClass(HEADING_ROW, "HEADING_ROW");

			for (var i = 0; i < 5; i++)
			{
				var elem;
				var iClass;
				switch (i)
				{
					case 0:
						elem = prevYear;
						iClass = "PREV_YEAR";
						break;
					case 1:
						elem = prevMonth;
						iClass = "PREV_MONTH";
						break;
					case 2:
						elem = MonthHeading;
						iClass = "MONTH_HEADING";
						break;
					case 3:
						elem = nextMonth;
						iClass = "NEXT_MONTH";
						break;
					case 4:
						elem = nextYear;
						iClass = "NEXT_YEAR";
						break;
				}

				var HEADING_DATA = document.createElement("TD");
				this._setClass(HEADING_DATA, iClass);
				HEADING_DATA.appendChild(elem);
				HEADING_ROW.appendChild(HEADING_DATA);
			}

			table.appendChild(HEADING_ROW);
		},

		_setCurrentDate: function(date)
		{
			return this.selectDate(date, 0);
		},

		_getCurrentDate: function()
		{
			return this._selectedDate;
		}	
	},
		
	inst: function (hidden_name, random_prefix, popup, options)
	{
		var today = new Date();
		this._popup = (popup ? true : false);
		this._hidden_name = hidden_name;
		this._random_prefix = random_prefix;
		this._selectedDate = Dates.parseDate( today.getFullYear(), today.getMonth()+1, today.getDate() );
		
		this._displayYear = this._selectedDate.getFullYear();
		this._displayMonth = this._selectedDate.getMonth() + 1;

		this._generateID = Calendar._private_functions._generateID;

		this._nextMonth = Calendar._private_functions._nextMonth;
		this._prevMonth = Calendar._private_functions._prevMonth;

		this._nextYear = Calendar._private_functions._nextYear;
		this._prevYear = Calendar._private_functions._prevYear;

		this._refreshCalendar = Calendar._private_functions._refreshCalendar;
		this.getCalendarField = Calendar._private_functions._getCalendarField;

		this._addHeading = Calendar._private_functions._addHeading;
		this._initializeCalendar = Calendar._private_functions._initializeCalendar;

		this._addEventListener = Calendar._private_functions._addEventListener;
		this._generateMonthArray = Calendar._private_functions._generateMonthArray;
		this._setClass = Calendar._private_functions._setClass;

		this._dateCallBack = Calendar._private_functions._dateCallBack;

		this.selectDate = Calendar._private_functions._selectDate;
		this.selectDateDay = Calendar._private_functions._selectDateDay;

		this.openCalendarPopup = Calendar._private_functions._openCalendarPopup;
		this.closeCalendarPopup = Calendar._private_functions._closeCalendarPopup;

		this.setSelectCallback = Calendar._private_functions._setSelectCallback;
		this.setCustomSelector = Calendar._private_functions._setCustomSelector;

		this.setCurrentDate = Calendar._private_functions._setCurrentDate;
		this.getCurrentDate = Calendar._private_functions._getCurrentDate;

		this.setCalendarMonthYear = Calendar._private_functions._setCalendarMonthYear;

		this.addOpenPopupListener = Calendar._private_functions._addOpenPopupListener;
		this.removeOpenPopupListener = Calendar._private_functions._removeOpenPopupListener;

		if (options != undefined && options != null)
		{
			if (options.NoMovements == true)
			{
				this._disableMovements = true;
			}
		}

		this._initializeCalendar();
		return this;
	}
};
