function jDate(){
//	example: var cal=new jDate();
//	example: var cal=new jDate("it", 2007,11);
//	example: var cal=new jDate("en", 2006,2,29);if(cal.exists)...
	
	this.now = new Date();
	// DATE FORMAT (PHP style: http://it2.php.net/manual/it/function.date.php )
	var startingLang = (arguments.length>0)?arguments[0]:"it";
	this.j = (arguments.length>3)?arguments[3]:this.now.getDate();		// day
	this.n = (arguments.length>2)?arguments[2]:(this.now.getMonth()+1);	// month
	this.Y = (arguments.length>1)?arguments[1]:this.now.getFullYear();	// year
	
	// check for valid date (and declaration of "checkDate" method)
	this.checkDate=function(yyyy,mm,gg){
		function y2k(q){return(q<1000)?q+1900:q;}
		var today=new Date();
		yyyy = ((!yyyy) ? y2k(today.getFullYear()):yyyy)
		mm = ((!mm) ? today.getMonth():mm-1)
		if (!gg) return false
		var test = new Date(yyyy,mm,gg)
		if ((y2k(test.getFullYear()) == yyyy) && (mm == test.getMonth()) && (gg == test.getDate()) ){
			return true
		}else{
			return false
		}
	}

	this.exists=this.checkDate(this.Y,this.n,this.j);
	
	/* LANGUAGE */
	this.lngStr = [];

	this.lngStr.it = {
		"dayName":["Domenica","Luned&#236;","Marted&#236;","Mercoled&#236;","Gioved&#236;","Venerd&#236;","Sabato"],
		"monthName":["Gennaio","Febbraio","Marzo","Aprile","Maggio","Giugno","Luglio","Agosto","Settembre","Ottobre","Novembre","Dicembre"],
		"labels":["Mostra il mese precedente","Mostra il mese successivo","Calendario eventi di"]
	};
	this.lngStr.en = {
		"dayName":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
		"monthName":["January","February","March","April","May","June","July","August","September","October","November","December"],
		"labels":["Show previous month","Show next month","Events calendar of"]
	};
	this.lngStr.zh = {
		"dayName":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
		"monthName":["January","February","March","April","May","June","July","August","September","October","November","December"],
		"labels":["Show previous month","Show next month","Events calendar of"]
	};
	this.lngStr.ru = {
		"dayName":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
		"monthName":["January","February","March","April","May","June","July","August","September","October","November","December"],
		"labels":["Show previous month","Show next month","Events calendar of"]
	};
	
	this.firstDay=0;
	/* GENERIC FUNCTIONS */
	this.zeroFill=function(q){
		q=String(q);
		return (q.length<2)?("0"+q):q;
	}
	/* METHODS (checkDate already declared) */
	this.setFirstDay=function(q){
		var i,r=[],a=this.lngStr[this.lang].dayName;
		if(q>a.length||q<=0||isNaN(q)){
			this.lngStr.current.dayName=a;
		}else{
			for(i=q;i<a.length;i++)r[r.length]=a[i];
			for(i=0;i<q;i++)r[r.length]=a[i];
			this.lngStr.current.dayName=r;
		}
	}

	this.setLang = function(q){
		var i,found=false;

		if(q!=this.lang){
			switch(q){
				case"it":	this.firstDay=1;found=true;		break;
				case"en":	this.firstDay=0;found=true;		break;
				case"zh":	this.firstDay=1;found=true;		break;
				case"ru":	this.firstDay=1;found=true;		break;
			}
			if(found){
				this.lang = q;
				this.lngStr.current={"dayName":[],"monthName":[],"labels":[]};
				for(i=0;i<this.lngStr[q].dayName.length;i++)this.lngStr.current.dayName[i]=this.lngStr[q].dayName[i];
				for(i=0;i<this.lngStr[q].monthName.length;i++)this.lngStr.current.monthName[i]=this.lngStr[q].monthName[i];
				for(i=0;i<this.lngStr[q].labels.length;i++)this.lngStr.current.labels[i]=this.lngStr[q].labels[i];
				this.setFirstDay(this.firstDay);
				this.F = this.lngStr[this.lang].monthName[this.now.getMonth()];
				this.M = this.F.substring(0,3);
				this.l = this.lngStr[this.lang].dayName[this.now.getDay()]
				this.D = this.l.substring(0,3);
			}
		}
	}

	// DATE FORMAT (PHP style: http://it2.php.net/manual/it/function.date.php )
	this.now.setFullYear(this.Y);
	this.now.setMonth(this.n-1);
	this.now.setDate((this.exists)?this.j:0);
	
	this.setLang(startingLang); // setting lang redefines F M l and D
	
	this.d = this.zeroFill(this.j);
	this.m = this.zeroFill(this.n);
	this.y = (this.Y/100-parseInt(this.Y/100))*100;
	
	this.L = ((this.Y%4==0&&this.Y%100!=0)||this.Y%400==0)?1:0;
	
	if(this.n==4||this.n==6||this.n==9||this.n==11)this.t=30;
	else if(this.n==1||this.n==3||this.n==5||this.n==7||this.n==8||this.n==10||this.n==12)this.t=31;
	else if(this.n==2)this.t=(this.L)?29:28;
	
	this.w=this.now.getDay();
	
	this.G = (arguments.length>4)?arguments[4]:this.now.getHours();
	this.H = this.zeroFill(this.G);
	this.i = this.zeroFill((arguments.length>5)?arguments[5]:this.now.getMinutes());
	this.s = this.zeroFill((arguments.length>6)?arguments[6]:this.now.getSeconds());
	
	this.g = (this.G==0)?12:((this.G>12)?(this.G-1):this.G);
	this.h = this.zeroFill(this.g);
	this.a = (this.G>0&&this.G<13)?"am":"pm";
	this.A = this.a.toUpperCase();
	
	// Swatch Internet Time
	this.B="@"+Math.floor(((this.G-1) * 3600 + (this.i *60) + this.s * 1) * 1000 / 86400);
	if(this.B>=1000)this.B-=1000;
	else if(this.B<0)this.B+=1000;
	
	// Ora legale
	var date1 = new Date(this.Y, 0, 1, 0, 0, 0, 0);
	var date2 = new Date(this.Y, 6, 1, 0, 0, 0, 0);
	var temp = date1.toGMTString();
	var date3 = new Date(temp.substring(0, temp.lastIndexOf(" ")-1));
	var temp = date2.toGMTString();
	var date4 = new Date(temp.substring(0, temp.lastIndexOf(" ")-1));
	var hoursDiffStdTime = (date1 - date3) / (1000 * 60 * 60);
	var hoursDiffDaylightTime = (date2 - date4) / (1000 * 60 * 60);
	var TimeZone = hoursDiffStdTime; // es: GMT+100 = 1 ; es ora legale: GMT+200 = 1;
	var isDstObserved = (hoursDiffDaylightTime != hoursDiffStdTime);
	
	this.O = String(this.now);
	this.O=this.O.substr(this.O.indexOf("+"),5);
	this.I = ( hoursDiffStdTime != parseInt((this.O*1)/100) && isDstObserved ) ? 1 : 0;
	
	/* NOT IMPLEMENTED YET 
	c: ISO 8601 date (added in PHP 5)   {2004-02-12T15:19:21+00:00}
	r: RFC 2822 formatted date   {Example: Thu, 21 Dec 2000 16:01:07 +0200}
	S: English ordinal suffix for the day of the month, 2 characters   {st, nd, rd or th. Works well with j}
	T: Timezone setting of this machine   {Examples: EST, MDT ...}
	U: Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT)   {See also time()}
	W: ISO-8601 week number of year, weeks starting on Monday (added in PHP 4.1.0)   {Example: 42 (the 42nd week in the year)}
	z: The day of the year (starting from 0)   {0 through 365}
	Z: Timezone offset in seconds. The offset for timezones west of UTC is always negative, and for those east of UTC is always positive.   {-43200 through 43200}
	*/
}


// This script extends tje jDate object
jDate.prototype.dxCalendar = function(){

	var i,j;
	var table = document.createElement('table');
	table.className="jCalDx";
	table.summary=this.lngStr.current.labels[2]+" "+this.F+" "+this.Y;
	table.cellSpacing=0;
	// Controls
	var tr = document.createElement('tr');
	tr.className="cControl";
	
	var td = document.createElement('td');
	var a = document.createElement('a');

	a.href="javascript:changeMonth('"+this.lang+"',-1)";
	a.title=this.lngStr.current.labels[0];
	a.innerHTML = "&#171;";
	td.appendChild(a);
	tr.appendChild(td);
	
	var td = document.createElement('td');
	td.colSpan="5";
	td.innerHTML = this.F + " " + this.Y;
	tr.appendChild(td);
	
	var td = document.createElement('td');
	var a = document.createElement('a');
	a.title=this.lngStr.current.labels[1];
	a.href="javascript:changeMonth('"+this.lang+"',1)";
	a.innerHTML = "&#187;";
	td.appendChild(a);
	tr.appendChild(td);
	
	table.appendChild(tr);
	// Headers
	var tr = document.createElement('tr');
	for(i=0;i<7;i++){
		var th = document.createElement('th');
		var dayName=this.lngStr.current.dayName[i];
		dayName=dayName.substring(0,2);
		th.innerHTML=dayName;
		tr.appendChild(th);
	}
	table.appendChild(tr);
	// Days
	var g=1;
	var paz=this.now;paz.setDate(g);
	var today=new Date();
	var mm=this.n,aaaa=this.Y,start=false,end=false;
	
	var gg=this.t
	
	for (j=0;j<6;j++){
		var tr=document.createElement('tr');
		tr.className="cRow";
		for (i=this.firstDay;i<7+this.firstDay;i++){
			var td=document.createElement('td');
			if (paz.getDay()==i||(paz.getDay()==0&&j==0&&i==7))start=true;
			if (start && g<=gg){
				td.className="c"+g;
				if ( g==today.getDate() && this.n==today.getMonth()+1 && this.Y==today.getFullYear() )td.className+=" today";
				if ( g==this.j ) td.className+=" sel";
				var div=document.createElement('div');
				div.innerHTML = g;
				td.appendChild(div);
				if(g==this.t)end=true;
				g++;
			}else{
				td.className="cEmpty";
				var div=document.createElement('div');
				div.innerHTML = "&#160;";
				td.appendChild(div);
			}
			tr.appendChild(td);
		}
		table.appendChild(tr);
		if(end)break;
	}
	//
	return table;
}
function appendDomObj(myId,obj){
	var o=document.getElementById(myId);
	if(document.all)o.innerHTML+=obj.outerHTML;
	else o.appendChild(obj);
}
function removeDomObj(myId){
	var o=document.getElementById(myId);
	if(document.all)o.innerHTML="";
	else for(var i=o.childNodes.length-1;i>-1;i--)o.removeChild(o.childNodes[i]);
}
function replaceDomObj(myId,obj){
	removeDomObj(myId);
	appendDomObj(myId,obj);
}
function changeMonth(l, q){
	var m=q+cal.n;
	var y=cal.Y;
	if(m<1){m=12;y--}else if(m>12){m=1;y++}
	cal=new jDate(l,y,m);
	replaceDomObj('calendario',cal.dxCalendar());
	var a=document.getElementById('calendario').getElementsByTagName('a');
	if(q<0)a[0].focus();else if(q>0)a[1].focus();
	addEvents();
	if(typeof initMap!='undefined')initMap();
}
function addDxEvent(myId,j,n,Y,c,h,t){
	var o=document.getElementById(myId);
	var TDs=o.getElementsByTagName('td');
	for(var i=0;i<TDs.length;i++){
		if( n==cal.n && Y==cal.Y ){
			td=TDs[i];
			if( td.className=="c"+j || td.className.indexOf("c"+j+" ")==0 ){
				td.className+=' jCategory'+c;
				if(td.innerHTML.indexOf("<a ")==-1)td.innerHTML='<a href="'+h+'" onmouseover="tooltip(\''+t.replace(/'/i,'\\\'')+'\');" onmouseout="tooltipOut();" onmousemove="tooltipMove();">'+j+'</a>';
				else{
					var a = td.innerHTML ;
					a=a.split(' onmouseover="tooltip(\'');
					a[1]=a[1].split('\');"');
					var a = a[0] + ' onmouseover="tooltip(\'' + a[1][0] + '<br>' + t.replace(/'/i,'\\\'') + '\');"' + a[1][1] ;
					td.innerHTML = a ;
				}
				break;
			}
		}
	}
}

var calendarRequests=0;
function addEvents(){
	$("cal-loading").show();
	calendarRequests++;
	new Ajax.Request(
		"parsepage.php",{
			method: 'get',
			encoding: 'ISO-8859-1',
			parameters: "tpl=tpl_xml_calendar&sqlpam1="+cal.Y+cal.m+"01000000&sqlpam2="+cal.Y+cal.m+cal.t+"235959&xml=1",
			onSuccess: function(result){
				var contents = getXMLvalue(result.responseText,"lists").strip();
				if (contents!=""){
					contents=contents.split("</list>");
					contents.pop();
					for (i=0; i<contents.length; i++){
						var content=contents[i];
						var date=getXMLvalue(content,"date");
						var dateElements=date.split("-");
						var day=parseFloat(dateElements[2]);
						var month=parseFloat(dateElements[1]);
						var year=dateElements[0];
						
						var categoryId=getXMLvalue(content,"category_id");
						var title=getXMLvalue(content,"title");
						var link=getXMLvalue(content,"link");
					
						//alert("> "+day+","+month+","+year+" - "+categoryId+" - "+link+" - "+title);
					
						/* addDxEvent(containerId, day, month, year, category, link, title)*/
						addDxEvent('calendario',day,month,year,categoryId,link,title);
					}
				}
				calendarRequests--;
				if(calendarRequests==0)$("cal-loading").hide();
			}
		}
	);
}

function getXMLvalue(s,q){
	s=s.substring(s.indexOf("<"+q+">")+q.length+2,s.lastIndexOf("</"+q+">"));
	if(s.strip().indexOf("<![CDATA[")==0){
		s=s.substring(s.indexOf("<![CDATA[")+9,s.lastIndexOf("]]>"));
	}
	return s;
}
