// Cette variable globale est utilisée par le mécanisme de cache de la PFW_Ajax_classe
// Elle permet d'utiliser un système de cache global (non dépendant de l'objet PFW_AJAX instancié) à toute la page jusqu'à son rafraichissement
var PFW_AjaxCache = new Array();

/**
* Constructeur de la classe PFW_AJAX
* @url : l'url du fichier php contenant la requete a executer 
**/
function PFW_AJAX(url)
{
	//***************************
	// Attributs de la classe
	//***************************
	this.xmlhttp 			= false; 
	this.url 				= url;
	this.parametres 		= false;
	this.id_champ 			= false;
	this.submitMethod 		= "post";
	this.Mode 				= "asynchronous";
	this.ResponseType 		= "text";
	this.Response 			= false;
	this.isAjaxMessage		= false;
	this.isIE				= document.all;
	this.CacheMode			= 'inactive';
	this.isResponseInCache	= false;
	//***************************
	
	//***************************
	// Instanciation des Attributs
	//***************************
	/*@cc_on @*/ 
	/*@if (@_jscript_version >= 5) 
	// JScript gives us Conditional compilation, we can cope with old IE versions. 
	// and security blocked creation of the objects. 
	try 
	{ 
		this.xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); 
	} 
	catch (e) 
	{ 
		try 
		{ 
			this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); 
		} 
		catch (E) 
		{ 
			this.xmlhttp = false; 
		} 
	} 
	@end @*/ 
	if (!this.xmlhttp && typeof XMLHttpRequest!='undefined') 
	{ 
		this.xmlhttp = new XMLHttpRequest(); 
	}
	//***************************
}


/**
* Definition des methodes de la classe PFW_AJAX
**/
PFW_AJAX.prototype = 
{
	//***************************
	// Définition des geters
	//***************************
	getUrl : function()
	{	
		return this.url;
	},
	
	getParametres : function()
	{	
		return this.parametres;
	},
	
	getIdChamp : function()
	{	
		return this.id_champ;
	},
	
	getsubmitMethod : function()
	{	
		return this.submitMethod;
	},
	
	getMode : function()
	{	
		return this.Mode;
	},
	
	getResponseType : function()
	{	
		return this.ResponseType;
	},
	
	getResponse : function()
	{	
		return this.Response;
	},
	
	getCacheMode : function()
	{	
		return this.CacheMode;
	},
	
	getFromCache : function()
	{	
		var index;
		var argv = this.getFromCache.arguments;
		
		if (argv.length > 0)
		{
			index = argv[0];
		}
		else
		{
			index = (this.getsubmitMethod() == "post")? this.getUrl()+"?"+this.getParametres() : this.getUrl();
		}
		
		return (PFW_AjaxCache[index]) ? PFW_AjaxCache[index] : false;
	},

	//***************************
	// Définition des seters
	//***************************
	setUrl : function(url)
	{	
		this.url = url;
	},
	
	setParametres : function(parametres)
	{	
		this.parametres = parametres;
	},
	
	setIdChamp : function(id)
	{	
		this.id_champ = id;
	},
	
	setsubmitMethod : function(submitMethod)
	{	
		this.submitMethod = submitMethod;
	},
	
	setMode : function(Mode)
	{	
		this.Mode = Mode;
	},
	
	setResponseType : function(responseType)
	{	
		this.ResponseType = responseType;
	},
	
	setCacheMode : function(mode)
	{	
		this.CacheMode = mode;
	},
		
	addIntoCache : function()
	{	
		var index;
		var argv = this.addIntoCache.arguments;
		
		if (argv.length > 0)
		{
			index = argv[0];
		}
		else
		{
			index = (this.getsubmitMethod() == "post")? this.getUrl()+"?"+this.getParametres() : this.getUrl();
		}
		
		PFW_AjaxCache[index] = (this.getResponse() instanceof PFW_AJAX_Message) ? this.getResponse().getResponseFromServer() : this.getResponse();
	},
	
	/**
	* Fonction qui recoit la reponse a une requete precedemment envoyée 
	**/
	setResponse : function()
	{	
		// 1) Aucune requete n'a été soumise car la réponse se trouve dans le cache
		if ( this.isResponseInCache )
		{
			this.Response = this.getFromCache();
		}
		// 2) On obtient la réponse suite à une requette HTTP au serveur
		else 
		{
			if (this.xmlhttp.readyState == 4) 
			{ 
				if (this.xmlhttp.status == 200) 
				{
					
					// Autodetection d'une réponse XML si le response_type a été laissé à sa valeur par défaut
					// ... alors que la reponse recue est bien de type XML
					if (this.isIE && this.getResponseType() == 'text' && this.xmlhttp.responseXML.firstChild != null)
					{
						this.setResponseType('xml');
					}
					else 
					{
						if (!this.isIE && this.getResponseType() == 'text' && this.xmlhttp.responseXML != null)
						{
							this.setResponseType('xml');
						}
					}

					switch (this.getResponseType()) 
					{ 
						case 'readyState': 
							this.Response = this.xmlhttp.readyState; 
						break; 
						
						case 'text': 
							//on effectue l'equivalent d'un trim() en JS pour supprimer tout caractere special en debut de chaine 
							this.Response = this.xmlhttp.responseText.replace(/(^\s*)|(\s*$)/g, ""); 
							
							// Si le cache est activé, on stocke le retour dans un tableau associatif
							if(this.getCacheMode()=='auto')
							{
								this.addIntoCache();
							}
						break; 
						
						case 'xml': 
							/* test de sécurité firefox multi domaine */
							try {
								this.xmlhttp.responseXML.firstChild.tagName;
								domdoc = this.xmlhttp.responseXML;
							} catch(e) {
								domdoc = (new DOMParser()).parseFromString(this.xmlhttp.responseText,"text/xml");
							}
							
							// On vérifie la présence d'erreur dans la réponse xml
							if (  domdoc==null
							 		|| (domdoc.parseError &&  domdoc.parseError.errorCode !=0)	
							 		|| domdoc.getElementsByTagName('*').length==0
						         	|| domdoc.firstChild.tagName== "parsererror"
						         	|| this.xmlhttp.responseText.replace(/(^\s*)/, "").substr(0,5)!="<"+"?xml"
						    	)
						    // Si la réponse ne peut pas être interprétée comme du XML valide, on la traite comme une chaine de texte ...
						    {
								this.setResponseType('text');
								this.Response = this.xmlhttp.responseText;
							}
							// ... sinon
							else
							{
								//on effectue l'equivalent d'un trim() pour supprimer tout caractere special dans l'arbre xml
								this.Response = PFW_clean(domdoc);
								
								// Si le cache est activé, on stocke le retour dans un tableau associatif
								if(this.getCacheMode()=='auto')
								{
									this.addIntoCache();
								}
							}
						break; 
						
						case 'status': 
							this.Response = this.xmlhttp.status; 
						break; 
						
						case 'onreadystate': 
							this.Response = this.xmlhttp.onreadystate; 
						break; 
						
						case 'statusText ': 
							this.Response = this.xmlhttp.onreadystate; 
						break; 
					}
				}
				else
				{
					return false;
				}
			}
			else
			{
				return false;
			}
		}
		
		// 3) Si j'ai bien obtenu ma reponse (du cache OU du serveur)
		if (this.getResponse())
		{	
			// 3.1) Autodetection d'une réponse XML si le response_type a été laissé à sa valeur par défaut
			// ... alors que la reponse recue est bien de type XML
			if (this.getResponseType() == 'text' && this.Response.firstChild != null)
			{
				this.setResponseType('xml');	
			}
			
			// 3.2) Auto détection d'une trame ajax message dans le cas ou la réponse est de type XML
			if (this.getResponseType() == 'xml')
			{
				if(this.getResponse().getElementsByTagName("message").length > 0 && this.getResponse().getElementsByTagName("message")[0].getAttribute("type") == "PFW_ajax_message")
				{
					this.isAjaxMessage = true;
					this.Response = new PFW_AJAX_Message(this.Response);
				}
			}
		}
		
		// 4) On execute le traitement post Réponse
		this.traitement();
	},
	
	/**
	* Fonction qui effectue une requete HTTP 
	* @cache : active le cache lors de l'envoi de la requete [non obligatoire]
	**/
	HTTPrequest : function()
	{	
		// 1) On s'assure que la fonction pour l'attente lors du traitement n'a pas été désactivée
		if (this.action_debut_ATTENTE != false)
		{
			this.action_debut_ATTENTE();
		}
		
		var cacheActif = false;
		
		// 2) On teste si le cache a été activé dans le mode manual
		if (this.getCacheMode()=='manual')
		{
			var argv = this.HTTPrequest.arguments;
			if (argv.length > 0)
			{
				cacheActif = (argv[0] == true)? true : false;
			}
		}
		
		// 3) Si le cache est activé et qu'on trouve l'url dans le cache
		if ( ( this.getCacheMode()=='auto' || (this.getCacheMode()=='manual' && cacheActif)) && this.getFromCache())
		{
			this.isResponseInCache = true;
			this.setResponse();
		}
		
		// 4) Sinon on realise une requete HTTP
		else
		{
			var mode = (this.Mode == "asynchronous")? true : false;
			
			if (this.submitMethod == 'post')
			{
				this.xmlhttp.open("POST", this.url, mode); 
				if (this.parametres!='') 
				{ 
					this.xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 
					this.xmlhttp.send(this.parametres); 
				} 
				else 
				{ 
					this.xmlhttp.send(null); 
				} 
				var refToThis = this;
				this.xmlhttp.onreadystatechange = function () {refToThis.setResponse();} 
			}
		}
	},
	
	
	/**
	* Fonction Javascript de traitement de la réponse à une requete XMLHttpRequest
	**/
	traitement : function()
	{ 
		// On s'assure que la fonction pour le traitement de la réponse n'a pas été désactivée
		if (this.action_OK != false)
		{
			switch (this.getResponseType()) 
			{ 
				case 'text': 
					this.action_OK();
				break; 
				
				case 'xml': 
					// 1 - Si la réponse est de type "PFW_ajax_message" ...
					if(this.isAjaxMessage)
					{
						// ... on verifie que le traitement s'est bien déroulé sur le serveur et on appelle action_OK
						if (this.getResponse().getError_code() == "0")
						{
							this.action_OK();
						}
						// ... sinon on appelle action_ERREUR
						else
						{
							this.action_ERREUR();
						}
						// Si j'ai un noeud debug dans le message, j'affiche son contenu
						if (this.getResponse().getDebug() && this.getIdChamp())
						{
							PFW_customInnerHTML(this.getIdChamp() , document.getElementById(this.getIdChamp()).innerHTML + '<fieldset><legend style="color:red;font-weight:bold;">DEBUG</legend>' +this.getResponse().getDebug() + '</fieldset>');
						}
					}
					// 2 - Sinon on appelle la fonction pour le traitement de la réponse
					else
					{
						this.action_OK();
					}
				break; 

				default : 
					this.action_OK();
				break; 
			} 
		}
		
		// On s'assure que la fonction pour l'attente lors du traitement n'a pas été désactivée
		if (this.action_fin_ATTENTE != false)
		{
			this.action_fin_ATTENTE();
		}
	},
	
	
	/**
	* Fonction Javascript appelée automatiquement lors du traitement de la réponse à une requete XMLHttpRequest si celle-ci est OK
	**/
	action_OK : function()
	{ 
		//alert('actionok');
		switch (this.getResponseType()) 
		{ 
			case 'text': 
				PFW_customInnerHTML(this.getIdChamp() , this.getResponse());
			break; 
			
			case 'xml': 	
				if (this.isAjaxMessage)
				{
					if (Number(this.getResponse().getVersion()) < 3)
					{
						PFW_customInnerHTML(this.getIdChamp() , this.getResponse().getHTML_content());
					}
					else
					{
						var tab_HTML_content = this.getResponse().getHTML_content();
						if (tab_HTML_content != false)
						{
							for (var i=0; i<tab_HTML_content.length; i++)
							{
								PFW_customInnerHTML(tab_HTML_content[i].id , tab_HTML_content[i].html);
							}
						}
					}
				}
			break; 
		}
	},
	
	
	/**
	* Fonction Javascript appelée automatiquement lors du traitement de la réponse à une requete XMLHttpRequest en cas d'erreur
	**/
	action_ERREUR : function()
	{ 
			if (this.isAjaxMessage)
			{
				alert("Code Erreur : " + this.getResponse().getError_code() + "\n" + this.getResponse().getError_message());
			}
	},
	
	
	/**
	* Fonction Javascript appelée automatiquement avant l'envoi de la requete HTTP
	**/
	action_debut_ATTENTE : function()
	{ 
	},
	
	
	/**
	* Fonction Javascript appelée automatiquement à la fin du traitement de la réponse à une requete XMLHttpRequest
	**/
	action_fin_ATTENTE : function()
	{ 
	}
}


/***************************************************************************************************/
/***************************************************************************************************/


/**
* Constructeur de la classe PFW_AJAX_Message
* @xml : le code XML genere par la classe AjaxMessage du serveur
**/
function PFW_AJAX_Message(xml)
{
	
	//***************************
	// Attributs de la classe
	//***************************
	
	// Le firstChild d'un objet XML document pour IE (6) est la balise de declaration <xml>
	// pour firefox c'est la racine du xml, en l'occurence <message>
	// on stocke dans xml_message le sous-arbre qui commence à la racine message en fonction du navigateur
	this.xml_message = xml; 
}


/**
* Definition des methodes de la classe PFW_AJAX_Message
**/
PFW_AJAX_Message.prototype = 
{
	/**
	* getResponseFromServer
	**/
	getResponseFromServer : function()
	{	
		return this.xml_message;
	},
	
	
	/**
	* getXMLMessage
	**/
	getXMLMessage : function()
	{	
		return (this.xml_message.childNodes[0].nodeName != 'message')? this.xml_message.childNodes[1] : this.xml_message.childNodes[0];
	},
	
	
	/**
	* getVersion
	**/
	getVersion : function()
	{	
		return (this.getXMLMessage().getAttribute("version") != null)? this.getXMLMessage().getAttribute("version") : false;
	},
	
	
	/**
	* getError_code
	**/
	getError_code : function()
	{	
		var return_value;
		
		switch (this.getVersion())
		{
			case "1":
				return_value = (this.getXMLMessage().getElementsByTagName("error_code")[0].firstChild != null)? this.getXMLMessage().getElementsByTagName("error_code")[0].firstChild.nodeValue : false;
			break;
			
			case "2" || "3":
				return_value = (this.getXMLMessage().firstChild.getElementsByTagName("error_code")[0].firstChild != null)? this.getXMLMessage().firstChild.getElementsByTagName("error_code")[0].firstChild.nodeValue : false;
			break;
			
			default:
				return_value = (this.getXMLMessage().getElementsByTagName("error_code")[0].firstChild != null)? this.getXMLMessage().getElementsByTagName("error_code")[0].firstChild.nodeValue : false;
			break;
		}
		
		return return_value;
	},
	
	
	/**
	* getError_message
	**/
	getError_message : function()
	{	
		var noeud_ERRORMESSAGE_content;
		var return_value;
		
		switch (this.getVersion())
		{
			case "1":
				noeud_ERRORMESSAGE_content = (this.getXMLMessage().getElementsByTagName("error_message")[0].firstChild != null)? this.getXMLMessage().getElementsByTagName("error_message")[0] : false;
			break;
			
			case "2" || "3":
				noeud_ERRORMESSAGE_content = (this.getXMLMessage().firstChild.getElementsByTagName("error_message").length > 0)? this.getXMLMessage().firstChild.getElementsByTagName("error_message")[0] : false;
			break;
			
			default:
				noeud_ERRORMESSAGE_content = (this.getXMLMessage().getElementsByTagName("error_message")[0].firstChild != null)? this.getXMLMessage().getElementsByTagName("error_message")[0] : false;
			break;
		}
		
		// On teste que le message contient bien un Debug_content
		if (noeud_ERRORMESSAGE_content)
		{
			return_value = this.getContentNodeAsString(noeud_ERRORMESSAGE_content);
		}
		else
		{
			return_value = false;
		}
		
		return return_value;
	},
	
	
	/**
	* getHTML_content
	**/
	getHTML_content : function()
	{	
		var noeud_HTML_content;
		var return_value = '';
		
		switch (this.getVersion())
		{
			case "1":
				noeud_HTML_content = (this.getXMLMessage().getElementsByTagName("HTML_content").length > 0)? this.getXMLMessage().getElementsByTagName("HTML_content")[0] : false;
			break;
			
			case "2" :
				noeud_HTML_content = (this.getXMLMessage().childNodes[1].getElementsByTagName("HTML_content").length > 0)? this.getXMLMessage().childNodes[1].getElementsByTagName("HTML_content")[0] : false;
			break;
			
			case "3":
				noeud_HTML_content = (this.getXMLMessage().childNodes[1].getElementsByTagName("HTML_content").length > 0)? this.getXMLMessage().childNodes[1].getElementsByTagName("HTML_content") : false;
			break;
			
			default:
				noeud_HTML_content = (this.getXMLMessage().getElementsByTagName("HTML_content").length > 0)? this.getXMLMessage().getElementsByTagName("HTML_content")[0] : false;
			break;
		}
		
		// On teste que le message contient bien un HTML_content
		if (noeud_HTML_content)
		{
			if (Number(this.getVersion()) < 3)
			{
				return_value = this.getContentNodeAsString(noeud_HTML_content);
			}
			else
			{
				var tab_HTML_content = new Array();
				for (var i=0; i<noeud_HTML_content.length; i++)
				{
					tab_HTML_content[i] = {id : noeud_HTML_content[i].getAttribute("id") , html : this.getContentNodeAsString(noeud_HTML_content[i])};
				}
				return_value = tab_HTML_content;
			}
		}
		else
		{
			return_value = false;
		}
		return return_value;
	},
	
	
	/**
	* getXML_content
	**/
	getXML_content : function()
	{	
		var noeud_XML_content;
		var return_value;
		
		switch (this.getVersion())
		{
			case "1":
				noeud_XML_content = (this.getXMLMessage().getElementsByTagName("XML_content").length > 0)? this.getXMLMessage().getElementsByTagName("XML_content")[0] : false;
			break;
			
			case "2" || "3":
				noeud_XML_content = (this.getXMLMessage().childNodes[1].getElementsByTagName("XML_content").length > 0)? this.getXMLMessage().childNodes[1].getElementsByTagName("XML_content")[0] : false;
			break;
			
			default:
				noeud_XML_content = (this.getXMLMessage().getElementsByTagName("XML_content").length > 0)? this.getXMLMessage().getElementsByTagName("XML_content")[0] : false;
			break;
		}
		
		// On teste que le message contient bien un XML_content
		if (noeud_XML_content)
		{
			// 1) On detecte le format du XML : string ou XML
			// On récupère le premier fils du noeud XML_content, on teste son type (3 = text, 1 = xml)
			// Si c'est une string : on essaie de la transformer en objet XML document
			if (noeud_XML_content.firstChild.nodeType == 3)
			{	
				var chaineXML = this.getContentNodeAsString(noeud_XML_content);
				
				// On transforme la chaineXML en objet XML Document
				// code for IE
				if (window.ActiveXObject)
				{
					var return_value = new ActiveXObject("Microsoft.XMLDOM");
					return_value.async = "false";
					// si le xml est mal formé, on retourne false
					if(!return_value.loadXML(chaineXML))
					{
						return_value = false;
					}
				}
				// code for Mozilla, Firefox, Opera, etc.
				else
				{
					var parser=new DOMParser();
					var return_value=parser.parseFromString(chaineXML,"text/xml");
				}
			}
			// 2) Dans le cas XML on renvoie le sous arbre contenu dans XML_content
			else
			{
				return_value = noeud_XML_content;
			}
		}
		else
		{
			return_value = false;
		}
		
		return return_value;
	},
	
	
	/**
	* getDebug
	**/
	getDebug : function()
	{	
		var noeud_DEBUG_content;
		var return_value;
		
		switch (this.getVersion())
		{
			case "1":
				noeud_DEBUG_content = (this.getXMLMessage().getElementsByTagName("debug").length > 0)? this.getXMLMessage().getElementsByTagName("debug")[0] : false;
			break;
			
			case "2" || "3":
				noeud_DEBUG_content = (this.getXMLMessage().firstChild.getElementsByTagName("debug").length > 0)? this.getXMLMessage().firstChild.getElementsByTagName("debug")[0] : false;
			break;
			
			default:
				noeud_DEBUG_content = (this.getXMLMessage().getElementsByTagName("debug").length > 0)? this.getXMLMessage().getElementsByTagName("debug")[0] : false;
			break;
		}
		
		// On teste que le message contient bien un Debug_content
		if (noeud_DEBUG_content)
		{
			return_value = this.getContentNodeAsString(noeud_DEBUG_content);
		}
		else
		{
			return_value = false;
		}
		return return_value;
	},
	
	
	/**
	* getContentNodeAsString
	**/
	getContentNodeAsString : function(node)
	{	
		var return_value = '';
		
		// Pour parer au probleme de Firefox et Opera qui eclatent les contenus de plus de 4ko (ou 32ko pour Opera) dans une collection de noeuds ...
		// ... , on detecte le nombre des noeuds qui stockent les données retournées par le serveur ...
		// ... , si on est en présence d'une collection : on la parcourt en concaténant le contenu de chacun de ses éléments
		// ... , si on est en presence d'un seul noeud, on retourne le contenu de celui-ci
		// ... , si on est en presence d'un noeud vide, on retourne une chaine vide
		if (node.childNodes.length > 1)
		{	
			for(i=0; i< node.childNodes.length; i++)
			{
				return_value += node.childNodes[i].nodeValue;
			}
		}
		else
		{
			if (node.childNodes.length == 1)
			{
				return_value = node.firstChild.nodeValue;
			}
			else
			{
				return_value = "";
			}
		}
		
		return return_value;
	}
}


/***************************************************************************************************/
/***************************************************************************************************/


/** 
* Transforme un formulaire en un objet Javascript contenant le nom des champs 
* ainsi que pour chacun leur(s) valeur(s). Est prévu pour gérer les champs de type radio , 
* checkbox , listbox (avec choix multiples possibles) en les traitant uniquement 
* dans le cas ou au moins une valeur a été spécifiées pour un élément de formulaire. 
* Ne traite pas les éléments de type submit , reset ou button. 
* 
* @En entree : prend l'id du formulaire a traiter 
* 
* @Retourne un objet JavaScript avec une propriété pour chaque champ du formulaire à soumettre. 
* La valeur de chaque propriété de l'objet est un tableau contenant une ou plusieurs valeurs à soumettre 
*/ 
function PFW_getFormValuesAsMap(id_form) 
{ 
	var params = new Object(); 
	var inputs = document.getElementById(id_form).elements; 
	for (var i=0; i<inputs.length; i++) 
	{ 
		var input = inputs[i]; 
		if (input.type == "radio" || input.type == "checkbox") 
		{ 
			//Cas des radios et checkboxes, ne les traite que s'ils sont checked 
			if (input.checked == true) 
			{ 
				if (params[input.name] == null) 
				{ 
					params[input.name] = new Array(); 
				} 
				params[input.name].push(input.value); 
			} 
		} 
		else if (input.type == "select-multiple") 
		{ 
			//Cas des Select multiple 
			for (var j=0; j<input.options.length; j++) 
			{ 
				if (input.options[j].selected == true) 
				{ 
					if (params[input.name] == null) 
					{ 
						params[input.name] = new Array(); 
					} 
					params[input.name].push(input.options[j].value); 
				} 
			} 
		} 
		else if (input.type == "submit" || input.type == "button" || input.type == "reset") 
		{ 
			//On exclue les submit , reset , button 
		} 
		else if (input.name != undefined && input.value != undefined) 
		{ 
			//On traite tous les autres cas : text , hidden , textarea ... 
			if (params[input.name] == null) 
			{ 
				params[input.name] = new Array(); 
			} 
			params[input.name].push(input.value); 
		} 
	} 
	return params; 
} 


/** 
* Retourne la query string contenant tous les champs avec que leur valeur d'un formulaire à soumettre. 
* Chaque valeur est encodee avant d'etre ajoutée à la query string. 
* 
* @En entree : prend l'id du formulaire a traiter 
* 
* @Retourne une query string 
*/ 
function PFW_getQueryString(id_form) 
{ 
	var params = PFW_getFormValuesAsMap(id_form); 
	var queryString = ""; 
	for (var name in params) 
	{ 
		var values = params[name]; 
		for (var i=0; i<values.length; i++) 
		{ 
			queryString += name + "=" + encodeURIComponent(values[i]) + "&"; 
		} 
	} 
	return queryString.substring(0,queryString.length-1);
}

/***************************************************************************************************/
/***************************************************************************************************/

/**
 * Fonction qui supprime les charactères invisibles (de type \n, tabulations...) dans une réponse XML
 */
function PFW_clean(d)
{
	function go(c)
	{
		if(!c.data.replace(/\s/g,''))
			c.parentNode.removeChild(c);
	}
	
	var bal=d.getElementsByTagName('*');

	for(i=0;i<bal.length;i++)
	{
		a=bal[i].previousSibling;
		if(a && a.nodeType==3)
			go(a);
		b=bal[i].nextSibling;
		if(b && b.nodeType==3)
			go(b);
	}
	return d;
}

/***************************************************************************************************/
/***************************************************************************************************/

/**
 * Fonction qui remplace la propriété innerHTML de n'importe quel élément
 * le but étant de pouvoir ajouter des sous éléments à un <table> (<thead>, <tbody>, <tr>, <td>) sous IE
 * (le innerHTML sur un <table> ne fonctionne pas correctement sous IE6)
 */
function PFW_customInnerHTML(id_dest, html)
{
	is_table_content= false;
	var dest= document.getElementById(id_dest);
	
	// Si l'element dont on doit rafraichir le contenu n'est pas present dans la page, on retourne false
	if(!dest)
	{
		return false;
	}
	
	// On detecte le type de balise de l'element dont on doit rafraichir le contenu
	// On recherche une balise de type table pour adapter le comportement de la fonction
	destTagName= dest.tagName.toLowerCase();
	if(destTagName=='table' || destTagName=='tr' || destTagName=='tbody' || destTagName=='thead' || destTagName=='tfoot')
	{
		is_table_content= true;	
	}
	
	// L'element dont on doit rafraichir le contenu est effectivement de type table ...
	if(is_table_content)
	{
		// On récupère le type de la première balise du contenu HTML a insérer
		var res= html.match(/<([a-z]+)/i);
		if(res && res[1])
		{
			balise= res[1];
		}
		// S'il n'y a aucune balise on assimile le cas à celui de la balise TD
		else
		{
			balise= 'td';
		}
			
		var content;
		
		// On recréée une table complète à partir du code HTML a insérer
		if(balise== 'td')
		{
			content='<table way_to_container="yes"><tbody way_to_container="yes"><tr is_searched_container="yes">'+ html +'</tr></tbody></table>';
		}
		else if(balise== 'tr')
		{
			content='<table way_to_container="yes"><tbody is_searched_container="yes">'+ html +'</tbody></table>';
		}
		else
		{
			content='<table is_searched_container="yes">'+ html +'</table>';
		}
		
		// On crée un élément temporaire qui autorise l'usage de innerHTML pour lui insérer via cette méthode, la table recréée précedemment
		// Le but de cette manipulation est d'obtenir une table qui soit parsable en DOM
		var container= document.createElement("div");
		container.innerHTML= content;
	
		// On parcourt desormais en DOM le sous arbre DOM ainsi obtenu à la recherche du contenu que l'on doit insérer
		// (l'équivalent DOM en fait du code html passé à la fonction PFW_customInnerHTML)
		var to_see=container;
		var found= null;
		while(to_see!=null)
		{
			var elem= to_see;
			to_see= null;
			
			for (var i=0;i<elem.childNodes.length;i++)
			{
				// On a trouvé le noeud qui contient notre code html ...
				if(elem.childNodes[i].getAttribute("is_searched_container")=="yes")
				{
					var src= elem.childNodes[i];
					
					// On supprime le contenu de l'element que l'on doit rafraichir
					while(dest.childNodes.length>0)
					{
						dest.removeChild(dest.childNodes[0]);
					}
					// On ajoute dans l'element que l'on doit rafraichir les noeuds DOM du contenu HTML passés à la fonction
					while(src.childNodes.length>0)
					{
						dest.appendChild(src.childNodes[0]);
					}
				}
				// On n'a pas trouvé le noeud qui contient notre code html à ajouter, on poursuit la recherche ...
				else if(elem.childNodes[i].getAttribute("way_to_container")=="yes")
				{
					to_see= elem.childNodes[i];
				}
			}
		}
	}
	// Si le contenu HTML a insérer n'est pas de type table, on utilise la méthode innerHTML classique
	else
	{
		dest.innerHTML= html;
	}
}