//Copyright (c) 2004-2011 Anastasis Societa' Cooperativa,Bologna,Italy - www.anastasis.it
//	This copyright notice must stay intact for use.
/**
 * @fileoverview Questo file contiene il core del framework Anastasis.
 */


/**
 * La classe principale del framework.
 * @constructor Il costruttore (senza parametri) della classe Anastasis.
 * @namespace
 * @property {boolean} is_ie 	true se il browser e' Internet Explorer
 * @property {boolean} is_ie7 	true se il browser e' Internet Explorer 7; idem per is_ie8,is_ie9,is_ie10
 * @property {boolean} is_gecko true se il browser si basa sul motore gecko (Mozilla Firefox)
 * @property {boolean} is_mozilla true se il browser e' Mozilla Firefox
 * @property {boolean} is_webkit true se il browser si basa sul motore webkit (Safari, Chrome)
 * @property {boolean} is_opera true se il browser e' Opera
 * @property {String} base_url la posizione di questo file sul server (ricavata automaticamente)
 * @property {String} domain il dominio del sito della pagina corrente, ricavato automaticamente
 * @property {String} servletContext la servlet del sito della pagina corrente, ricavato automaticamente
 * @property {Object - Anastasis.Ajax} ajax un oggetto Ajax per la comunicazione
 * @property {Object - Anastasis.Utils} utils raccoglie varie funzioni utili
 */
function Anastasis()
{
	//--------- funzioni "private" usate solo dal costruttore -------------//
	var getBaseUrl=function()
	{
		var ss=document.getElementsByTagName("script");
		for(var index=0; index<ss.length; index++)
		{
			if(ss[index].src && ss[index].src.match(/Anastasis\.js/i))
			{
				try //Mozilla
				{
					return "/"+ss[index].src.match(/.*:\/\/[\.\w\d-]*\/(.*)Anastasis\.js/i)[1];
				}catch(e) //IE
				{
					try
					{
						var url=ss[index].src.match(/(.*)Anastasis\.js/i)[1];
						//L'url potrebbe essere relativo, dobbiamo farlo assoluto
						if(url && url.match(/^\.\./))
						{
							var dove=window.location.toString();
							dove=dove=dove.match(/(.*)\/.*/);
							if(dove &&  dove[1])
								url=dove[1]+"/"+url;
						}
						return url;
					}catch(e){alert("Impossibile inizializzare base_url"); return "";}
				}
			}
		}
	}

	var identifyBrowser=function(anastasis)
	{
		anastasis.is_ie=$.browser.msie;
		
		if(anastasis.is_ie)
		{
			var sBrowserVersion = $.browser.version;
			if ( sBrowserVersion >= 5.5 ) anastasis.is_ie=true;
			if ( sBrowserVersion >= 6 && sBrowserVersion < 7) anastasis.is_ie6=true;
			if ( sBrowserVersion >= 7 && sBrowserVersion < 8) anastasis.is_ie7=true;
			if ( sBrowserVersion >= 8 && sBrowserVersion < 9) anastasis.is_ie8=true;
			if ( sBrowserVersion >= 9 && sBrowserVersion < 10) anastasis.is_ie9=true;
			if ( sBrowserVersion >= 10 ) anastasis.is_ie10=true;
		}		
		
		anastasis.is_gecko=$.browser.mozilla;
		anastasis.is_mozilla=$.browser.mozilla;
		
		anastasis.is_webkit=$.browser.webkit;
		
		anastasis.is_opera=$.browser.opera;		
	}

	//-------------variabili------------------//

	this.is_ie=false;
	this.is_ie6=false;
	this.is_ie7=false;
	this.is_ie8=false;
	this.is_ie9=false;
	this.is_ie10=false;
	
	this.is_gecko=false;
	this.is_mozilla=false;
	
	this.is_webkit=false;
	
	this.is_opera=false;
	
	identifyBrowser(this);
	this.base_url=getBaseUrl();
	if(window.location.href.match(/(https?:\/\/[^\/]+\/).*/)) this.domain=window.location.href.match(/(https?:\/\/[^\/]+\/).*/)[1];
	if(window.location.href.match(/https?:\/\/[^\/]+\/[^\/]+\/.*/)) this.servletContext=window.location.href.match(/https?:\/\/[^\/]+\/([^\/]+)\/.*/)[1];
	this.systemScripts=[]; //new Array()
	
	this.ajax=new Anastasis.Ajax();
	this.utils=new Anastasis.Utils();
	this.logger=new Anastasis.Logger();
}


/**
 * Carica uno script; a caricamento avvenuto esegue l'azione passata onload.
 * @param {String} 		src 	l'indirizzo dello script (o solo il nome se e' di sistema - cioe' nella stessa cartella di questo js)
 * @param {function}	onload 	una funzione di callback
 * @param {boolean}		system 	specifica se e' uno script di sistema oppure no
 * @memberOf Anastasis
 */
 //Problema: IE non supporta il parametro onload degli script --> bisogna caricare gli script con Ajax!
Anastasis.prototype.loadScript=function(src,onload,system)
{

	if(system)
	{
		//Se e' di sistema, se c'e' gia' non la carica
		var className=src.split("/");
		if(typeof(eval("Anastasis."+className[className.length-1]))=="function") return;

		src=this.base_url+src+".js";
	}

	/*
	var head = document.getElementsByTagName("head")[0];
	var script = document.createElement("script");
	script.type = "text/javascript";
	script.src = src;
	script.onload = onload;
	head.appendChild(script);
	*/

	var onReceived=function(text)
	{
		try{eval(text);} catch(e){alert("Anastasis.loadScript-onReceived\n"+src+"\n"+e+"\n"+text);}
		if (typeof onload == "function") onload();
	}

	this.ajax.send(new Object(),src,"GET",false,true,onReceived);

}

/**
 * Carica in sequenza una lista di script, dopodiche' chiama una funzione di callback(se passata).
 * @param {Array} 		scripts 	la lista degli scripts da caricare (["script1","script2"])
 * @param {function} 	callback 	la funzione da chiamare alla fine del caricamento di tutti gli script
 * @param {boolean} 	specifica 	se e' gli script sono sistema oppure no (se sono di sistema basta mettere il nome(senza neanche '.js'), altrimenti serve il path completo)
 */
Anastasis.prototype.loadScriptSequence=function(scripts,callback,system)
{
	var me=this;
	if(scripts.length==1)
		this.loadScript(scripts[0],callback,system);
	else
	{
		var next=[];
		for(var index=1; index<scripts.length; index++)
		{
			next[index-1]=scripts[index];
		}
		this.loadScript(scripts[0],function(){me.loadScriptSequence(next,callback,system);},system);
	}
}

/**
 * Carica in maniera sincrona uno script.
 * @param {String} src l'indirizzo dello script (o solo il nome se e' di sistema - cioe' nella stessa cartella di questo js)
 * @param {Boolean} system specifica se e' uno script di sistema oppure no
 * @param {function} una funzione, che deve ritornare un boolean, per controllare se esiste gia': in quel caso non deve essere caricato
 */
Anastasis.prototype.syncLoadScript=function(src,system,existenceConditionFunction)
{
	if(system)
	{
		//Se e' di sistema, se c'e' gia' non la carica
		var className=src.split("/");
		if(typeof(eval("Anastasis."+className[className.length-1]))=="function") return;

		src=this.base_url+src+".js";
	}
	else if(existenceConditionFunction)
	{
		if(existenceConditionFunction()) return;
	}

	text=this.ajax.send(new Object(),src,"GET",false,false);
	eval(text);

}

/**
 * Carica un css e lo applica alla pagina.
 * @param {String} url l'url del css
 */
Anastasis.prototype.loadStyle = function(url)
{
	var head=document.getElementsByTagName("head")[0];
	var link = document.createElement("link");
	link.type = "text/css";
	link.rel="stylesheet";
	link.href=url;
	head.appendChild(link);
}

//-------------------------------------------------//
/**
 * Classe Ajax.
 * Gestisce la comunicazione Ajax.
 * @constructor
 * @class Anastasis.Ajax
 */
Anastasis.Ajax=function ()
{
	this.iframe=null;
	this.iframeActionQueue=new Array();
	this.iframePostQueue=new Array();
	this.iframeWaitingForReply=false;
}

//------------GLOBAL FUNCTIONS-------------------------------//

/**
 * Implementazione della funzione selectSingleNode per un oggetto XMLElement.
 * Preso in input l'oggetto xml e l'xpath di un nodo, se c'è lo restituisce, altrimenti restituisce null.
 * @static
 * @param {XMLElement} xmlElement l'oggetto xml all'interno del quale si vuole cercare il nodo
 * @param {String} il path del nodo da cercare
 * @return il nodo cercato
 * @type XMLElement
 */
Anastasis.Ajax.selectSingleNode=function(xmlElement,node)
{
	node=node.split(/\//);
	var currentElement=xmlElement;
	for(var i=0;i<node.length;i++)
	{
		if(!currentElement) break;
		var child=currentElement.firstChild;
		if(!child) 	currentElement=null;
		while(child)
		{
			if(child.tagName && child.tagName==node[i])
			{
				currentElement=child;
				break;
			}
			else
			{
				currentElement=null;
			}
			child=child.nextSibling;
		}
	}
	return currentElement;

}

/**
 * Preso un xmlElement, ne restituisce il testo (o null se non è una "foglia")
 * @static
 * @param {XMLElement} xmlElement l'oggetto xml da cui si vuole estrarre il testo
 * @return il testo
 * @type String
 */
Anastasis.Ajax.getText=function(xmlElement)
{
	if(xmlElement.textContent)			//Mozilla
		return xmlElement.textContent;
	if(xmlElement.text) 				//IE
		return xmlElement.text;
	else if(xmlElement.firstChild && xmlElement.firstChild.nodeType==4)
	{
		if(xmlElement.firstChild.textContent)			//Mozilla
			return xmlElement.firstChild.textContent;
		if(xmlElement.firstChild.text)
			return xmlElement.firstChild.text;		//IE
	}
	else if(xmlElement.firstChild && xmlElement.firstChild.nodeType==8)	//Problema di Mozilla che vede CDATA come commenti
	{
		if(xmlElement.firstChild.textContent)			//Mozilla
			return xmlElement.firstChild.textContent.replace(/^\[CDATA\[/,'').replace(/\]\]$/,'');
	}
	return null;
}




//---------------------------METODI-PUBBLICI---------------------------//
/**
* Invio sincrono o asincrono di dati via XMLHttp; i primi due parametri sono obbligatori, gli altri opzionali.<br />
* Se e' sincrono, restituisce l'output della pagina receiver sotto forma di testo
* @param {Object} 	param 		param[id]=contenuto, dove id e' l'id che avra' nella queryString
* @param {String} 	receiver 	l'indirizzo a cui mandarlo
* @param {String} 	method 		se non specificato e' POST
* @param {boolean} 	xmldoc 		se true ritona un Document Xml, altrimenti una semplice stringa
* @param {boolean} 	async 		asincrono? se false non ritorna nulla!
* @param {function} callback 	se il metodo e' asincrono, la funzione che gestisce l'arrivo della risposta (opzionale)
* @return se la chiamata è sincrona, restituisce il messaggio di risposta, altrimenti lo passa alla funzione di callback. Se xmldoc e' true, restituisce un XMLElement, altrimenti una stringa
* @type XMLElement|String
*/
Anastasis.Ajax.prototype.send=function (param,receiver,method,xmldoc,async,callback)
{
  var reply="",result="", dataType="text";;
  if(method!="GET" && method!="POST") { method="POST"; }
  if(xmldoc) { dataType="xml"; } else {dataType="text";}
  
  try
  {
	  if(async)
	  {
		  reply=$.ajax({
	          url: receiver,
	          async: true,
	          data: param,
	          type: method,
	          cache: false,
	          contentType: "application/x-www-form-urlencoded; charset=UTF-8",
	          success: function(res){if(typeof(callback)=="function") { callback(res); }},
	          error: function (jqXHR, textStatus, errorThrown) { this.errore("send",textStatus); }
	          });
	  }
	  else
	  {	  	  
		  reply=$.ajax({
	          url: receiver,
	          async: false,
	          data: param,
	          type: method,
	          cache: false,
	          contentType: "application/x-www-form-urlencoded; charset=UTF-8"
	          });
		  
		  if(xmldoc) 
		  {
			  try
			  {
				  result=reply.responseXml;
			  } catch(e)
			  {
				 this.errore("send","Si richiedeva una risposta XML ma il Content-Type dichiarato non corrisponde.");
  				//prova comunque a parserizzarla...
				 result=Anastasis.Utils.parseXML(reply.responseText);
			  }
		  }
		  else 
		  {
			  result=reply.responseText; 
		  }
		  
		  return result;
	  }
  }catch(err){this.errore("send",err);}	  
  /*
  try
  {
    var xmlHttp=this.getSender();

	//Apre la "connessione"
    xmlHttp.open(method,receiver,async);    //(method, url, async)
    if(method=="POST")
    	xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=ISO-8859-1");
    else
    	xmlHttp.setRequestHeader("Content-Type","text/plain; charset=ISO-8859-1");


    //Compone la richiesta da inviare
    var qs="";
    var tmp;
    var primo=false;
    for(var par in param)
    {
      if(!primo) primo=true; else qs+="&";
      tmp=encodeURIComponent(param[par]); //Encode con tutti i %
      tmp=tmp.replace(/&/g,"%26");   //Sostituisce gli &, perche' encodeURI non lo fa
      qs+=par+"="+tmp; //Attenzione alla sostituzione degli &!!!
    }

    if(async)
    {
    	var ajax=this;
    	if(xmldoc)
	    	xmlHttp.onreadystatechange=function()
	    		{
	    			if(xmlHttp.readyState==4 && callback)
	    				callback(xmlHttp.responseXML);
	    		}
	    else
	    	xmlHttp.onreadystatechange=function()
	    		{
	    			if(xmlHttp.readyState==4 && callback)
	    				callback(xmlHttp.responseText);
	    		}
    }

    xmlHttp.send(qs);

    if(!async)
    {
	    var response;
	    if(xmldoc)
	    	{
	    		var contentType=xmlHttp.getResponseHeader("Content-Type");
	    		//contentType=contentType.toLowerCase();
	    		if(!(contentType && (contentType.match(/application\/xml/) || contentType.match(/text\/xml/))))
	    			{
	    				this.errore("send","Si richiedeva una risposta XML ma il Content-Type dichiarato non corrisponde.\nContent-type: "+contentType+"\nText: "+xmlHttp.responseText);
	    				//prova comunque a parserizzarla...
	    				response=Anastasis.Utils.parseXML(xmlHttp.responseText);
	    			}
	    		else
		    		response = xmlHttp.responseXML;
	    	}
	    else
	    	response = xmlHttp.responseText;
	    return response;
    }

  }catch(err){this.errore("send",err);}
  */
}

/**
 * Funzione che invia un form in background. 27/06/2011: jquerizzato.
 * Quando riceve la risposta, la passa alla funzione di callback che gli viene passata.<br />
 * NB: l'oggetto passato alla funzione di callback, nel caso che la risposta sia xml,
 * 		e'un oggetto XMLElement gia' parserizzato. In tutti gli altri casi e' una semplice stringa.
 *
 * @param {String} 		id_form 	l'id del form da inviare
 * @param {function} 	callback 	la funzione di callback chiamata passandole la risposta come primo parametro
 * @return nulla, passa la risposta alla funzione di callback
 */

Anastasis.Ajax.prototype.sendForm=function(id_form,callback)
{
	var $form=$(document.getElementById(id_form));
	var address=$form.attr("action");
	var method=$form.attr("method");
	if(!method) method="POST";
	
	var onsubmit_ok=true;
	
	var onsubmit = $form.attr("onsubmit");
	if(onsubmit)
	{
		try
		{
			onsubmit_ok=(new Function(onsubmit))();
			if(typeof(onsubmit_ok)=="undefined") onsubmit_ok=true;
		} catch(e){ onsubmit_ok=true; }
	}
	
	if(onsubmit_ok)
	{
		var dati=$form.serialize();
		reply=$.ajax({
	           url: address,
	           async: false,
	           data: dati,
	           type: method,
	           cache: false
	           }).responseText;	
		if(typeof(callback=="function")) { callback(reply); }
	}
	else
	{
		try{ console.info("Form validation failed.");} catch(e){}
	}
}

/**
 * Funzione che invia un form con uno o più campi file in background. Non ancora jquerizzato.
 * Quando riceve la risposta, la passa alla funzione di callback che gli viene passata.<br />
 * NB: l'oggetto passato alla funzione di callback, nel caso che la risposta sia xml,
 * 		e'un oggetto XMLElement gia' parserizzato. In tutti gli altri casi e' una semplice stringa.
 *
 * @param {String} 		id_form 	l'id del form da inviare
 * @param {function} 	callback 	la funzione di callback chiamata passandole la risposta come primo parametro
 * @return nulla, passa la risposta alla funzione di callback
 */

Anastasis.Ajax.prototype.sendFormWithFile=function(id_form,callback)
{
	var form=document.getElementById(id_form);
	this.createIFrame();
	form.target=this.iframe.name;
	this.iframeActionQueue.push(function(rep){callback(rep);});
	this.doSendForm(form);
}
//---------------------------METODI-PRIVATI---------------------------//

/**
 * Crea un nuov oggetto xmlHTTP (va rifatto ogni volta)
 * @private
 */
Anastasis.Ajax.prototype.getSender=function ()
{
	var xmlHttp=null;

	if(window.XMLHttpRequest)//IE 7, Firefox
		try
		{
			xmlHttp=new XMLHttpRequest();
		}catch(e){this.errore("resetSender",e);}
	else //IE 6
	{
		try { xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");}         //IE nuovi
	    catch (e)
	    { try { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); }    //IE vecchi
	      catch (E){this.errore("resetSender",e+"\n"+E);}
	    }
	}

	return xmlHttp;
}

/**
 * @private
 */
Anastasis.Ajax.prototype.errore=function(metodo,err)
{
	alert("[Ajax."+metodo+"]\n"+err);
}

/**
 * @private
 */
Anastasis.Ajax.prototype.createIFrame=function()
{
		if(this.iframe){ return; }

		var iframe = null;

		var ifrstr = '<iframe name="anastasis_ajax_iframe" src="'+anastasis.base_url+'blank_src.html" onload="parent.anastasis.ajax.onloadedIFrame();">';
		var div=document.createElement("div");
		div.innerHTML=ifrstr;
		iframe = div.firstChild;

		this.iframe = iframe;

		iframe.style.position = "absolute";
		iframe.style.left = iframe.style.top = "-1000px";
		iframe.style.height = iframe.style.width = "0px";

		document.body.appendChild(iframe);
}

/**
 * @private
 */
Anastasis.Ajax.prototype.doSendForm=function(form)
{
	if(this.iframeWaitingForReply)
	{
		this.iframePostQueue.push(form);
	}
	else
	{
		this.iframeWaitingForReply=true;
		form.submit();
	}
}

/**
 * @private
 */
Anastasis.Ajax.prototype.onloadedIFrame=function()
{
	var rep="";

	if(anastasis.is_ie && this.iframe.contentWindow.document.XMLDocument)			//E' un doc XML e siamo in IE
	{
		rep=this.iframe.contentWindow.document.XMLDocument;
	}
	else if(this.iframe.contentWindow.document.firstChild && this.iframe.contentWindow.document.firstChild.nodeType==1)	//E' un doc XML 
	{
		rep=this.iframe.contentWindow.document.firstChild;
	}
	else
	{
		try
		{
				rep=this.iframe.contentWindow.document.body.innerHTML;
		}	catch(e){}
	}


	if(rep.match && rep.match("BLANK_ANASTASIS_IFRAME")) 
	{
		return;	//primo caricamento dell'iframe (anche se non avviene sempre)
	}

	try
	{
		var callback=this.iframeActionQueue.shift();
		callback(rep);
	}
	catch(e){this.errore("onloadedIframe",e.toString());}


	//Ora vediamo se c'erano altri form in attesa di essere inviati e li inviamo
	this.iframeWaitingForReply=false;
	var next=this.iframePostQueue.shift();
	if(next)
	{
		this.doSendForm(next);
	}
}

//------------CLASS XMESSAGE--------------------------//
/**
 * Costruttore degli XMessaggi: non va mai usato, si costruiscono con la funzione buildXMessage
 * @class 	Wrapper per XMessage in X-serena. La sintassi di un XMessage e':<br /><code> &lt;serena&gt;&lt;service&gt;&lt;_system_message&gt;...&lt;/_system_message&gt;&lt;/service&gt;&lt;/serena&gt;</code><br /> All'interno ci deve stare almeno il tag &lt;type&gt; e, se il type e' "error", anche il tag &lt;error&gt;
 * @property {XMLElement} message la root del messaggio
 * @property {String} type il tipo del messaggio (contentuto anche in /type)
 * @property {String} error l'eventuale messaggio di errore, se il type e' "error"
 */
 //Per chi sta leggendo la documentazione da qua e non dall'html: <serena><service><_system_message>...</_system_message></service></serena>
Anastasis.XMessage=function()
{
	this.message=null;
	this.type="";
	this.error="";
}

	//----------GLOBAL FUNCTIONS-----------------------//

/**
 * Funzione statica che ritorna in XMessaggio a partire ad un element XML.
 * @param {XMLElement} un elemento xml scritto in x-serena rispettando la sintassi di un xmessage.
 */
Anastasis.XMessage.buildXMessage=function(xmldoc)
{
	msg=new Anastasis.XMessage();

/*
	alert("QUA");
	var aa=Anastasis.Ajax.selectSingleNode(xmldoc,"serena");
	alert("Node type: "+aa.nodeType);
	alert("TAGNAME: "+aa.tagName);
	return;
*/
	if(xmldoc.tagName!="serena")
	{
		if(xmldoc.tagName && xmldoc.tagName.toLowerCase()=="html")
		{
			msg.type="error";
			msg.error="Il content-type della risposta ricevuta e' HTML anizhe' XML\nOppure il content-type e' corretto ma il contenuto e' HTML.";
			return msg;
		}
		xmldoc=Anastasis.Ajax.selectSingleNode(xmldoc,"serena");
		if(!xmldoc)
		{
			msg.type="error";
			msg.error="XML ricevuto non inizia con tag serena";
			return msg;
		}
	}
	if(!Anastasis.Ajax.selectSingleNode(xmldoc,"service"))
	{
		msg.type="error";
		msg.error="XML ricevuto non contiene serena/service";
		return msg;
	}

	msg.message=Anastasis.Ajax.selectSingleNode(xmldoc,"service/_system_message");
	if(!msg.message)
	{
		msg.type="error";
		msg.error="XML ricevuto non contiene service/_system_message";
		return msg;
	}

	msg.type=Anastasis.Ajax.selectSingleNode(msg.message,"type");
	if(msg.type) msg.type=Anastasis.Ajax.getText(msg.type);

	if(msg.type=="error" && Anastasis.Ajax.selectSingleNode(msg.message,"error"))
		msg.error=Anastasis.Ajax.getText(Anastasis.Ajax.selectSingleNode(msg.message,"error"));

	return msg;
}

	//-----------PUBLIC FUNCTIONS----------------------//

/**
 * Restituisce il testo contenuto nell'elemento richiesto
 * @param {String} element il nome del nodo di cui si vuole il contenuto
 * @return il testo contenuto nell'elemento richiesto
 * @type String
 */
Anastasis.XMessage.prototype.getContentOf=function(element)
{
	var el=Anastasis.Ajax.selectSingleNode(this.message,element);
	if(el) return Anastasis.Ajax.getText(el);
	else return null;
}

/**
 * Restituisce il l'element richiesto
 * @param {String} element il nome del nodo
 * @return l'elemento richiesto
 * @type XMLElement
 */
Anastasis.XMessage.prototype.selectSingleNode=function(element)
{
	var el=Anastasis.Ajax.selectSingleNode(this.message,element);
	return el;
}

/**
 * True se il messaggio è un messaggio di errore. In questo caso sara' disponibile il campo <code>error</code>.
 * @return true se il messaggio è un messaggio di errore
 * @type boolean
 */
Anastasis.XMessage.prototype.isErrorMessage=function()
{
	return (this.type=="error");
}

/**
 * True se il messaggio è un messaggio di di tipo "ok".
 * @return true se il messaggio è un messaggio di ok
 * @type boolean
 */
Anastasis.XMessage.prototype.isOkMessage=function()
{
	return (this.type=="ok");
}


//------------CLASS UTILS-------------------------//

/**
 * @class Una serie di strumenti utili.
 */
Anastasis.Utils=function(){};

	//----------GLOBAL FUNCTIONS-----------------------//
//Queste funzioni possono essere chiamate ovunque, basta aver caricato questo js.
/**
 * Trim di stringhe
 * @param {String} stringa la stringa
 * @return la stringa senza spazi prima e dopo
 * @type {String}
 */
Anastasis.Utils.trim = function(stringa)
{
	stringa = stringa.replace(/^\s+/, '');
	return stringa.replace(/\s+$/, '');
};

/**
 * Da una stringa restituisce un oggetto DOM XML.
 * @param {String} xml una stringa con un xml ben formato
 * @return un elemento xml ottenuto parserizzando la stringa
 * @type XMLElement
 * @throws una stringa con il messaggio di errore
 */
Anastasis.Utils.parseXML=function(xml)
{
	var xmldoc;
	try
	{
	  	if(window.DOMParser)  //Mozilla
		{
			var parser=new DOMParser();
			xmldoc=parser.parseFromString(xml,"text/xml");
		}
		else  //IE
	  	{
			xmldoc=new ActiveXObject("Microsoft.XMLDOM");		//new ActiveXObject("Msxml2.DOMDocument.3.0");
		  	xmldoc.async="false";
		  	xmldoc.loadXML(xml);
	  	}
	}catch(e) { throw "parseXML - Errore nel parsing dell'xml.\n"+e; }

  if(!(xmldoc.documentElement))
  {
  	if (xml) throw "parseXML - Errore nel parsing dell'xml.\n"+xml;
  	else throw "parseXml - Tentativo di parseXML() su variabile null";
  	return null;
  }

  return xmldoc;
}

/**
 * Crea un cookie descritto dai parametri passati.
 * @param {String} name il nome del cookie
 * @param {String} value il valore del cookie
 * @param {String} days il numero di giorni di validita' del cookie
 */
Anastasis.Utils.creaCookie=function(name,value,days)
{
  if (days)
  {
    var date = new Date();
    date.setTime(date.getTime()+(days*24*60*60*1000));
    var expires = "; expires="+date.toGMTString();
  }
  else expires = "";
  document.cookie = name+"="+value+expires+"; path=/";
}

/**
 * Legge un cookie e ne riporta il valore.
 * @param {String} name il nome del cookie
 * @return il valore del cookie oppure null
 * @type String
 */
Anastasis.Utils.leggiCookie=function(name)
{
  var nameEQ = name + "=";
  var ca = document.cookie.split(';');
  for(var i=0;i < ca.length;i++) {
    var c = ca[i];
    while (c.charAt(0)==' ') c = c.substring(1,c.length);
    if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
  }
  return null;
}

/**
 * Esegue l'encoding html di un testo, sostituendo solo i quattro simboli piu' ostici: &amp; &lt; &gt; &quot;
 */
Anastasis.Utils.htmlEncode = function(str)
{
	str = str.replace(/&/ig, "&amp;");
	str = str.replace(/</ig, "&lt;");
	str = str.replace(/>/ig, "&gt;");
	str = str.replace(/\x22/ig, "&quot;");
	return str;
};

	//-----------PUBLIC FUNCTIONS----------------------//
// Questi metodi sottindendono l'allocazione di un oggetto Utils e anche di uno Anastasis

/**
 * @private
 */
Anastasis.Utils.prototype.errore=function(metodo,err)
{
	alert("[Utils."+metodo+"]\n"+err);
}

/**
 * Ferma la propagazione dell'evento ev.
 * @param {Object - event} ev l'evento da stoppare
 */
Anastasis.Utils.prototype.stopEvent = function(ev)
{
	if(anastasis.is_ie) {
		ev.cancelBubble = true;
		ev.returnValue = false;
	} else {
		ev.preventDefault();
		ev.stopPropagation();
	}
};

/**
 * Registra la funziona passata come handler per l'evento evname sull'elemento el.<br />
 * Se questa funzione è chiamata piu' volte per lo stesso evento sullo stesso oggetto,
 * le funzioni passate sono eseguite nell'ordite in cui sono state registrate.<br />
 * @param {HTMLElement} el l'elemento
 * @param {String} evname il nome dell'evento(senza il prefisso "on"
 * @param {function} func la funzione handler
 */
 // Registers the function as handler for the event evname on the element el.<br />
 // If this function is called more than one time for the same element and the same event,
 // the function are executed one after the other in the registering order.
Anastasis.Utils.prototype.addEvent = function(el, evname, func)
{
	if(!el.document && !el.nodeType) el=document.getElementById(el);
	if (anastasis.is_ie)
	{
		el.attachEvent("on" + evname, func);
	}
	else
	{
		el.addEventListener(evname, func, false);
	}
};

/**
 * Rimuove una specifica funzione dall'handler dell'evento ev sull'elemento el.<br />
 * La funzione non puo' essere anonima.
 * @param {HTMLElement} el l'elemento
 * @param {String} evname il nome dell'evento(senza il prefisso "on"
 * @param {function} func la funzione da rimuovere, che deve essere esattamente quella aggiunta
 */
 //Removes a specific function as handler for the event evname on the element el
Anastasis.Utils.prototype.removeEvent = function(el, evname, func)
{
	if(!el.document && !el.nodeType) el=document.getElementById(el);
	if (anastasis.is_ie)
	{
		el.detachEvent("on" + evname, func);
	}
	else
	{
		el.removeEventListener(evname, func, false);
	}
};

/**
 * Rimuove una classe da un elemento. Se non c'e' non succede nulla.
 * @param {HTMLElement} el l'elemento html
 * @param {String} className la classe da eliminare
 */
 //Removes the class className from the element el
Anastasis.Utils.prototype.removeClass = function(el, className)
{
	if (!(el && el.className && el.className.match(className)))
	{
		return;
	}
	var cls = el.className.split(" ");
	var ar = new Array();
	for (var i = cls.length; i > 0;)
	{
		if (cls[--i] != className)
		{
			ar[ar.length] = cls[i];
		}
	}
	el.className = ar.join(" ");
};

/**
 * @param {Object} event l'evento che generato dalla pressione di un tasto
 * @param {integer} charCode il codice del tasto da monitorare
 * @param {boolean} propagation se l'esecuzione deve continuare dopo l'esecuzione dell'azione
 * @param {Function} action l'azione da eseguirsi nel caso in cui l'evento sia generato da charCode
 */
Anastasis.Utils.prototype.checkKeyPressed = function(event,charCode,propagation,action)
{
	var keynum;

	if(window.event) // IE
  	{
  		keynum = event.keyCode;
  	}
	else if(event.which) // Netscape/Firefox/Opera
	{
		keynum = event.which;
  	}

	if (keynum==charCode)
	{
		if (action) action();
		return propagation;
	}
}

/**
 * Aggiunge una classe ad un elemento html.
 * @param {HTMLElement} el l'elemento html
 * @param {String} className la classe da aggiugere (aggiunge uno spazio e la accoda alle preesistenti)
 */
 //Adds the class className to the element el
Anastasis.Utils.prototype.addClass = function(el, className)
{
	this.removeClass(el, className);
	el.className += " " + className;
};

/**
 * Ritorna l'HTMLElement che ha generato l'evento. Serve perche' il mdo di richiederlo cambia in ie e firefox.
 */
Anastasis.Utils.prototype.getEventSource=function(event)
{
	if(anastasis.is_ie)
		return event.srcElement;
	else
		return event.target;
}

//--------------------------------------------------------------------//

/**
 * Internationalization class.
 * It must be initialized with an object with the following syntax:
 * object_name=
 * {
 * 	"text" : "translation",
 * 	"text" : "translation"
 * }
 * @param strings Object; the strings and their tranlsations
 * @class
 * @constructor
 */
Anastasis.I18N=function(strings)
{
	this.strings=strings;
}

Anastasis.I18N.prototype.translate=function(string)
{
	string=string.replace(/^\s*/,'');
	string=string.replace(/\s*$/,'');
	var punteggiatura="";
	if(string.match(/[:\s*.]$/))
	{
		match=string.match(/(.*)([:\s*.])$/);
		string=match[1];
		punteggiatura=match[2];
	}

	if(this.strings && this.strings[string])
		return this.strings[string]+punteggiatura;
	else
		return string+punteggiatura;
}

Anastasis.I18N.prototype.add=function(term,translation)
{
	this.strings[term]=translation;
}

Anastasis.Utils.translatePage=function(i18n)
{
	if(!i18n) return;

	tags_to_translate=["div","span","p","option","td","button","legend","label"];
	//-----------------------------------------------------------------------------------------------------//
	function toBeTranslated(tag)
	{
		for(var i in tags_to_translate)
		{
			if(tag==tags_to_translate[i]) return true;
		}
		return false;
	}

	function recTranslate(root)
	{
		if(!root) return;
		if(root.nodeType==1 || root.nodeType==11)
	  	{
	    	var i;
	    	var root_tag = (root.nodeType == 1) ? root.tagName.toLowerCase() : '';
	    	if(toBeTranslated(root_tag))
	      		if (root.firstChild && root.firstChild.data)
	        	{
	  				root.firstChild.data = i18n.translate(root.firstChild.data);
				 }
			if(root.title) root.title=i18n.translate(root.title);
	    	for (i=root.firstChild; i; i = i.nextSibling) recTranslate(i);
	  	}
	}

	document.title = i18n.translate(document.title);
	recTranslate(document.body);
}

//---------------------CLASS--DIALOG-------------------------------------------//

/**
 * @class La classe per lanciare popups.
 * @private
 */
Anastasis.Dialog=function(url, action, init)
{
	var me=this;
	
	this.finestra = null;
	
	//Viene passato a tutti i popup per avere le coordinate per caricare popup.js e popup_style.css
	//if(!init) init=new Object();
	//if(_editor_url) init["editor_url"]=_editor_url;		
		
	this.argument = init;
	this.action=action;		
	this.url=url;
}

/**
 * @private
 */
Anastasis.Dialog.prototype.show=function() 
{
	var menubar="no";
	if(this.argument && this.argument["menubar"]) menubar="yes";
	
	var scrollbars="no";
	if(this.argument && this.argument["scrollbars"]) scrollbars="yes";
	
	if(anastasis.is_ie) this.finestra=window.open("","_blank",
			      "toolbar=no,menubar="+menubar+",personalbar=no,width=10,height=10,location=no," +
			      "scrollbars="+scrollbars+",resizable=yes,modal=yes,dependable=yes");	
	else               this.finestra=window.open("","dialog "+this.url,
			      "toolbar=no,menubar="+menubar+",personalbar=no,width=10,height=10," +
			      "scrollbars="+scrollbars+",resizable=yes,modal=yes,dependable=yes");		
	
		
	
	var me=this;		
	
	//Sarebbe l'ideale, ma in IE non va...
	//anastasis.utils.addEvent(me.finestra,"load",function(){me.finestra.anastasis.syncLoadScript("Popup",true); me.finestra.popup.init();});			
	
	me.finestra.location=this.url;
}

/**
 * @private
 */
Anastasis.Dialog.prototype.restitute = function (param) 
{    			
	if (this.action) 
		return this.action(param);
	
	return null;	
};





//----------------FUNZIONI A DISPOSIZIONE DELL'OGGETTO ANASTASIS--------------//
/**
 * Apre un popup passandogli dei parametri e una funzione di callback.<br />
 * NB: si puo' aprire una sola finsetra di popup alla volta (le precedenti vengono chiuse). Se tentiamo di aprire un'altra finestra uguale alla preesistente,le diamo semplicemente il focus.
 * @param {String} url l'indirizzo della pagina da aprire nel popup
 * @param {function} action la funzione di callback chiamata alla chiusura della finestra; puo' prendere in input un Object con tutti i parametri ritornati
 * @param {Object} init un Object con tutti i parametri da passare alla finestra
 * @example  var param=new Object(); <br /> param["parametro"]="valore"; <br /> var action=function(returnParams){alert(returnParams["parametro_ritornato"]);}; <br /> anastasis.openDialog("http://url",action,param);
 */
Anastasis.prototype.openDialog=function(url, action, init)
{
	//Se tentiamo di aprire un'altra finestra diversa, chiudiamo la preestistente.
	//Se tentiamo di aprire un'altra finestra uguale alla preesistente,le diamo semplicemente il focus
	if(anastasis.current_dialog && anastasis.current_dialog.finestra && !anastasis.current_dialog.finestra.closed)
	{	
		if(url==anastasis.current_dialog.url)
		{
			anastasis.current_dialog.finestra.focus();
			return;
		}
		else
			anastasis.current_dialog.finestra.close();
	}
	anastasis.current_dialog=new Anastasis.Dialog(url, action, init);
	anastasis.current_dialog.show();
}

/**
 * Funzione che puo' usare la finestra di popup per ricevere i parametri con cui e' stata chiamata.
 * @private
 */
Anastasis.prototype.getDialogArguments=function()
{
	return window.opener.anastasis.current_dialog.argument;
}

/**
 * Funzione che deve usare il popup per ritornare i valori alla finestra chimante.
 * @private
 */
Anastasis.prototype.dialogReturn=function(param)
{
	return window.opener.anastasis.current_dialog.restitute(param);
}

//---------------------CLASS--LOGGER-------------------------------------------//
/**
 * @class La classe per eseguire il log.
 * @private
 */
Anastasis.Logger=function()
{
	this.enabled=false;
	this.console=null;
	this.virtual=false;
	this.handle=null;
	this.message=null;
	
	try{
		if(typeof(window.console)!=='undefined')
		{
			this.enabled=true;
			this.console=console;
		}
		else if(typeof(window.jQuery)!=='undefined')
		{
			var me=this;
			$(document).ready(function(){
					me.enabled=true;
					me.virtual=true;
					me.console=$("<div>");
					me.console.attr("id","anastasis_console");
					me.console.css("position","fixed");
					me.console.css("top","0px");
					me.console.css("left","0px");
					me.console.css("font-size","11px");
					
					me.board=$("<div>");
					me.board.css("display","none");
					me.board.css("background-color","#fff");
					me.console.append(me.board);
					
					me.handle=$("<div>");
					me.handle.html("x");
					me.handle.css("display","none");			
					me.console.append(me.handle);
					
					me.handle.click(function(){me.board.toggle();});
					
					$("body").append(me.console);
				});			
		}
	}catch(e){}
}

Anastasis.Logger.prototype.error=function(message,error)
{	
	if(this.enabled)
	{
		this.message=message;
		if(error && error.message) { this.message=this.message+" - "+error.message; }
		if(this.virtual)
		{
			this.virtualConsoleAppender("ERROR: "+this.message);
		}
		else
		{
			console.error(message,error);			
		}		
	}
}

Anastasis.Logger.prototype.warn=function(message,error)
{	
	if(this.enabled)
	{
		this.message=message;
		if(error && error.message) { this.message=this.message+" - "+error.message; }
		if(this.virtual)
		{
			this.virtualConsoleAppender("WARN: "+this.message);
		}
		else
		{
			console.warn(message,error);			
		}		
	}
}

Anastasis.Logger.prototype.info=function(message)
{	
	if(this.enabled)
	{
		this.message=message;
		if(this.virtual)
		{
			this.virtualConsoleAppender("INFO: "+this.message);
		}
		else
		{
			console.info(this.message);			
		}		
	}
}

Anastasis.Logger.prototype.debug=function(message)
{	
	if(this.enabled)
	{
		this.message=message;
		if(this.virtual)
		{
			this.virtualConsoleAppender("DEBUG: "+this.message);
		}
		else
		{
			console.debug(this.message);			
		}		
	}
}

Anastasis.Logger.prototype.virtualConsoleAppender=function(message)
{
	this.board.append(message+"<br />");
	this.handle.css("display","");
}


 //-----------------MANTENUTO PER RETROCOMPATIBILITA' -------------------------//

Anastasis.Utils.print=function(cosa)
{
	anastasis.syncLoadScript("serena/SerenaUtils",true);
	Anastasis.SerenaUtils.print(cosa);
}

//-----------------------------------------------------------------------------//

window.anastasis=new Anastasis();

