/* 
#######################################################
JavaScript XMLHttpRequest object builder
Restituisce l' oggetto usato per eseguire chiamate AJAX
#######################################################
*/
function createHttpRequest() 
{
	if (typeof XMLHttpRequest != "undefined") {
		return new XMLHttpRequest();
	} else if (window.ActiveXObject) {
		var sVersions = [ "MSXML2.XMLHttp.5.0",
		"MSXML2.XMLHttp.4.0","MSXML2.XMLHttp.3.0",
		"MSXML2.XMLHttp","Microsoft.XMLHttp"
		];

		// Cerca di ottenere un'istanza a partire dalla versione piu' recente
		for (var i = 0; i < sVersions.length; i++) {
			try {
				var ret = new ActiveXObject(sVersions[i]);
				return ret;
			} catch (oException) {
				// Non fa niente, presegue...
			};
		};
	};
	// Oggetto XHR non disponibile.
	alert("Errore nella creazione dell'oggetto XMLHttpRequest");
	return false;
}

/*
####################################################################
JavaScript ContentRetriever class
Recupera il contenuto di un URL.
Successivamente il risultato viene "trasformato" in codice HTML / 
Javascript (tipicamente array) e viene passato agli "Observers".
Il codice HTML/Js viene restituito dalla classe AjaxRender class. 
Questo approccio consente di separare la logica di recupero del
risultato ottenuto dalla chiamata AJAX dalla logica di render 
in codice HTML. La classe AjaxRender ritorna tipicamente un array , 
successivamente viene inviata una notifica di aggiornamento a tutti
gli "Observers" chiamando la funzione update() che dovra' essere 
definita come metodo all' interno della classe tenuta in osservazione
(es. Basket).
####################################################################
*/

// ContentRetriever class
function ContentRetriever(dataRetrieverUrl, observerObjectsArray, responseType) {
	// Dati restituiti dal server (chiamata AJAX)
	this.xhrData = "";
	// URL responsabile del recupero dati dal server 
	this.dataRetrieverUrl = dataRetrieverUrl;
	// oggetto XHR
	this.ajaxObj = createHttpRequest();
	// array di observer
	this.observerObjectsArray = observerObjectsArray;
	// tipo di risposta (html,json)
	this.responseType = responseType;
};

// Chiamata AJAX verso il server
ContentRetriever.prototype.getContent = function() {
	if (this.ajaxObj) {
		var instance = this;
		this.ajaxObj.open('GET', this.dataRetrieverUrl, true);
		//Funzione di callback. Viene chiamata appena i dati sono disponibili
		this.ajaxObj.onreadystatechange = function() {instance.processDataRetrieved();};
		this.ajaxObj.send(null);
	};
};

//callback function
ContentRetriever.prototype.processDataRetrieved = function() {
	//richiesta completata
	if (this.ajaxObj.readyState == 4) { 
		//richiesta con successo
		if (this.ajaxObj.status==200) { 
			//controlla che il response non sia vuoto
			if(this.ajaxObj.responseText != null && this.ajaxObj.responseText.length > 0) {
				
				// Istanzio oggetto renderer, parse dei dati (Es. JSON)
				var ajaxRender = new AjaxRender(this.ajaxObj.responseText,this.responseType);
				this.xhrData = ajaxRender.toClient();
				
			} else {
				//in caso di errore ritorna un array vuoto
				this.xhrData = [];
			};
			// notifica tutti gli observer
			this.notify();
		};
	};
};

//notify all observers
ContentRetriever.prototype.notify = function() {
	//call the observers' callback function passing in the resulting array
	for(var i = 0; i < this.observerObjectsArray.length; i++) {
		this.observerObjectsArray[i].update(this.xhrData);
	};
};	

//aggiunge un observer
ContentRetriever.prototype.attach = function(observerObject) {
	this.observerObjectsArray.push(observerObject);
};

//rimuove un observer
ContentRetriever.prototype.detach = function(observerObject) {
	if(this.observerObjectsArray == null || this.observerObjectsArray.length == 0) {
		return;
	};
	var index = this.findIndexOf(observerObject);
	if(index != -1) {
		this.detachAt(index);
	};
};

//trova l'indice di un oggetto all'interno di un array
ContentRetriever.prototype.findIndexOf = function(observerObject) {
  for (var i = 0; i < this.observerObjectsArray.length; ++i) {
    if (this.observerObjectsArray[i] == observerObject) {
      return i;
    };
  };
  //non trovato
  return -1;
};

//rimuove un elemento da un array
ContentRetriever.prototype.detachAt = function(index) {
  var length = this.observerObjectsArray.length;
  if (length  == 0) {
    return;
  };

  switch(index) {
  case -1:
  	//non valido
    break;
  case 0:
  	//rimuove il primo elemento
    this.observerObjectsArray.shift();
    break;
  case length - 1:
  	//rimuove l'ultimo elemento
    this.observerObjectsArray.pop();
    break;
  default:
  	//rimuove un elemento intermedio
    var head = this.observerObjectsArray.slice(0, index);
    var tail = this.observerObjectsArray.slice(index+1);
    this.observerObjectsArray = head.concat(tail);
    break;
  };
};	

/*
#############################################################
JavaScript AjaxRender class
Questa classe si occupa della conversione del risultato JSON.
#############################################################
*/

//AjaxRender class
function AjaxRender(xhrString,responseType) {
	// testo JSON oppure HTML
	this.xhrString = xhrString;
	// Tipo di risposta (html,json)
	this.responseType = responseType;
}

//Genera il codice HTML e lo restituisce come array Javascript
AjaxRender.prototype.toClient = function() {

	var output = this.xhrString;

	//decodifica in JSON
	if (this.responseType=='json') output = this.decodeJson();

	return output;
};

//JSON decoder
AjaxRender.prototype.decodeJson = function() {
	//Parse della stringa JSON
	return eval("(" + this.xhrString + ")");
};

