/**
 * 
 * var ajax = new Ajax3(url);
 * ajax.setTextLoading(message);
 *
 * ajax.makeRequestText(get, onSuccess) 
 * ajax.makeRequestJson(get, onSuccess) 
 *
 * 
 * La réponse du serveur est toujours écrite dans un textarea
 * makeRequestText : la réponse est le contenu du textarea
 * makeRequestJson : le contenu du textarea est évalué, et doit contenir ses codes de réponse
 *
 */
Ajax.Instances = {};
Ajax._num_ = 0;
function Ajax(url) { 
    this._id_ = Ajax._num_++;
    Ajax.Instances[this._id_] = this;

    this._url = url;

    this._iframe = null;
    this._formToPost = null; // Est un formulaire pour soumettre des paramètres POST dans un iframe

    this._reponse = null;
    this._frameOnLoadCalled = false;
    this._formSubmitted = false;
    this._timer = null;
    this._timeout = -1; // aucun timeout, attend indéfiniment que le iframe soit chargé

    this._onSuccess = null;
    this._onMessages = null;
    this._onError = null;
    this._onServerError = null;

    this._textLoading = "";
}

Ajax.prototype.setTextLoading = function(text) { this._textLoading = text; }
Ajax.prototype.setOnMessages = function(func) { this._onMessages = func; }
Ajax.prototype.setOnError = function(func) { this._onError = func; }
Ajax.prototype.setOnServerError = function(func) { this._onServerError = func; }

Ajax.prototype.textLoading = function() { return this._textLoading; }

Ajax.prototype.makeCrossDomainRequestJson = function(get, post, onSuccess, timeout) {
    if (timeout!=null) this._timeout = timeout;
    this._onSuccess = onSuccess;

    this._frameOnLoadCalled = false;
    if (this._textLoading!="") Ajax.setLoading(this._textLoading);

    if (get!=null) get += "&";
    get += "_c_=ta"; // _c_=ta signifie réponse dans un textarea, le format json étant le format par défaut

    if (post==null) {
	this._createIframe();
	this._formSubmitted = true;
	this._iframe.src = this._url + "?" + get;

    } else { // Créer un formulaire pour le soumettre dans l'iframe
	// Obtenir les paramètres à poster
	var args  = post.split('&');
	var params = {};
	var numPost = 0;
	for (var i=0;i<args.length;i++) {
	    pos = args[i].indexOf('=');
	    if (pos<1) continue;
	    
	    var name = args[i].substring(0, pos);
	    var value = "";
	    if (pos+1<args[i].length) value = args[i].substring(pos+1, args[i].length);
	    
	    params[name] = value;
	    numPost++;
	}
	
	if (numPost==0) { // Pas la peine de passer par un formulaire, rien à poster
	    this._createIframe();
	    this._formSubmitted = true;
	    this._iframe.src = this._url + "?" + get;

	} else {
	    this._formToPost = document.createElement('form');
	    this._formToPost.target = "iframeForm_"+this._id_;
	    this._formToPost.action = this._url + "?" + get;
	    this._formToPost.method = "POST";
	    
	    for (key in params) {
		var input = document.createElement('input');
		input.type = "hidden";
		input.name = key;
		input.value = params[key];
		this._formToPost.appendChild(input);
	    }
	    this._createIframe("iframeForm_"+this._id_);
	    document.body.appendChild(this._formToPost);
	    this._formSubmitted = true;
	    this._formToPost.submit();
	    document.body.removeChild(this._formToPost);
	}
    }

    if (this._timeout!=-1) this._timer = setInterval('Ajax.Instances['+this._id_+']._checkOnLoad()', this._timeout*1000);
}

Ajax.prototype._checkOnLoad = function() {
    clearInterval(this._timer);
    this._timer = null;

    if (!this._frameOnLoadCalled) {
	this._reponse = {"reponse":{"code":-1, "error":"Le serveur est injoignable : n'a pas répondu dans les "+this._timeout+" secondes"}};

	if (this._textLoading!="") Ajax.resetLoading();
	try {
	    document.body.removeChild(this._iframe);
	} catch (e) {}

	if (this._onServerError!=null) this._onServerError(this._reponse);
	else Ajax.onDefaultServerError(this._reponse);	
    }
}

Ajax.prototype._createIframe = function(iframeName) {
    if (iframeName!=null && iframeName!="" && document.getElementById(iframeName)!=null) return false;

    var s = this;

    if (browser.ie()) {
	var name = "";
	if (iframeName!="") name = 'name="'+iframeName+'" id="'+iframeName+'"';
	this._iframe = document.createElement('<iframe '+name+' src="" style="display: none; width: 0px; height: 0px; margin: 0; padding: 0; border: 0;" onload="Ajax.Instances['+this._id_+']._onFrameOnload();"></iframe>');

    } else {
	this._iframe = document.createElement('iframe');
	if (iframeName!="") {
	    this._iframe.name = iframeName;
	    this._iframe.id = iframeName;
	}
	
	this._iframe.style.width = "0px";
	this._iframe.style.height = "0px";
	this._iframe.style.display = "none";
	this._iframe.style.margin = "0px";
	this._iframe.style.padding = "0px";
	this._iframe.style.border = "0px";
	this._iframe.onload = function() { s._onFrameOnload(); }
    }

    this._formSubmitted = false;
    document.body.appendChild(this._iframe);
    // Le fait d'ajouter le frame au document va créer l'iframe et le charger
    // du coup un premier onload va être émis, qui ne nous intéresse pas
    // ceci n'est pas vrai dans Firefox, mais vrai par exemple dans Google Chrome
    // dans ce cas on détecte le faux onload par le fait que this._formSubmitted = false
    
    return true;
}

/**
 *
 * "reponse":{ // Réponse correcte, onSuccess sera exécuté
 *  {"code":1, "infos":["info1", "info2"...], "warnings":["warning1","warning2"]}
 * }
 *
 * "reponse":{ // Erreur du serveur, onServerError sera exécuté
 *  {"code":-1, "error":"une erreur grave : la réponse du serveur n'a pas pu être déterminée"}
 * }
 * 
 * "reponse":{ // Le serveur n'a pas exécuté la requête demandée car elle conduit à une erreur, onError sera exécuté
 *  {"code":0, "errors":["erreur1", "erreur2"]}
 * }
 *
 * Note :
 *  Si un seul infos, errors ou warnings, peut être de la forme "infos":"le message..." au lieu d'un tableau
 *
 * Si le code d'erreur n'est pas présent, exécute onServerError
 *
 */

Ajax.prototype._onFrameOnload = function() {
    if (!this._formSubmitted) return;

    this._frameOnLoadCalled = true;
    var textarea = null;

    try {
	var doc = this._iframe.contentDocument;
	if (doc==null) doc = this._iframe.contentWindow.document;
	if (doc==null) this._reponse = {"reponse":{"code":-1, "error":"Réponse incorrecte du serveur (document vide ?)"}};
	else {
	    try {
		var textareas = doc.getElementsByTagName('textarea');
		if (textareas==null) this._reponse = {"reponse":{"code":-1, "error":"Réponse incorrecte du serveur (pas de textarea)"}};
		else if (textareas.length!=1) this._reponse = {"reponse":{"code":-1, "error":"Réponse incorrecte du serveur (contient "+textareas.length+" textarea)"}};
		else textarea = textareas[0];

	    } catch(e) {
		this._reponse = {"reponse":{"code":-1, "error":e}};
	    }
	    
	}
	
    } catch (e) {
	this._reponse = {"reponse":{"code":-1, "error":"L'URL "+this._iframe.src+" n'existe pas, ou n'a rien retourné"}};
    }

    var success = false;
    var reponse = null;

    if (this._reponse!=null) { // Est une erreur du serveur
	if (this._onServerError!=null) this._onServerError(this._reponse);
	else Ajax.onDefaultServerError(this._reponse);

    } else {
	
	// Analyser textarea
	reponse = Ajax.jsonDecode(textarea.value);
	if (reponse==null) {
	    this._reponse = {"reponse":{"code":-1, "error":"La réponse du serveur au format JSON n'a pas pu être évaluée"}};
	    if (this._onServerError!=null) this._onServerError(this._reponse);
	    else Ajax.onDefaultServerError(this._reponse);
	    
	} else if (reponse['reponse']==null || reponse['reponse']['code']==null) {
	    this._reponse = {"reponse":{"code":-1, "error":"Le serveur n'a pas retourné le code de réponse"}};
	    if (this._onServerError!=null) this._onServerError(this._reponse);
	    else Ajax.onDefaultServerError(this._reponse);
	    
	} else if (reponse['reponse']['code']!=1) {
	    // Erreur de la requête sur le serveur
	    if (this._onError!=null) this._onError(reponse);
	    else Ajax.onDefaultError(reponse);
	    
	} else {
	    // Peut y avoir des infos et warning
	    if (reponse['reponse']['infos']!=null || reponse['reponse']['warnings']!=null) {
		if (this._onMessages!=null) this._onMessages(reponse);
		else Ajax.onDefaultMessages(reponse);		    
	    }
	    success = true;
	}
    }

    if (this._textLoading!="") Ajax.resetLoading();

    this._formSubmitted = false;
    this._iframe.src = "";
    try {document.body.removeChild(this._iframe);} catch (e) {}
    this._iframe = null;

    if (success) this._onSuccess(reponse);
}

Ajax.jsonDecode = function(json) {
    try {
	eval('var a = ' + json);
	return a;
	
    } catch(ex) {
	return null;
    }
    
    return null;
}

Ajax.onDefaultServerError = function(reponse) {
    alert(reponse['reponse']['error']);
}

Ajax.onDefaultError = function(reponse) {
    var str = "";
    if (reponse['reponse']['errors']==null) str = "Erreur mais pas de message d'erreurs !";
    else {
	var errors = reponse['reponse']['errors'];
	if (!(errors instanceof Array)) errors = [errors];	
	for (var i=0;i<errors.length;i++) str += "Erreur : " + errors[i]+"\n";
    }
    alert(str);
}

Ajax.onDefaultMessages = function(reponse) {
    var str = "";

    var warnings = reponse['reponse']['warnings'];
    if (warnings!=null) {
	if (!(warnings instanceof Array)) warnings = [warnings];
	for (var i=0;i<warnings.length;i++) str += "Warning : " + warnings[i]+"\n";
    }

    var infos = reponse['reponse']['infos'];
    if (infos!=null) {
	if (!(infos instanceof Array)) infos = [infos];
	for (var i=0;i<infos.length;i++) str += "Info : " + infos[i]+"\n";
    }
    alert(str);    
}

Ajax.nodeLoading = null;
Ajax.setLoading = function(text) {
    if (Ajax.nodeLoading==null) {
	var node = document.createElement('span');
	node.style.position = "fixed";
	node.style.right = "0px";//"500px";
	node.style.top = "0px";
	node.style.backgroundColor = "#fff1a8";
	node.style.fontSize = "15px";
	node.style.fontWeight = "bold";
	node.style.padding = "5px";
	node.style.zIndex = 5000;

	Ajax.nodeLoading = node;
	document.body.appendChild(node);

    } else Ajax.nodeLoading.style.display = "inline";

    Ajax.nodeLoading.innerHTML = text;
}
Ajax.resetLoading = function() {
    if (Ajax.nodeLoading!=null) Ajax.nodeLoading.style.display = "none";
}

Ajax.prototype.makeRequestSynchroneJson = function(get, post) {
   var http_request = null;

   if (window.XMLHttpRequest) { // Mozilla, Safari,...
      http_request = new XMLHttpRequest();
      if (http_request.overrideMimeType) {
         http_request.overrideMimeType('text/xml');
      }

   } else if (window.ActiveXObject) { // IE
      try {
         http_request = new ActiveXObject("Msxml2.XMLHTTP");
      } catch (e) {
         try {
            http_request = new ActiveXObject("Microsoft.XMLHTTP");
         } catch (e) { }
      }
   }

   if (!http_request) {
       this._reponse = {"reponse":{"code":-1, "error":"Impossible de créer une instance XMLHTTP"}};
       
       if (this._onServerError!=null) this._onServerError(this._reponse);
       else Ajax.onDefaultServerError(this._reponse);
       
       return null;
   }
   
   var url = this._url;
   if (get!="") url += "?" + encodeURI(get);   
   // le paramètre _c_ n'est pas présent dans la requête : renvoi <html><body>json</body></html>

   if (post==null) {
       http_request.open('GET', url, false);
       http_request.setRequestHeader("Content-Type", "text/html;charset=UTF-8");
       http_request.send(null);

   } else {
       http_request.open('POST', url, false);
       http_request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
       http_request.send(post);
   }

   var deb = http_request.responseText.substr(0, 12);
   var fin = http_request.responseText.substring(http_request.responseText.length-14, http_request.responseText.length);
   if (deb!="<html><body>" || fin!="</body></html>") {
       this._reponse = {"reponse":{"code":-1, "error":"Réponse du serveur incorrecte : n'est pas de la forme <html><body>json</body></html>"}};

       if (this._onServerError!=null) this._onServerError(this._reponse);
       else Ajax.onDefaultServerError(this._reponse);

       return null;
   }
   
   var reponse = Ajax.jsonDecode(http_request.responseText.substr(12, http_request.responseText.length-12-14));
   var success = false;
   if (reponse==null) {
       this._reponse = {"reponse":{"code":-1, "error":"La réponse du serveur au format JSON n'a pas pu être évaluée"}};
       if (this._onServerError!=null) this._onServerError(this._reponse);
       else Ajax.onDefaultServerError(this._reponse);
       
   } else if (reponse['reponse']==null || reponse['reponse']['code']==null) {
       this._reponse = {"reponse":{"code":-1, "error":"Le serveur n'a pas retourné le code de réponse"}};
       if (this._onServerError!=null) this._onServerError(this._reponse);
       else Ajax.onDefaultServerError(this._reponse);
       
   } else if (reponse['reponse']['code']!=1) {
       // Erreur de la requête sur le serveur
       if (this._onError!=null) this._onError(reponse);
       else Ajax.onDefaultError(reponse);
       
   } else {
       // Peut y avoir des infos et warning
       if (reponse['reponse']['infos']!=null || reponse['reponse']['warnings']!=null) {
	   if (this._onMessages!=null) this._onMessages(reponse);
	   else Ajax.onDefaultMessages(reponse);		    
       }
       success = true;
   }

   if (!success) return null;
   return reponse;
}

Ajax.prototype.makeRequestAsynchroneJson = function(get, post, onSuccess) {
    this._onSuccess = onSuccess;

   var http_request = null;
   if (window.XMLHttpRequest) { // Mozilla, Safari,...
      http_request = new XMLHttpRequest();
      if (http_request.overrideMimeType) {
         http_request.overrideMimeType('text/xml');
      }
   } else if (window.ActiveXObject) { // IE
      try {
         http_request = new ActiveXObject("Msxml2.XMLHTTP");
      } catch (e) {
         try {
            http_request = new ActiveXObject("Microsoft.XMLHTTP");
         } catch (e) {}
      }
   }

   if (!http_request) {
       this._reponse = {"reponse":{"code":-1, "error":"Impossible de créer une instance XMLHTTP"}};
       
       if (this._onServerError!=null) this._onServerError(this._reponse);
       else Ajax.onDefaultServerError(this._reponse);
       
       return;
   }

   if (this._textLoading!="") Ajax.setLoading(this._textLoading);

   var s = this;
   http_request.onreadystatechange = function() { s.onreadystatechange(http_request); }

   var url = this._url;
   if (get!="") url += "?" + encodeURI(get);   
   // le paramètre _c_ n'est pas présent dans la requête : renvoi <html><body>json</body></html>

   if (post==null) {
       http_request.open('GET', url, true);
       http_request.setRequestHeader("Content-Type", "text/html;charset=UTF-8");
       http_request.send(null);

   } else {
       http_request.open('POST', url, true);
       http_request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
       http_request.send(post);
   }
}

Ajax.prototype.onreadystatechange = function(http_request) { 
    if (http_request.readyState==4) {
	if (http_request.status!=200) {
	    this._reponse = {"reponse":{"code":-1, "error":"L'URL "+this._url+" n'existe pas, ou n'a rien retourné"}};
	    if (this._onServerError!=null) this._onServerError(this._reponse);
	    else Ajax.onDefaultServerError(this._reponse);

	} else {
	    var deb = http_request.responseText.substr(0, 12);
	    var fin = http_request.responseText.substring(http_request.responseText.length-14, http_request.responseText.length);
	    if (deb!="<html><body>" || fin!="</body></html>") {
		this._reponse = {"reponse":{"code":-1, "error":"Réponse du serveur incorrecte : n'est pas de la forme <html><body>json</body></html>"}};
		
		if (this._onServerError!=null) this._onServerError(this._reponse);
		else Ajax.onDefaultServerError(this._reponse);
		
		return;
	    }

	    var reponse = Ajax.jsonDecode(http_request.responseText.substr(12, http_request.responseText.length-12-14));
	    var success = false;
	    if (reponse==null) {
		this._reponse = {"reponse":{"code":-1, "error":"La réponse du serveur au format JSON n'a pas pu être évaluée"}};
		if (this._onServerError!=null) this._onServerError(this._reponse);
		else Ajax.onDefaultServerError(this._reponse);
		
	    } else if (reponse['reponse']==null || reponse['reponse']['code']==null) {
		this._reponse = {"reponse":{"code":-1, "error":"Le serveur n'a pas retourné le code de réponse"}};
		if (this._onServerError!=null) this._onServerError(this._reponse);
		else Ajax.onDefaultServerError(this._reponse);
		
	    } else if (reponse['reponse']['code']!=1) {
		// Erreur de la requête sur le serveur
		if (this._onError!=null) this._onError(reponse);
		else Ajax.onDefaultError(reponse);
		
	    } else {
		// Peut y avoir des infos et warning
		if (reponse['reponse']['infos']!=null || reponse['reponse']['warnings']!=null) {
		    if (this._onMessages!=null) this._onMessages(reponse);
		    else Ajax.onDefaultMessages(reponse);		    
		}
		success = true;
	    }
	    
	    if (this._textLoading!="") Ajax.resetLoading();
	    if (success) this._onSuccess(reponse);
	}
    }
}

Ajax.submitForm = function(form, receiver, textLoading) { 
    var target = form.getAttribute('target');
    if (target==null || target=="") {
	alert("ERREUR ! L'attribut target du formulaire n'est pas renseigné");
	return false;
    }

    var ajax = new Ajax();
    if (!ajax._createIframe(target)) {
	alert("Cette action est refusée, une autre action est déjà en cours...");
	return false; // Ne soumet pas le formulaire
    }

    if (receiver.onFormResponse) ajax._onSuccess = function(rep) { receiver.onFormResponse.apply(receiver, [rep]); } // Pour compatibilité
    else ajax._onSuccess = function(rep) { receiver.onSuccess.apply(receiver, [rep]); }
    if (receiver.onError) ajax._onError = function(rep) { receiver.onError.apply(receiver, [rep]); }
    if (receiver.onServerError) ajax._onServerError = function(rep) { receiver.onServerError.apply(receiver, [rep]); }
    if (receiver.onMessages) ajax._onMessages = function(rep) { receiver.onMessages.apply(receiver, [rep]); }

    if (textLoading==null) ajax._textLoading = "Requête en cours...";
    else ajax._textLoading = textLoading;
    Ajax.setLoading(ajax._textLoading);

    // Toujours retourner la réponse dans un textarea
    var action = form.getAttribute('action');
    if (action.indexOf("?")==-1) action += "?_c_=ta";
    else action += "&_c_=ta";

    form.setAttribute('action', action);

    ajax._formSubmitted = true;

    return true; // Soumet le formulaire
}
    
Ajax.makeRequestSynchroneJson = function(url, get, post) {    
    var ajax = new Ajax(url);
    return ajax.makeRequestSynchroneJson(get, post);
}
Ajax.makeRequestAsynchroneJson = function(url, get, post, textLoading, onSuccess) {
    var ajax = new Ajax(url);
    if (textLoading!=null) ajax.setTextLoading(textLoading);
    ajax.makeRequestAsynchroneJson(get, post, onSuccess);
}

Ajax.prototype.makeRequestSynchroneViaProxyJson = function(get, post) {    
    if (get=="") get = "_url_="+this._url;
    else get += "&_url_="+this._url;

    this._url = "/proxy.php";

    return this.makeRequestSynchroneJson(get, post);
};

Ajax.prototype.makeRequestAsynchroneViaProxyJson = function(get, post, onSuccess) {    
    if (get=="") get = "_url_="+this._url;
    else get += "&_url_="+this._url;

    this._url = "/proxy.php";
    
    this.makeRequestAsynchroneJson(get, post, onSuccess);
};

Ajax.makeRequestSynchroneViaProxyJson = function(url, get, post) {    
    var ajax = new Ajax("/proxy.php");

    if (get=="") get = "_url_="+url;
    else get += "&_url_="+url;

    return ajax.makeRequestSynchroneJson(get, post);
};

Ajax.makeRequestAsynchroneViaProxyJson = function(url, get, post, textLoading, onSuccess) {
    var ajax = new Ajax("/proxy.php");
    if (textLoading!=null) ajax.setTextLoading(textLoading);

    if (get=="") get = "_url_="+url;
    else get += "&_url_="+url;

    ajax.makeRequestAsynchroneJson(get, post, onSuccess);
};

