/**
 * Oggetto usat per effettuare chiamate AJAX (o semplici invocazioni a servlet)
 *
 * Come si usa: l'oggetto e' unico, ne deve esistere un'istanza sola.
 * Chi volesse invocare una servlet deve fornire un oggetto handler, che 
 * implementa i seguenti metodi:
 *         performingRequest(boolean performing): 
 *                segnala l'effettivo inizio e fine della richiesta (permette di attivare/disattivare messaggi di attesa etc...) 
 *         manageSuccessResponse(response): in caso di risposta con successo
 *                l'oggetto response e' una stringa se e' stata fatta una richiesta di tipo testuale, un elemento DOM in caso contrario    
 *         manageErrorResponse: in caso di fallimento (errore HTTP 40?)
 *
 * Deve essere presente un campo 'requestUrl' contenente l'URL della richiesta
 *  Handler puo' avere un campo 'synchronous' valorizzato a true per effettuare una invocazione sincrona  
 */
var MwAjaxUtil = new Object();  

// mappa delle richieste pendenti: array associativo url->richiesta
MwAjaxUtil.pendingRequests = new Array();

/*
 * Effettua una richiesta HTTP Get:
 * requestURL: l'URL della risorsa da richiedere
 * handler: vedi sopra
 * type:"xml" o "text": il tipo di risposta attesa: default to XML
 * Le richieste vengono eseguite in parallelo  
 */
MwAjaxUtil.performRequest = function(handler, type)
{
	var request = new Object();
	var key = handler.requestUrl;

// creco l'univocita' della chiave
	while (this.pendingRequests[key] != null)
	{
		key += "$";
	}
	
	request.downloader = this.newXMLDownloader();
	request.url = handler.requestUrl;
	request.handler = handler;
	request.isText = (type != null && type == "text");

	//applico un timestamp per disabilitare la cache degli url
	var notCachedUrl = request.url;
	notCachedUrl += (notCachedUrl.indexOf("?") == -1) ? "?" : "&";
	notCachedUrl += "timestamp=" + new Date().getTime();

	if (handler.synchronous == undefined || handler.synchronous == null || handler.synchronous != true) // la richiesta e' asincrona...
	{
		this.pendingRequests[key]=request;
	   	request.handler.performingRequest(true);
		request.downloader.onreadystatechange = this.stateChange;
		request.downloader.open("GET", notCachedUrl, true);
	    request.downloader.send(null);
    }
    else  // la richiesta e' sincrona
    {
    	while (request.downloader.readyState != 4)
    	{
    		request.downloader.open("GET", notCachedUrl, false);
    		request.downloader.send(null);
    	}

		MwAjaxUtil.examineResponse(request);
    }
}


/**
 * Nocciolo della gestione delle richieste:
 */
MwAjaxUtil.stateChange = function ()
{
		for(var index in MwAjaxUtil.pendingRequests)
		{
			var response = null;
			var request = MwAjaxUtil.pendingRequests[index];
			var downloader = request.downloader;

		    if (downloader.readyState != 4)
				continue;

	  		try
	  		{
		   	    // rimuovo la richiesta esaurita per evitare ricorsioni infinite
		   	    delete MwAjaxUtil.pendingRequests[index];
	  			response = MwAjaxUtil.examineResponse(request,index);
	  		}
	  		finally
		    {
		    	request.handler.performingRequest(false);
		   	}
		}
}

/**
 *	Tenta di parsare l'xml restituito dal downloader restituendo l'oggetto DOM
 *
 *  Safari:
 *    request.isText = false
 *    downloader.responseXML = null
 *    bisogna usare XMLDocument e fare il parsing della stringa xml
 *      
 *  Firefox:
 *    request.isText = false
 *    downloader.responseXML = Document
 *    si puo' usare il dom ritornato direttamente dal downloader
 *
 *  IE:
 *    request.isText = false
 *    downloader.responseXML.documentElement = null
 *    bisogna passare dagli activeX per parsare il dom
 */
MwAjaxUtil.parseXML = function ( downloader)
{
	var response = null;

    try
    {
		//Questa roba va solo con explorer
		var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
					
		xmlDoc.async="false";			    
		xmlDoc.loadXML(downloader.responseText);
		response = xmlDoc.documentElement;		              
	}
	catch(e)
	{
		//Questo invece va bene con firefox
        try
        {
    		response = downloader.responseXML.documentElement;
		}
		catch (e)
		{
			//questo funziona con safari e forse anche col resto del mondo
	        try
	        {
				response = new DOMParser().parseFromString(downloader.responseText, "text/xml").firstChild;
			}
			catch (e)
			{
				e.message = downloader.responseText;
				throw e;
			}
		}
    }

	//in qualche modo ho beccato la risposta
	return response;    
}

MwAjaxUtil.examineResponse = function ( request)
{
	var response = null;
	var downloader = request.downloader;

	try
    {
        if (downloader.status == 200)
        {
        	if (request.isText)
	        	response = downloader.responseText;
			else
	        	response = MwAjaxUtil.parseXML(downloader);
	        
			request.handler.manageSuccessResponse(response);
        }
        else
        {
        	//non e' arrivato un 200. e' un errore
            request.handler.manageErrorResponse();
        }    
	}
    catch(e)
    {
    	alert("Non e' stato possibile interpretare la risposta:\n" + e.message);
    }
}

/**
 * Funzione che ritorna un XML Downloader pronto all'uso
 */ 
MwAjaxUtil.newXMLDownloader = function()
{
	var downloader = null;

    if (window.XMLHttpRequest)
    { // Mozilla, Safari,...
    	downloader = new XMLHttpRequest();
    }
    else if (window.ActiveXObject) 
    { // IE
    	try 
    	{
        	downloader = new ActiveXObject("Msxml2.XMLHTTP.3.0");
        }
        catch (e)
        {
        	try 
        	{
            	downloader = new ActiveXObject("Microsoft.XMLHTTP");
            }
            catch (e)
            {
			    alert('Impossibile creare una istanza XMLHTTP');
            }
        }
    }
    else
	    alert('Impossibile creare una istanza XMLHTTP per questo browser');

	return downloader;
}


/**
 * Rappresentazione in javascript dell'albero DOM: ogni elemento ha MWName (nome dell'elemento) e/o MWText (valore del testo contenuto).
 
 On oggetto complesso di nome 'pippo' puo' essere acceduto come obj.pippo o obj.pippo[0];
 */
MwAjaxUtil.parseDOM = function (node)
{
	if (node == null)
		return null;

	var ret = new Object();

	ret.MWname = node.nodeName;
	
	if (node.nodeType == 1) // se ho un elemento ciclo sugli attributi
	{
		for(var i = 0;  i < node.attributes.length; i++)
		{
				var attribute =  node.attributes[i];
				ret[attribute.nodeName] = attribute.nodeValue;
		}
	}
	
	
	for(var t = 0; t < node.childNodes.length; t++)
	{
		var child = node.childNodes[t];
		
		switch (child.nodeType)
		{
			case 3: // text
				ret.MWtext = child.nodeValue;
				break;
			case 1: // element
				// ottengo l'elemento figlio
				var temp = MwAjaxUtil.parseDOM(child);
				var others = ret["_" + temp.MWname];  // mi aspetto un array
				// se non ho altri figli con lo stesso nome, aggiungo il figlio, chiamandolo _nome e creo l'array
				if (others == undefined || others == null)
				{
					others = new Array();
					others[0] = temp ; // faccio cosi' perche' in questo modo ho sempre un array!
					ret[temp.MWname] = temp;
					ret["_" + temp.MWname] = others;					
				} 	
				else
				{
					// aggiungo un elemento
					others.push(temp);
				}
				break;
		}
	}
	
	return ret;
}















