function EventCalendar(htmlId, language, urlprefix) {

	this.getE = function (idorobj) {
		if (typeof idorobj == 'string') return document.getElementById(idorobj);
		else return idorobj;
	}
	this.emptyElement = function(elem) {
		while (elem.firstChild) elem.removeChild(elem.firstChild);
	}
	this.slideLeft = function(from) {
		this.closePopup();
		this.slide(from, -5);
	}
	this.slideRight = function(from) {
		this.closePopup();
		this.slide(from, 5);
	}
	this.slide = function(from, direction) {
		if (!this.sliderTimer) {
			var self = this;
			this.slideOffset = direction;

			this.innerDiv.style.position = 'relative';
			
			if (direction > 0) {
				this.innerDiv.firstChild.style.cssFloat = 'right';
				this.innerDiv.firstChild.style.marginLeft = '20px';
				this.innerDiv.style.left = (0 - this.container.offsetWidth-20) + 'px';
				this.slideOffset = 0-this.container.offsetWidth-20;
			} else {
				this.innerDiv.firstChild.style.cssFloat = 'left';
				this.innerDiv.style.left = '0px';
				this.innerDiv.firstChild.style.marginRight = '20px';
			}
			

			this.sliderTimer = window.setInterval(function(){
				self.innerDiv.style.left = self.slideOffset + 'px';
				
				if (((direction < 0) && (Math.abs(self.slideOffset) >= (self.container.offsetWidth+20))) || ((direction > 0) && (self.slideOffset >= 0))) {
					window.clearTimeout(self.sliderTimer);
					self.sliderTimer = null;
					self.innerDiv.removeChild(self.innerDiv.firstChild);
					self.innerDiv.style.position = 'static';
				}
				self.slideOffset += direction;
			}, 20);
			this.show(from);
		}
	}
	this.show = function(from) {
		var url = this.prefixURL + '/get_events.html?lang=' + this.languageCode;
		if (typeof from != 'undefined') url += "&month=" + from;
		var self = this;
		this.xmlreq.setEventHandler(
			function(readyState, response, error) {
				self.onEventsResponse(from, readyState, response, error);
			}
		);
		if (!this.xdomain) {
			//
			// Old browsers do not support cross domain XHR, so we have to carefully
			// determine the outcome of the send() call. Mozilla seems to return false on failure,
			// while IE seems to drop an exception. crossDomainRequest() is supposed to solve this whole
			// problem by using a local file as proxy.
			try {
				this.xmlreq.send(url);
				//if (this.xmlreq.send(url) == false) this.crossDomainRequest(from);
			} catch(e) {
				this.crossDomainRequest(from);
			}
		} else this.crossDomainRequest(from);
	}
	//
	// Pass the request through a local file to circumvent the cross domain restriction
	this.crossDomainRequest = function(from) {
		this.xdomain = true;
		var url = '/events_proxy.php?lang=' + this.languageCode + '&prefix=' + encodeURIComponent(this.prefixURL);
		if (typeof from != 'undefined') url += "&month=" + from;
		try {
			this.xmlreq.send(url);
		} catch(e) {}
	}
	this.daysInMonth = function(month,year) {
		var m = [31,28,31,30,31,30,31,31,30,31,30,31];
		if (month != 2) return m[month - 1];
		if (year%4 != 0) return m[1];
		if (year%100 == 0 && year%400 != 0) return m[1];
		return m[1] + 1;
	} 
	this.isParam = function(param) {
		return (typeof(param) != 'undefined') && (param != null);
		
	}
	this.onEventsResponse = function(from, readyState, response, error) {
		var self = this;
		if ((readyState == 4) && (response==null)) {
			//alert(from+'-'+readyState+'-'+response+'-'+error);
			setTimeout(function(){self.crossDomainRequest(from);},100);
			//this.crossDomainRequest(from);
		} else if ((readyState == 4) && response && response.firstChild && (response.firstChild.nodeName == 'events')) {
			var events = [];
			for(var i=0; i<response.firstChild.childNodes.length; i++) {
				events.push([response.firstChild.childNodes[i].getAttribute('from')*1000, response.firstChild.childNodes[i].getAttribute('to')*1000, response.firstChild.childNodes[i].firstChild.nodeValue, response.firstChild.childNodes[i].getAttribute('datetext')]);
			}
			var previousTimeframe = response.getAttribute('previous');
			var nextTimeframe = response.getAttribute('next');
			var startOfTimeframe = new Date(response.getAttribute('from')*1000);
			
			var day = 1 - (startOfTimeframe.getDay()==0?6:(startOfTimeframe.getDay() - 1));
			var end = this.daysInMonth(startOfTimeframe.getMonth() + 1, startOfTimeframe.getFullYear());
			var j; var row; var cell; var thisDate; var today = new Date(new Date().getFullYear(), new Date().getMonth(), new Date().getDate()).getTime(); var className; var tooltip; var thisEvents;
			
			this.container.style.overflow = 'hidden';
			if (this.slideOffset == 0) {
				this.emptyElement(this.container);
				var table = this.createTable(this.innerDiv = this.createDiv(this.container, 20 + (this.container.offsetWidth * 2)), 2, 0, this.container.offsetWidth);
			} else {
				var table = this.createTable(this.innerDiv, 2, 0, this.container.offsetWidth);
			}
			row = this.createRow(table, 'header');
			this.createCell(row, 'center', 7, response.getAttribute('name'));
			while (day < end) {
				row = this.createRow(table);
				for(j = 0; j<7; j++) {
					if ((day <= 0) || (day > end)) this.createCell(row);
					else {
						className='';thisDate=new Date(startOfTimeframe.getFullYear(),startOfTimeframe.getMonth(),day).getTime();
						if(today==thisDate)className+=(className!=''?' ':'')+'today';
						tooltip = ''; thisEvents = [];
						for(i=0; i<events.length; i++) {
							if ((events[i][0] <= thisDate) && (events[i][1] >= thisDate)) {
								if (className.indexOf('event') == -1) className+=(className!=''?' ':'')+'event';
								tooltip += (tooltip!=''?'\n':'') + events[i][2];
								thisEvents.push(events[i]);
							}
						}
						// create cell
						var cell = this.createCell(row, 'center', null, day, className==''?null:className);
						if (tooltip != '') cell.title = tooltip;
						if (thisEvents.length > 0) {
							this.hackOnClick(cell, thisEvents);
						} else {
							cell.style.cursor = 'default';
						}
					}
					day++;
				}
			}
			row = this.createRow(table, 'footer');
			this.createLink(this.createCell(row, 'left', '3'), '#', function(){self.slideRight(previousTimeframe);return false;}, ' <<< ');
			this.createCell(row);
			this.createLink(this.createCell(row, 'right', '3'), '#', function(){self.slideLeft(nextTimeframe);return false;}, ' >>> ');
		}
	}
	this.hackOnClick = function(obj, events) {
		var self = this;
		obj.onclick=function(){self.openPopup(events)};
		obj.style.cursor = 'pointer';
	}
	this.createTable = function(container, padding, spacing, width, domChildPosition) {
		var table = document.createElement('TABLE');
		if (this.isParam(width)) table.width = width;
		if (this.isParam(padding)) table.cellPadding = padding;
		if (this.isParam(spacing)) table.cellSpacing = spacing;
		var tbody = document.createElement('TBODY');
		table.appendChild(tbody);
		if (this.isParam(domChildPosition)) container.insertBefore(table, domChildPosition);
		else container.appendChild(table);
		return tbody;
	}
	this.createRow = function(container, className) {
		var row = document.createElement('TR');
		if (this.isParam(className)) row.className = className;
		container.appendChild(row);
		return row;
	}
	this.createCell = function(container, align, colspan, text, className) {
		var cell = document.createElement('TD');
		if (this.isParam(align)) cell.align = align;
		if (this.isParam(colspan)) cell.colSpan = colspan;
		if (this.isParam(text)) cell.appendChild(document.createTextNode(text));
		if (this.isParam(className)) cell.className = className;
		container.appendChild(cell);
		return cell;
	}
	this.createLink = function(container, href, onclick, text) {
		var link = document.createElement('A');
		link.href = href;
		if (this.isParam(text)) link.appendChild(document.createTextNode(text));
		if (this.isParam(onclick)) link.onclick = onclick;
		container.appendChild(link);
		return link;
	}
	this.createDiv = function(container, width) {
		var div = document.createElement('DIV');
		if (this.isParam(width)) div.style.width = width + 'px';
		container.appendChild(div);
		return div;
	}
	this.setPopupResize = function() {
		var self = this;
		if (!this.popupOnResizeSet) {
			this.popupOnResizeSet = true;
			if (window.onresize) window.onPreviousResize = window.onresize;
			window.onresize = function(){
				if (window.onPreviousResize) window.onPreviousResize();
				self.popupWindow.style.left = (document.body.scrollLeft + Math.round((parseInt(document.body.offsetWidth) / 2) - (parseInt(self.popupWindow.style.width) / 2)))  + "px";
				self.popupWindow.style.top = (document.body.scrollTop + Math.round((parseInt(document.body.offsetHeight) / 2) - (parseInt(self.popupWindow.style.height) / 2)))  + "px";
			};
			if (window.onscroll) window.onPreviousScroll = window.onscroll;
			window.onscroll = function(){
				if (window.onPreviousScroll) window.onPreviousScroll();
				self.popupWindow.style.left = (document.body.scrollLeft + Math.round((parseInt(document.body.offsetWidth) / 2) - (parseInt(self.popupWindow.style.width) / 2)))  + "px";
				self.popupWindow.style.top = (document.body.scrollTop + Math.round((parseInt(document.body.offsetHeight) / 2) - (parseInt(self.popupWindow.style.height) / 2)))  + "px";
			};
		}
	}
	this.closePopup = function() {
		this.clearPopupResize();
		this.popupWindow.style.display = 'none';
	}
	this.clearPopupResize = function() {
		if (this.popupOnResizeSet) {
			this.popupOnResizeSet = false;
			if (window.onPreviousResize) window.onresize = window.onPreviousResize;
			else window.onresize = null;
			if (window.onPreviousScroll) window.onscroll = window.onPreviousScroll;
			else window.onscroll = null;
		}
	}
	this.openPopup = function(events, speed, state) {
		if (typeof(speed) == 'undefined') speed = 40;
		var self = this; var steps = 15;
		this.clearPopupResize();
		if (typeof(state) == 'undefined') {
			this.popupWindow.targetWidth = 300;
			
			this.popupWindow.onclick = function(){self.closePopup()};
			this.popupWindow.style.cursor = 'pointer';
			this.popupWindow.style.opacity = 0;
			this.popupWindow.style.filter = 'alpha(opacity=' + 0 + ')';
			this.popupWindow.style.display = 'block';
			this.popupWindow.style.width = this.popupWindow.targetWidth + "px";
			this.popupWindow.style.height = 'auto';
			this.popupWindow.innerHTML = ''; var extracss = '';
			for (var i=0; i<events.length; i++) {
				extracss = (i+1)==events.length?' last':'';
				this.popupWindow.innerHTML += '<span class="date">' + events[i][3] + '</span><span class="description'+extracss+'">' + events[i][2] + '</span>';
			}
			this.popupWindow.targetHeight = Math.max(this.popupWindow.offsetHeight-12, 100);
			//alert(this.popupWindow.targetWidth + 'x' + this.popupWindow.targetHeight);
			
			this.popupWindow.targetLeft = Math.round((parseInt(document.body.offsetWidth) / 2) - (this.popupWindow.targetWidth / 2));
			this.popupWindow.targetTop = Math.round((parseInt(document.body.offsetHeight) / 2) - (this.popupWindow.targetHeight / 2));

			this.popupWindow.style.width = (this.container.offsetWidth - (this.isMozilla?2:0)) + "px";
			this.popupWindow.style.height = (this.container.offsetHeight - (this.isMozilla?2:0)) + "px";
			this.popupWindow.style.left = this.findPosX(this.container) + "px";
			this.popupWindow.style.top = this.findPosY(this.container) + "px";
			window.setTimeout(function(){self.openPopup(events, speed, 1)}, speed);
		} else if(this.popupWindow.style.display == 'block') {
			this.popupWindow.style.opacity = ((1 / (steps)) * (state-1));
			this.popupWindow.style.filter = 'alpha(opacity=' + ((100 / steps) * state) + ')';
			this.popupWindow.style.width = (parseInt(this.popupWindow.style.width) + Math.round((this.popupWindow.targetWidth - parseInt(this.popupWindow.style.width)) / (steps - state)))  + "px";
			this.popupWindow.style.height = (parseInt(this.popupWindow.style.height) + Math.round((this.popupWindow.targetHeight - parseInt(this.popupWindow.style.height)) / (steps - state)))  + "px";
			this.popupWindow.style.left = (parseInt(this.popupWindow.style.left) + Math.round((document.body.scrollLeft + this.popupWindow.targetLeft - parseInt(this.popupWindow.style.left)) / (steps - state)))  + "px";
			this.popupWindow.style.top = (parseInt(this.popupWindow.style.top) + Math.round((document.body.scrollTop + this.popupWindow.targetTop - parseInt(this.popupWindow.style.top)) / (steps - state)))  + "px";
			if (state < steps) {
				window.setTimeout(function(){self.openPopup(events, speed, state + 1)}, speed);
			} else {
				this.setPopupResize();
			}
		}
	}
	this.findPosX = function(obj) {
		var curleft = 0;
		if (obj.offsetParent) {
			while (obj.offsetParent) {
				curleft += obj.offsetLeft
				obj = obj.offsetParent;
			}
		} else if (obj.x)
			curleft += obj.x;
		return curleft;
	}
	
	this.findPosY = function(obj) {
		var curtop = 0;
		if (obj.offsetParent) {
			while (obj.offsetParent) {
				curtop += obj.offsetTop
				obj = obj.offsetParent;
			}
		} else if (obj.y)
			curtop += obj.y;
		return curtop;
	}

	this.innerDiv = null;
	this.xmlreq = new XMLRequest(true, 'XML');
	this.xdomain = false;
	this.container = this.getE(htmlId);
	this.isMozilla = navigator.appName.indexOf('Netscape')!=-1;
	this.languageCode = language;
	this.prefixURL = urlprefix?urlprefix:'';
	this.sliderTimer = null;
	this.slideOffset = 0;
	this.popupWindow = this.createDiv(document.body);
	this.popupWindow.className = 'eventsPopupWindow';
	this.popupWindow.style.position = 'absolute';
	this.popupWindow.style.display = 'none';
	this.show();
}
