/////////////////////////////////
// Built in Date Class upgrade //
// * this code comes first     //
/////////////////////////////////

Date.isLeapYear=function(year) {
	return (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) ? true:false;
}

Date.prototype.isLeapYear=function() {
	var year=this.getFullYear();
	return (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) ? true:false;
}

Date.prototype.getNumOfDaysInMonth=function() {
	var numOfDaysInMonthArray=new Array(31,28,31,30,31,30,31,31,30,31,30,31);
	var currentMonth=this.getMonth();	
	if (currentMonth!=1 || (currentMonth==1 && !this.isLeapYear())) {
		return numOfDaysInMonthArray[currentMonth];
	} else {
		return 29;
	}
}



DHTMLApi = {
	
	CSS : {
		getStyle: function (element, name) {
			var styleObj;
			if (element.style[name]) return element.style[name];
			if (element.currentStyle) {	
				name=name.replace(/-([a-z])/g, function (matched) {
					return matched.toUpperCase().slice(1, matched.length);
				});
				return element.currentStyle[name];
			}
			if (document.defaultView && document.defaultView.getComputedStyle) {
				name=name.replace(/([A-Z])/g,"-$1");
				name=name.toLowerCase();
				styleObj=document.defaultView.getComputedStyle(element,"");
				return styleObj && styleObj.getPropertyValue(name);
			} else {
				return null;
			}
		},
		
		setProperties: function (element, properties) {
			var oldProperties={};
			for (var i in properties) {
				oldProperties[i]=element.style[i];
				element.style[i]=properties[i];
			}
			return oldProperties;
		},
		
		setClass:function (element,addClassesArray,removeClassesArray) {
			var currentClasses=new Array();
			var newClasses=new Array();
			var removedClasses=new Array();
			findWordsExp=new RegExp("\\w+", "g");
			var result;
			while ((result= findWordsExp.exec(element.className))!= null) currentClasses.push(result[0]); 
			for (var i=0; i<addClassesArray.length; i++) {
				var classExists=false;
				for (var j=0; j<currentClasses.length; j++) {
					if (currentClasses[j]==addClassesArray[i]) {
						classExists=true;
						break;
					}					
				}
				if (!classExists) newClasses.push(addClassesArray[i]);
			}
			currentClasses=currentClasses.concat(newClasses);
			if (removeClassesArray==null) return removedClasses;
			for (var i=0; i<removeClassesArray.length; i++) {
				for (var j=0; j<currentClasses.length; j++) {
					if (currentClasses[j]==removeClassesArray[i]) {
						removedClasses=removedClasses.concat(currentClasses.splice(j,1));
						break;
					}					
				}
			}
			element.className=currentClasses.join(" ");
			return removedClasses;
		}
	},
	
	Position : {
		getXPosOnPage: function (element) {
			return element.offsetParent?element.offsetLeft+DHTMLApi.Position.getXPosOnPage(element.offsetParent):element.offsetLeft;
		},
		
		getYPosOnPage: function (element) {
			return element.offsetParent?element.offsetTop+DHTMLApi.Position.getYPosOnPage(element.offsetParent):element.offsetTop;
		},
		
		getXPosInElement: function (element,container) {
			return DHTMLApi.Position.getXPosOnPage(element)-DHTMLApi.Position.getXPosOnPage(container);
		},
		
		getYPosInElement: function (element,container) {
			return DHTMLApi.Position.getYPosOnPage(element)-DHTMLApi.Position.getYPosOnPage(container);
		},
		
		setXPosOnPage: function (element,posX) {
			var propertiesArray={};
			if (element.parentNode!=document.body) {
				element=element.parentNode.removeChild(element);
				document.body.appendChild(element);
			}
			if (DHTMLApi.CSS.getStyle(element,"position")!="absolute") {
				propertiesArray={position: "absolute"};
			}
			propertiesArray.left=posX+"px";
			DHTMLApi.CSS.setProperties(element,propertiesArray);
		},
		
		setYPosOnPage: function (element,posY) {
			var propertiesArray={};
			if (element.parentNode!=document.body) {
				element=element.parentNode.removeChild(element);
				document.body.appendChild(element);
			}
			if (DHTMLApi.CSS.getStyle(element,"position")!="absolute") {
				propertiesArray={position: "absolute"};
			}
			propertiesArray.top=posY+"px";
			DHTMLApi.CSS.setProperties(element,propertiesArray);
		},
		
		setXPos: function (element, posX, relativeToElement) {
			if (relativeToElement==undefined) {
				element.style.left=posX+"px";
			} else {
				if(DHTMLApi.CSS.getStyle(element.parentNode,"position")=="static"){
					element.parentNode.style.position="relative";
				}
				element.style.position="absolute";
				element.style.left=(posX-DHTMLApi.Position.getXPosInElement(element.parentNode,relativeToElement))+"px";
			}
		},
		
		setYPos: function (element, posY, relativeToElement) {
			if (relativeToElement==undefined) {
				element.style.top=posY+"px";
			} else {
				if(DHTMLApi.CSS.getStyle(element.parentNode,"position")=="static"){
					element.parentNode.style.position="relative";
				}
				element.style.position="absolute";
				element.style.top=(posY-DHTMLApi.Position.getYPosInElement(element.parentNode,relativeToElement))+"px";
			}
		}
		
	},
	
	Size : { 
		
		getElementWidth : function (element) {
			var tempProperties, width;
			if (DHTMLApi.CSS.getStyle(element, "display" ) != "none") {
				return element.offsetWidth || parseInt(DHTMLApi.CSS.getStyle(element, "width"));
			}
			tempProperties=DHTMLApi.CSS.setProperties(element, {display: "block", visibility: "hidden", position: "absolute"});
			width=element.clientWidth || parseInt(DHTMLApi.CSS.getStyle(element, "width"));
			DHTMLApi.CSS.setProperties(element, {display: "", visibility: "", position: ""});
			DHTMLApi.CSS.setProperties(element,tempProperties);
			return width;		
		},
		
		getElementHeight : function (element) {
			var tempProperties, height;
			if (DHTMLApi.CSS.getStyle(element, "display" ) != "none") {
				return element.offsetHeight || parseInt(DHTMLApi.CSS.getStyle(element, "height"));
			}
			tempProperties=DHTMLApi.CSS.setProperties(element, {display: "block", visibility: "hidden", position: "absolute"});
			height=element.clientHeight || parseInt(DHTMLApi.CSS.getStyle(element, "height"));
			DHTMLApi.CSS.setProperties(element, {display: "", visibility: "", position: ""});
			DHTMLApi.CSS.setProperties(element,tempProperties);
			return height;
		},
		
		getPageWidth: function () {
			//return Math.max(document.body.scrollWidth,document.body.offsetWidth);
			return (document.documentElement && document.documentElement.scrollWidth) ? document.documentElement.scrollWidth : (document.body.scrollWidth > document.body.offsetWidth) ? document.body.scrollWidth : document.body.offsetWidth;
		},
		
		getPageHeight: function () {
			//var height=(typeof document.documentElement != "undefined" && typeof document.documentElement.offsetHeight != "undefined") ? document.documentElement.offsetHeight : 0;
			//return Math.max(document.body.scrollHeight,document.body.offsetHeight,height);
			return (document.documentElement && document.documentElement.scrollHeight) ? document.documentElement.scrollHeight : (document.body.scrollHeight > document.body.offsetHeight) ? document.body.scrollHeight : document.body.offsetHeight;
		}
	
	},
	
	Visibility: {
		
		show: function (element) {
			element.style.display=element.__display__ || 'block';
		},
		
		hide: function (element) {
			var currentDisplay=DHTMLApi.CSS.getStyle(element,"display");
			if (currentDisplay != 'none') element.__display__=currentDisplay;
			element.style.display='none';
		},
		
		setOpacity: function (element,percent) {
			if (element.filters) {	
				element.style.filter='alpha(opacity='+percent+')';
			} else {
				element.style.opacity=percent/100;
			}
		}
		
	},
	
	Browser : {
		
		getViewportWidth: function () {
			return self.innerWidth || (document.documentElement && document.documentElement.clientWidth) || document.body.clientWidth;
		},
		
		getViewportHeight: function () {
			return self.innerHeight || (document.documentElement && document.documentElement.clientHeight) || document.body.clientHeight;
		},
		
		getScrollX: function () {
			return self.pageXOffset || (document.documentElement && document.documentElement.scrollLeft) || document.body.scrollLeft;
		},
		
		getScrollY: function () {
			return self.pageYOffset || (document.documentElement && document.documentElement.scrollTop) || document.body.scrollTop;
		}
		
	}
};

MousePositionOnPage = {
	getX: function (mouseEvent) {
		return mouseEvent.pageX || mouseEvent.clientX+DHTMLApi.Browser.getScrollX();
	},
	getY: function (mouseEvent) {
		return mouseEvent.pageY || mouseEvent.clientY+DHTMLApi.Browser.getScrollY();
	}
};


function DOMEventHandle(element, type, handler) {
	this.element=element;
	this.type=type;
	this.handler=handler;
}

DOMEvent = {	

	// public
	
	addDomListener: function (element, type, handler) {
		var handlers, newHandler;
		newHandler=this.modifyHandlerExceptions(element, type, handler);
		if (newHandler!==false) handler=newHandler;
		if (!handler.__id__) handler.__id__ = DOMEvent.currentId++;
		if (!element.events) element.events = {};
		handlers = element.events[type];
		if (!handlers) {
    		handlers = element.events[type] = {};
		    if (element["on" + type]) {
      			handlers[0] = element["on" + type];
    		}
  		}
		handlers[handler.__id__] = handler;
		element["on" + type] = DOMEvent.handleEvent;
		return new DOMEventHandle(element, type, handler);
	},
	
	modifyHandlerExceptions : function (element, type, handler) {
		var newHandler;
		if ((type == "mouseout" || type == "mouseover") && element.nodeName == 'DIV') {
			newHandler=function (eventObject) {
				var relatedTarget= (eventObject.relatedTarget) ? eventObject.relatedTarget : eventObject.toElement;
				while (relatedTarget !==null && relatedTarget !== element && relatedTarget.nodeName != 'BODY') {
					relatedTarget= relatedTarget.parentNode;
				}
				if (relatedTarget !== element) {
					handler(eventObject);
				}
			}
			return newHandler;
		}
		
		//if (window.addEventListener)
        /** DOMMouseScroll is for mozilla. */
        //window.addEventListener('DOMMouseScroll', wheel, false);
/** IE/Opera. */
//window.onmousewheel = document.onmousewheel = wheel;
		return false;
	},
	
	removeListener: function (domEventHandleObj) {
		var element,type,handler;
		element=domEventHandleObj.element;
		type=domEventHandleObj.type;
		handler=domEventHandleObj.handler;
		if (element.events && element.events[type]) {
   			delete element.events[type][handler.__id__];
  		}
	},
	
	preventDefault: function (eventObj) {
		if (eventObj.preventDefault) {
			eventObj.preventDefault();
		} else {
			eventObj.returnValue=false;
		}
	},
	
	stopPropagation: function (eventObj) {
		if (eventObj.stopPropagation) {
			eventObj.stopPropagation();
		} else {
			eventObj.cancelBubble=true;
		}
	},
	
	// private
	
	currentId: 1,
	
	handleEvent: function (event) {
  		var handlers;
		event = event || window.event;
  		handlers = this.events[event.type];
  		for (var i in handlers) {
    		this.__handleEvent = handlers[i];
    		this.__handleEvent(event);
  		}
		this.__handleEvent=null;
	}
};


JSON={
	serialize: function (JSONObject) {
		var elementArray=new Array();
		var resultString;			
		var objectTypeIsArray=false;
		if (JSONObject.constructor==Array) {
			objectTypeIsArray=true;
			for (var i=0; i<JSONObject.length; i++) {
				if (typeof JSONObject[i] == "object") {
					elementArray.push(JSON.serialize(JSONObject[i]));
				} else if (typeof JSONObject[i] == "string") {
					elementArray.push('"'+encodeURIComponent(JSONObject[i])+'"');
				} else {
					elementArray.push(JSONObject[i]);
				}
			}
		} else if (JSONObject.constructor==Object) {
			for (var property in JSONObject) {
				if (typeof JSONObject[property] == "object") {
					elementArray.push(property+':'+JSON.serialize(JSONObject[property]));
				} else if (typeof JSONObject[property] == "string") {
					elementArray.push(property+':'+'"'+encodeURIComponent(JSONObject[property])+'"');
				} else {
					elementArray.push(property+':'+JSONObject[property]);
				}
			}
		} else 	{
			return encodeURIComponent(JSONObject);
		}
		resultString=elementArray.join(",");
		if (objectTypeIsArray) {
			return "["+resultString+"]";
		} else {
			return "{"+resultString+"}";
		}
	},
	
	unserialize: function (JSONString) {
		var JSONObject;
		try {
			eval("JSONObject="+JSONString);
		} catch (e) {
			JSONObject=new Object();
		};
		return JSON.urlDecodeJSONObject(JSONObject);
	},
	
	urlDecodeJSONObject: function (JSONObject) {
		var decodedObject;
		if (JSONObject===null) {
			decodedObject=null;
		} else 	if (JSONObject.constructor==Array) {
			decodedObject=new Array();
			for (var i=0; i<JSONObject.length; i++) {
				if (typeof JSONObject[i] == "object") {
					decodedObject.push(JSON.urlDecodeJSONObject(JSONObject[i]));
				} else if (typeof JSONObject[i] == "string") {
					decodedObject.push(decodeURIComponent(JSONObject[i]));
				} else {
					decodedObject.push(JSONObject[i]);
				}
			}
		} else if (JSONObject.constructor==Object) {
			decodedObject=new Object();
			for (var property in JSONObject) {
				if (typeof JSONObject[property] == "object") {
					decodedObject[property]=JSON.urlDecodeJSONObject(JSONObject[property]);
				} else if (typeof JSONObject[property] == "string") {
					decodedObject[property]=decodeURIComponent(JSONObject[property]);
				} else {
					decodedObject[property]=JSONObject[property];
				}
			}
		} else 	{
			decodedObject=decodeURIComponent(JSONObject);
		}
		return decodedObject;
	}
};


Ajax={ 
	getXMLHttpRequest : function () {
	
		if ((typeof XMLHttpRequest) == "undefined") {
			XMLHttpRequest=function() {
				return new ActiveXObject(navigator.userAgent.indexOf("MSIE 5") >= 0 ? "Microsoft.XMLHTTP" : "Msxml2.XMLHTTP");
			}
		} 	
		return (new XMLHttpRequest());
	},
	
	isSuccess : function (xmlHttpRequestObj) {
		try {
			return (!xmlHttpRequestObj.status && location.protocol=="file:") || (xmlHttpRequestObj.status >=200 && xmlHttpRequestObj.status < 300) || xmlHttpRequestObj.status==304 || (navigator.userAgent.indexOf("Safari") >= 0 && typeof xmlHttpRequestObj.status == "undefined");
		} catch(e){};
		return false;		
	},
	
	/* dataType is string, values: xml, html, json */
	
	getResponseData : function (xmlHttpRequestObj,dataType) {
		var ct=xmlHttpRequestObj.getResponseHeader("content-type");
		var xmlData= !dataType && ct && ct.indexOf("xml")>=0;
		var data= (dataType == "xml" || xmlData)? xmlHttpRequestObj.responseXML: xmlHttpRequestObj.responseText;
		if (dataType=="json") {
			data=JSON.unserialize(data);
		}
		return data;
	}
}

//////////////////////////
// Interface Observable //
//////////////////////////

Observable = {
	addListener : function(listenerObj) {
		if (typeof this.listeners == 'undefined') {
			this.listeners=[];
		}
		for (var i=0; i<this.listeners.length; i++) {
			if (this.listeners[i]==listenerObj) return;
		}
		this.listeners[this.listeners.length]=listenerObj;
	},

	removeListener : function(listenerObj) {
		for (var i=0; i<this.listeners.length; i++) {
			if (this.listeners[i]==listenerObj) {
				this.listeners.splice(i,1);
				return;
			}
		}
	},
	
	notifyListeners : function (eventName,eventObj) {
		if (typeof this.listeners == 'undefined') return;
		for (var i=0; i< this.listeners.length; i++) {
			if (typeof this.listeners[i][eventName]!="undefined") {
				this.listeners[i][eventName](eventObj);
			}
		}
	}
};

function implementsInterface(obj) {
	var prototypeObj={};
	for (var i=0; i<arguments.length; i++) {
		for (var method in arguments[i]) {
			prototypeObj[method]=arguments[i][method];
		}	
	}
	return prototypeObj;
}

function addObjectMethods(targetClass, methodObject) {
	for (var method in methodObject) {
		targetClass.prototype[method]=methodObject[method];
	}
}


Utopia={};

Utopia.Calendar={};

//////////////////////////////////
// class Utopia.Calendar.Viewer //
//////////////////////////////////

/*
	CSSClasses={calendarTable: string, selectedDay: string}
*/

Utopia.Calendar.Viewer=function (weekDaysLabels, startWithDayOfTheWeek,CSSClasses) {
	this.calendarDate=null;
	this.weekDaysLabels=weekDaysLabels;
	this.CSSClasses=CSSClasses;
	this.selectedDays=new Array();
	this.calendarCellObj=new Array();
	this.columnDayOrder=this.getDayOrderArray(startWithDayOfTheWeek);
}

Utopia.Calendar.Viewer.prototype.getDayOrderArray= function (startWithDayOfTheWeek) {
	var dayArray=new Array();
	for (var i=startWithDayOfTheWeek; i<7; i++) {
		dayArray[i-startWithDayOfTheWeek]=i;
	}
	for (var i=0; i<startWithDayOfTheWeek; i++) {
		dayArray[i+7-startWithDayOfTheWeek]=i;
	}
	return dayArray;		
}

Utopia.Calendar.Viewer.prototype.isDateValid=function(dayNum) {
	if (dayNum<=this.calendarDate.getNumOfDaysInMonth()) {
		return true; 
	} else {
		return false;
	}
}

Utopia.Calendar.Viewer.prototype.changeDate=function (newYear,newMonth) {
	this.calendarDate=new Date(newYear, newMonth);
} 

Utopia.Calendar.Viewer.prototype.getHtml=function(newYear,newMonth) {
	var firstDayInNextWeek,calendarTable,firstDayInMonth;
	this.changeDate(newYear,newMonth);
	calendarTable=document.createElement("TABLE");
	firstDayInMonth=new Date(this.calendarDate.getFullYear(),this.calendarDate.getMonth(),1);
	this.getTableHeader(calendarTable);
	firstDayInNextWeek=this.getTableRow(calendarTable,firstDayInMonth.getDay(),1);
	while (this.isDateValid(firstDayInNextWeek)) {
		firstDayInNextWeek=this.getTableRow(calendarTable,this.columnDayOrder[0],firstDayInNextWeek);
	}
	DHTMLApi.CSS.setClass(calendarTable,[this.CSSClasses['calendarTable']],[]);
	return calendarTable;
}

Utopia.Calendar.Viewer.prototype.getTableHeader=function(tableObj) {
	var headerCell;
	var headerRow=tableObj.insertRow(0);
	for (i=0;i<7;i++) {
		headerCell=document.createElement("TH");
		headerCell.appendChild(document.createTextNode(this.weekDaysLabels[this.columnDayOrder[i]]));
		headerRow.appendChild(headerCell);
	}
}

Utopia.Calendar.Viewer.prototype.getTableRow=function(tableObj,firstDayofTheWeek,startDate) {
	var calendarRow=tableObj.insertRow(tableObj.rows.length);
	var columnIndex=0;
	var currentDayNum=startDate;

	while (firstDayofTheWeek!=this.columnDayOrder[columnIndex]) {
		calendarRow.insertCell(calendarRow.cells.length);
		columnIndex++;
	}
	
	for(var i=columnIndex; i<7; i++) {
		var calendarCell=calendarRow.insertCell(calendarRow.cells.length);
		//calendarCell.style.cursor="pointer";
		DHTMLApi.CSS.setProperties(calendarCell,{cursor: "pointer"});
		calendarCell.appendChild(document.createTextNode(currentDayNum));
		calendarRow.appendChild(calendarCell);
		this.calendarCellObj[currentDayNum]=calendarCell;
		currentDayNum++;
		columnIndex++;				
		if (!this.isDateValid(currentDayNum)) break;
	}
		
	for (var j=0; j<7-columnIndex; j++) {
		calendarRow.insertCell(calendarRow.cells.length);
	}
	return currentDayNum;
}

Utopia.Calendar.Viewer.prototype.setSelectedDate=function(dayNum) {
	this.selectedDays=new Array();
	this.selectedDays[0]=dayNum;
}

Utopia.Calendar.Viewer.prototype.setSelectedDates=function(daysNumArray) {
	this.selectedDays=daysNumArray;
}

Utopia.Calendar.Viewer.prototype.isSelected=function (dayNumber) {
	for (var i=0; i<this.selectedDays.length; i++) {
		if (this.selectedDays[i]==dayNumber) return true;
	}
	return false;
}

Utopia.Calendar.Viewer.prototype.displaySelectedDates=function() {
	for (var i=1; i<this.calendarCellObj.length; i++) {
		if (this.isSelected(i)==true) {
			DHTMLApi.CSS.setClass(this.calendarCellObj[i],[this.CSSClasses['selectedDay']],[]);
		} else {
			DHTMLApi.CSS.setClass(this.calendarCellObj[i],[],[this.CSSClasses['selectedDay']]);
		}
	}
}

Utopia.Calendar.Viewer.prototype.getCalendarCellObjectArray=function() {
	return this.calendarCellObj;
}



//////////////////////////////////////////////////
// class Utopia.Calendar.DatePickerControlPanel //
//////////////////////////////////////////////////

/*
 CSSClasses = {monthSelector: string, yearInputField: string}
*/

Utopia.Calendar.DatePickerControlPanel=function (container,year,month,monthsArray,CSSClasses,onChangeHandler) {
	this.container=container;
	this.yearField=null;
	this.CSSClasses=CSSClasses;
	this.monthSelector=this.getMonthSelector(monthsArray,month);
	this.CSSClasses=CSSClasses;
	this.yearSelectorGroup=this.getYearSelectorGroup(year);
	this.onChangeHandler=onChangeHandler;
	this.init();
}

Utopia.Calendar.DatePickerControlPanel.prototype.getMonthSelector=function(monthsArray,monthSelected) {
	var obj=this;
	var monthSelector=document.createElement("SELECT");
	for (var i=0; i<monthsArray.length; i++) {
		var monthOption=document.createElement("OPTION");
		monthOption.appendChild(document.createTextNode(monthsArray[i]));
		monthOption.value=i;
		if (i==monthSelected) {
			monthOption.selected=true;
		}
		monthSelector.appendChild(monthOption);
	}
	DHTMLApi.CSS.setClass(monthSelector,[this.CSSClasses['monthSelector']],[]);
	DOMEvent.addDomListener(monthSelector,"change", function () {obj.onChangeHandler();});
	return monthSelector;
}

Utopia.Calendar.DatePickerControlPanel.prototype.getYearSelectorGroup=function(yearSelected) {
	var obj=this;
	this.yearField=document.createElement("INPUT");
	this.yearField.type="text";
	this.yearField.value=yearSelected;
	this.yearField.maxLength=4;
	DHTMLApi.CSS.setClass(this.yearField,[this.CSSClasses['yearInputField']],[]);
	DOMEvent.addDomListener(this.yearField,"keyup", function () {if (this.value.length==4) {
		obj.onChangeHandler();
	}});
	return this.yearField;	
}

Utopia.Calendar.DatePickerControlPanel.prototype.init=function() {
	this.container.appendChild(this.monthSelector);
	this.container.appendChild(this.yearSelectorGroup);
}

Utopia.Calendar.DatePickerControlPanel.prototype.getYearSelected=function() {
	return Number(this.yearField.value);
}

Utopia.Calendar.DatePickerControlPanel.prototype.getMonthSelected=function() {
	return(this.monthSelector.options[this.monthSelector.selectedIndex].value);
}


///////////////////////////////////////////
// class Utopia.Calendar.DateChangeEvent //
///////////////////////////////////////////

Utopia.Calendar.DateChangeEvent=function (year,month,day) {
	this.year=year;
	this.month=month;
	this.day=day;
}

Utopia.Calendar.DateChangeEvent.prototype.getYear=function() {
	return Number(this.year);
}

Utopia.Calendar.DateChangeEvent.prototype.getMonth=function() {
	return Number(this.month);
}

Utopia.Calendar.DateChangeEvent.prototype.getDay=function() {
	return Number(this.day);
}


//////////////////////////////////////
// class Utopia.Calendar.DatePicker //
//////////////////////////////////////

/*
{calendarTable: "calendar", selectedDay: "markedday", monthSelector: "datepickermonth", yearInputField: "datepickeryearfield"}
*/

// listenerObj must implement onDateChange(Utopia.Calendar.DateChangeEvent event) method

Utopia.Calendar.DatePicker=function (controlPanelContainer,calendarContainer,yearSelected,monthSelected,daySelected,weekDaysLabels,startWithDayOfTheWeek,monthsArray,CSSClasses) {
	this.controlPanelContainer=controlPanelContainer;
	this.calendarContainer=calendarContainer;
	this.yearSelected=yearSelected;
	this.monthSelected=monthSelected;
	this.daySelected=daySelected;
	this.CSSClasses=CSSClasses;
	this.pickerCalendar=null;
	this.pickerControlPanel=null;	
	this.calendarTable=null;
	this.init(weekDaysLabels,startWithDayOfTheWeek,monthsArray);
}

Utopia.Calendar.DatePicker.prototype=implementsInterface(Observable);

Utopia.Calendar.DatePicker.prototype.init=function(weekDaysLabels,startWithDayOfTheWeek,monthsArray) {
	var obj=this;
	this.pickerCalendar=new Utopia.Calendar.Viewer(weekDaysLabels, startWithDayOfTheWeek, this.CSSClasses);
	this.pickerControlPanel=new Utopia.Calendar.DatePickerControlPanel(this.controlPanelContainer,this.yearSelected,this.monthSelected,monthsArray,this.CSSClasses,changeMonth);	
	this.calendarTable=this.pickerCalendar.getHtml(this.yearSelected,this.monthSelected);
	//this.controlPanelContainer.appendChild(this.pickerControlPanel.getControlPanel());
	this.calendarContainer.appendChild(this.calendarTable);
	this.displaySelectedDay(this.yearSelected,this.monthSelected);
	//this.pickerControlPanel.setOnChangeHandler(changeMonth);	
	this.initDateCells();
	function changeMonth() {
		var yearViewed=obj.pickerControlPanel.getYearSelected();
		var monthViewed=obj.pickerControlPanel.getMonthSelected();
		obj.calendarTable=obj.pickerCalendar.getHtml(yearViewed,monthViewed);
		obj.calendarContainer.removeChild(obj.calendarContainer.getElementsByTagName("TABLE")[0]);
		obj.calendarContainer.appendChild(obj.calendarTable);
		obj.displaySelectedDay(yearViewed,monthViewed);
		obj.initDateCells();
	}
}

Utopia.Calendar.DatePicker.prototype.initDateCells=function() {
	var obj=this;
	var cellsArray=this.pickerCalendar.getCalendarCellObjectArray();
	for (var i=1;i<cellsArray.length;i++) {
		cellsArray[i].onclick=cellClickHandler;
	}

	function cellClickHandler() {
		var dateNumber=this.firstChild.nodeValue;
		obj.yearSelected=obj.pickerControlPanel.getYearSelected();
		obj.monthSelected=obj.pickerControlPanel.getMonthSelected();
		obj.daySelected=dateNumber;
		obj.displaySelectedDay(obj.pickerControlPanel.getYearSelected(),obj.pickerControlPanel.getMonthSelected());
		// inform listeners about date change
		obj.notifyListeners("onDateChange",new Utopia.Calendar.DateChangeEvent(obj.yearSelected,obj.monthSelected,obj.daySelected));
	}
}

Utopia.Calendar.DatePicker.prototype.displaySelectedDay=function(yearViewed,monthViewed) {
	if (this.yearSelected==yearViewed && this.monthSelected==monthViewed) {
		this.pickerCalendar.setSelectedDate(this.daySelected);
		this.pickerCalendar.displaySelectedDates();
	}
}

/////////////////////////////////////////
// class Utopia.Calendar.DateFormField //
/////////////////////////////////////////

Utopia.Calendar.DateFormField=function(calendarDatePickerObj, calendarContainer, dateValueField, showButton, hideButton, dateDisplayContainer) {
	this.calendarDatePickerObj=calendarDatePickerObj;
	this.calendarContainer=calendarContainer;
	this.dateValueField=dateValueField;
	this.showButton=showButton;
	this.hideButton=hideButton;
	this.dateDisplayContainer=dateDisplayContainer;
	this.calendarIsVisible=false;
	this.init();
}

Utopia.Calendar.DateFormField.prototype.init=function() {
	var obj=this;
	this.displayDate(this.calendarDatePickerObj.yearSelected,this.calendarDatePickerObj.monthSelected,this.calendarDatePickerObj.daySelected);
	this.setValueField(this.calendarDatePickerObj.yearSelected,this.calendarDatePickerObj.monthSelected,this.calendarDatePickerObj.daySelected);
	DOMEvent.addDomListener(this.showButton,"click",function () {obj.showCalendar();});
	DOMEvent.addDomListener(this.hideButton,"click",function () {obj.hideCalendar();});
	this.calendarDatePickerObj.addListener(this);
}

Utopia.Calendar.DateFormField.prototype.onDateChange=function(changedDateEvent) {
	this.displayDate(changedDateEvent.getYear(),changedDateEvent.getMonth(),changedDateEvent.getDay());
	this.setValueField(changedDateEvent.getYear(),changedDateEvent.getMonth(),changedDateEvent.getDay());
}

Utopia.Calendar.DateFormField.prototype.hideCalendar=function() {
	DHTMLApi.Visibility.hide(this.calendarContainer);
	DHTMLApi.Visibility.show(this.showButton);
	DHTMLApi.Visibility.hide(this.hideButton);
	this.calendarIsVisible=false;
}

Utopia.Calendar.DateFormField.prototype.showCalendar=function() {
	DHTMLApi.Visibility.show(this.calendarContainer);
	DHTMLApi.Visibility.hide(this.showButton);
	DHTMLApi.Visibility.show(this.hideButton);
	this.calendarIsVisible=true;
}

Utopia.Calendar.DateFormField.prototype.displayDate=function(year,month,date) {
	while (this.dateDisplayContainer.hasChildNodes()) {
		this.dateDisplayContainer.removeChild(this.dateDisplayContainer.firstChild);
	}
	this.dateDisplayContainer.appendChild(document.createTextNode(date+" / "+(month+1)+" / "+year));
}

Utopia.Calendar.DateFormField.prototype.setValueField=function(year,month,date) {
	var timeStampString=String(year);
	if (month<9) timeStampString+="0";
	timeStampString+=String((month+1));
	if (date<10) timeStampString+="0";
	timeStampString+=String(date);
	this.dateValueField.value=timeStampString;
}

/////////////////////////////
// Static Class PopUpLayer //
/////////////////////////////

PopUpLayer= {
	
	containerZIndex: 10000,
	
	init: function (popUpDivNode,backgroundCssClass,backgroundAlpha,closeButtonElement,onCloseCallback) {
		this.popUpDivNode=popUpDivNode;
		this.parentpopUpDivNode=popUpDivNode.parentNode;
		this.nextSiblingpopUpDivNode=popUpDivNode.nextSibling;
		this.popupContainerNode=null;
		this.backgroundNode=null;
		this.backgroundCssClass=backgroundCssClass;
		this.backgroundAlpha=backgroundAlpha;
		this.closeButtonElement=null;
		this.onCloseCallback=null;
		if (typeof closeButtonElement != "undefined") {
			this.closeButtonElement=closeButtonElement;
		}
		if (typeof onCloseCallback != "undefined") {
			this.onCloseCallback=onCloseCallback;
		}
		this.resizeHandler=null;
		this.closeHandler=null;
		this.closeButtonHandler=null;
		this.tempPopUpDivNodeStyles={position: DHTMLApi.CSS.getStyle(this.popUpDivNode, "position"), top: DHTMLApi.CSS.getStyle(this.popUpDivNode, "top"), left: DHTMLApi.CSS.getStyle(this.popUpDivNode, "left"), zIndex: DHTMLApi.CSS.getStyle(this.popUpDivNode, "z-index"), display: DHTMLApi.CSS.getStyle(this.popUpDivNode, "display")};
	},
	
	initHandlers: function () {
		var obj=this;
		this.resizeHandler=DOMEvent.addDomListener(window, "resize", function () {
			obj.centerOnPage();
		});
		this.closeHandler=DOMEvent.addDomListener(this.backgroundNode, "click", function () {
			obj.hide();
			if (obj.onCloseCallback!==null) (obj.onCloseCallback)();
		});
		if (this.closeButtonElement!==null) {
			this.closeButtonHandler=DOMEvent.addDomListener(this.closeButtonElement, "click", function () {
				obj.hide();
				if (obj.onCloseCallback!==null) (obj.onCloseCallback)();
			});
		}
	},
	
	removeHandlers: function () {
		DOMEvent.removeListener(this.resizeHandler);
		DOMEvent.removeListener(this.closeHandler);
		if (this.closeButtonHandler!==null) {
			DOMEvent.removeListener(this.closeButtonHandler);
		}
		this.resizeHandler=null;
		this.closeHandler=null;
		this.closeButtonHandler=null;
	},
	
	build: function () {
		var popUpNode;
		this.popupContainerNode=document.createElement("DIV");
		document.body.appendChild(this.popupContainerNode);
		DHTMLApi.CSS.setProperties(this.popupContainerNode,{position: "absolute", top: "0px", left: "0px", width: DHTMLApi.Size.getPageWidth()+"px", height: DHTMLApi.Size.getPageHeight()+"px", zIndex: this.containerZIndex, overflow:"auto"});
		this.backgroundNode=document.createElement("DIV");
		this.popupContainerNode.appendChild(this.backgroundNode);
		DHTMLApi.CSS.setProperties(this.backgroundNode,{position: "absolute", top: "0px", left: "0px", zIndex: 1, cursor: "pointer", width: "100%", height: "100%"});
		DHTMLApi.CSS.setClass(this.backgroundNode,new Array(this.backgroundCssClass),new Array());
		
		popUpNode=this.parentpopUpDivNode.removeChild(this.popUpDivNode);
		this.popupContainerNode.appendChild(popUpNode);
		DHTMLApi.CSS.setProperties(popUpNode, {position: "absolute", zIndex: 2, display: "block"});
		DHTMLApi.Visibility.setOpacity(this.backgroundNode,this.backgroundAlpha);
		
		this.initHandlers();
	},
	
	restorePopUpNode: function() {
		if (this.nextSiblingpopUpDivNode!==null) {
			this.parentpopUpDivNode.insertBefore(this.popUpDivNode,this.nextSiblingpopUpDivNode);
		} else {
			this.parentpopUpDivNode.appendChild(this.popUpDivNode);
		}
		
		DHTMLApi.CSS.setProperties(this.popUpDivNode,this.tempPopUpDivNodeStyles);
	},
	
	centerOnPage: function () {
		var leftPos,topPos;
		leftPos=Math.round((DHTMLApi.Browser.getViewportWidth()-DHTMLApi.Size.getElementWidth(this.popUpDivNode))/2+DHTMLApi.Browser.getScrollX());
		topPos=Math.round((DHTMLApi.Browser.getViewportHeight()-DHTMLApi.Size.getElementHeight(this.popUpDivNode))/2+DHTMLApi.Browser.getScrollY());
		if (topPos+DHTMLApi.Size.getElementHeight(this.popUpDivNode)>DHTMLApi.Size.getPageHeight()) {
			topPos=DHTMLApi.Size.getPageHeight()-DHTMLApi.Size.getElementHeight(this.popUpDivNode);
		}
		DHTMLApi.CSS.setProperties(this.popUpDivNode, {left: leftPos+"px", top: topPos+"px"});
	},
	
	display: function (popUpDivNode,backgroundCssClass,backgroundAlpha,closeButtonElement,onCloseCallback) {
		this.init(popUpDivNode,backgroundCssClass,backgroundAlpha,closeButtonElement,onCloseCallback);
		this.build();
		this.centerOnPage();
	},
	
	hide: function () {
		this.removeHandlers();
		this.restorePopUpNode();
		document.body.removeChild(this.popupContainerNode);
	}	
}
