/****
 Global vars
*******/
var IS_IE = document.all && window.print && !window.opera && ( !document.compatMode || /MSIE 6/.test(navigator.userAgent) || (document.compatMode && document.compatMode=="BackCompat"));
var IE_NG = document.all && window.print && !window.opera && /MSIE [7-9]/.test(navigator.userAgent) && document.compatMode && document.compatMode!="BackCompat"; //variable pour IE7 et + si besoin.
var IS_quirks = IS_IE && document.compatMode && document.compatMode=="BackCompat"; // variable qui declare le quirksmode seulement utile pour IE
var heightPropertyToUse = IS_IE ? "height" : "minHeight"; //variable utilisee pour l'alignement en hauteur des elements.
var IS_Webkit = /Konqueror|Safari|KHTML/.test(navigator.userAgent); 

//ajoute la classe hasJS si le JS est active sur le navigateur
document.documentElement.className+=" hasJS";
if (IS_IE) document.documentElement.className+=" IS_IE";


/*******
* Framework : 
* Fonctions necessaires au fonctionnement general. Elles apportent une aide supplementaire pour le developpement d'autres fonctions. Ces fonction sont utilisees par toutes les autres.
*********/

// $() : remplacement de document.getElementById();
function $(str) {
	return (typeof str == "string") ? document.getElementById(str) : str;
}

function addEvent( obj, type, fn ) {
	if (obj.addEventListener)
			obj.addEventListener( type, fn, false );
	else if (obj.attachEvent) {
		   obj["e"+type+fn] = fn;
		   obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
		   obj.attachEvent( "on"+type, obj[type+fn] );
	}
}

function removeEvent( obj, type, fn ) {
	if (obj.removeEventListener)
		obj.removeEventListener( type, fn, false );
	else if (obj.detachEvent) {
		obj.detachEvent( "on"+type, obj[type+fn] );
		obj[type+fn] = null;
		obj["e"+type+fn] = null;
	}
}

function handleEvent(event) {
    var returnValue = true;
    event = event || fixEvent(window.event);
    var handlers = this.events[event.type];
    for (var i in handlers) {
        this.$$handleEvent = handlers[i];
        if (this.$$handleEvent(event) === false) {
            returnValue = false;
        }
    }
    return returnValue;
};

function fixEvent(event) {
    event.preventDefault = fixEvent.preventDefault;
    event.stopPropagation = fixEvent.stopPropagation;
    return event;
};
fixEvent.preventDefault = function() {
    this.returnValue = false;
};
fixEvent.stopPropagation = function() {
    this.cancelBubble = true;
};
cancelBubble = function(e){
	if (window.event){
		window.event.cancelBubble = true;
		window.event.returnValue = false;
		return;
	}
	if (e){
		e.stopPropagation();
		e.preventDefault();
	}
}


/* supprime la propagation du click sur un &eacute;l&eacute;ment (le click n'est pas r&eacute;percut&eacute; sur les autres &eacute;l&eacute;ments en dessous du block en question) */
cancelClick = function(e){
	if (window.event){
		window.event.cancelBubble = true;
		return;
	}
	if (e){
		if (e.stopPropagation) {
			e.stopPropagation();
		}
	}
}


function getElementsByClassName(oElm, sTagName, sClassName){
	var aElements = (sTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(sTagName);
	var aReturnElements = new Array();
	sClassName = sClassName.replace(/\-/g, "\\-");
	var oRegExp = new RegExp("(^|\\s)" + sClassName + "(\\s|$)");
	var oElement;
	for(var i=0; i < aElements.length; i++){
		oElement = aElements[i];
		if(oRegExp.test(oElement.className))
			aReturnElements.push(oElement);
	}
	return aReturnElements
}

// getStyle : retourne la valeur d'une propriete CSS appliquee a un element
function getStyle(oElm, strCssRule){
	var strValue = "";
	if(document.defaultView && document.defaultView.getComputedStyle) {
		try{ 
			strValue = document.defaultView.getComputedStyle(oElm, null).getPropertyValue(strCssRule); 
		}
		catch(e) { strValue = ""; }
	}
	else if(oElm.currentStyle) {
		try{
			strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
				return p1.toUpperCase();
			});
			strValue = oElm.currentStyle[strCssRule];
		} catch(e) {
			strValue = "";
		}
	}
	return strValue;
}

/*retourne la valeur entiere d'un style*/
function intStyle(oElm, strCSSRule) {
	var val = parseInt(getStyle(oElm, strCSSRule));
	if (isNaN(val)) val=0;
	return val;
}

/* retourne la somme de tous les styles verticaux appliques (border-width+padding) */ 
function getVStyles(elm) {
	return IS_quirks ? 0 : intStyle(elm, "border-top-width")+intStyle(elm, "border-bottom-width")+intStyle(elm, "padding-top")+intStyle(elm, "padding-bottom");
}
function getHStyles(elm) {
	return IS_quirks ? 0 : intStyle(elm, "border-left-width")+intStyle(elm, "border-right-width")+intStyle(elm, "padding-left")+intStyle(elm, "padding-right");
}
//removeClass
function removeClass(element, className) {
	element.className = element.className.replace(new RegExp("\\b"+className+"\\b","g"),"");
};

//addClass
function addClass(element, className) {
	element.className += " " + className;
};

//toggleClass
function toggleClass(element, className, classNameReplace) {
	element.className = element.className.replace(new RegExp("\\b"+className+"\\b","g"), classNameReplace);
};

function findPos(obj) {
	var curleft = curtop = 0;
	if (obj.offsetParent) {
		curleft = obj.offsetLeft
		curtop = obj.offsetTop
		while (obj = obj.offsetParent) {
			curleft += obj.offsetLeft
			curtop += obj.offsetTop
		}
	}
	return [curleft,curtop];
}

/* openclose */
function openclose(elm) {
	var par = getParent(elm, {className:"content(show|hide)"});
	par.className.match(/contenthide/) ? toggleClass(par, "contenthide", "contentshow") : toggleClass(par, "contentshow", "contenthide");
	fixColumns();
}

/**********
* $n : objet de parcours du DOM, facile. Les fonctions ne font que les nodes HTML
***********/
var $n = {
	/* 	hasAttributes : retourne true si l'element passe en parametre correspond a tous les attributs passes, on peut aussi donner des attributs que l'on ne veut pas, afin de filtrer tous les &eacute;lements
		ex : if (hasAttributes(div, {nodeName:"div", className:"foobar"), {className:"idontwant"} ) doStuff();
		ici on recherche tous les DIV qui on la classe "foobar", mais on ne prend pas ceux qui ont la classe "idontwant" ex : <div class="foobar idontwant"> ne sera pas recupere.
	*/
	hasAttr : function(n, a, not) {
		var re, at;
		if (n.nodeType!=1) return false;
		function check(attr) {
			for (var i in attr) {
				at = (typeof n[i]) !="undefined" ? n[i] : n.getAttribute(i);
				re = attr[i] instanceof RegExp ? re : new RegExp("\\b" + attr[i] + "\\b","i");
				if (!at || !re.test(at)) 
					return false;
			}
			return true;
		};
		if (not && check(not))	return false;
		if (check(a)) return true;
		return false;
	},
	/* getByTagName : equivalent a element.getElementsByTagName, mais compatible avec IE5 et IE5.5 pour l'histoire du "*" */
	getByTagName : function(n, tag) {
		return  (tag=="*") ? (n.all ? n.all : n.getElementsByTagName("*")) : n.getElementsByTagName(tag);
	},
	/* fonction qui retourne le premier element correspondant aux attributs donnes */
	node : function(n, a, not) {
		return $n.nodes(n, a, not, true);
	},
	/* fonction qui retourne tous les elements correspondant selon "a" */
	nodes : function(n, a, not, oneNode, arrElms) {
		var aRetElms=[];
		if (!a) a = {};
		if (typeof a == "string") a = {nodeName:a}; //si une chaine de caract&egrave;res pass&eacute;e en param&egrave;tre, cela signifie qu'on ne veut que r&eacute;cup&eacute;rer des tags
		if (a.nodeName && a.nodeName=="*") delete a.nodeName;
		var elms = arrElms || $n.getByTagName(n, (a.nodeName || "*"));
		for (var i=0; i<elms.length; i++) {
			var x = elms[i];
			if ($n.hasAttr(x, a, not)) {
				if (oneNode) return x;
				else aRetElms.push(x);
			}
		}
		if (oneNode) return null;
		return aRetElms;
	},
	/* childs : retourne tous les noeuds enfants de l'element  */
	childs : function(n, a, not) {
		return $n.nodes(n, a, not, false, n.childNodes);
	},
	firstChild : function(n, a, not) {
		return $n.nodes(n, a, not, true, n.childNodes);
	},
	lastChild : function(n, a, not) {
		var node = $n.nodes(n, a, not, false, n.childNodes);
		return node[node.length-1];
	},
	move : function(n, a, not, action) {
		while (n) {
			if ($n.hasAttr(n, a, not)) return n;
			n = n[action];
		}
		return null;
	},
	after : function(n, a, not) { 
		return $n.move(n, a, not, "nextSibling");
	},
	before : function(n, a, not) {
		return $n.move(n, a, not, "previousSibling");
	},
	parent : function(n, a, not) {
		return $n.move(n, a, not, "parentNode");
	}
}
/* fonctions raccourcis */
var getNode = $n.node,
	getNodes = $n.nodes,
	getChildNodes = $n.childs,
	getNextSibling = $n.after,
	getPreviousSibling = $n.before,
	getParent = $n.parent,
	hasAttributes = $n.hasAttr,
	getElementsByTagName = $n.getByTagName;



/*****************
* domLoad et onload fonctions
* Ces fonctions permettent de lancer des fonctions en 2 temps
* - Soit pendant le chargement de la page (mais le DOM est construit)
* - Soit une fois que la page est construite
*****************/
/* domload functions 
  utilisation : 
	Si on veut rajouter une fonction pendant le chargement de la page : addDomLoadFunc(myfunc), ou addDomLoadFunc(function() {myfunc(param1, param2) };
	Si on veut rajouter une fonction une fois la page charge (onload)  : addOnloadFunc(myfunc), ou addOnloadFunc(function() {myfunc(param1, param2) };
	il y a aussi les fonctions domLoadFunctions() et onLoadFunctions() qui peuvent contenir toutes les autres fonctions a lancer.
*/
domLoadBottomDivId = "footer"; // l'id du div qui est en bas de la page. S'il n'y est pas, la fonction est quand meme executee

/* variables globales (arrays et booleens) qui permettent de gerer le lancement des fonctions domload et onload */
var domLoaded=false;
var domMustLaunch=false;
var domLoadFunctionLaunched=false;
var domLoadTimer=null;
var domLoadArrFunctions=[];
var onLoadArrFunctions=[];

/* 	domLoad() : Cette fonction attend que le dom soit totalement construit */
function domLoad() {
	if(document.getElementById(domLoadBottomDivId)) {
		domLoadCaller();
	} else {
		domLoadTimer=setTimeout("domLoad()",10);
	}
};
domLoad();

/* 	domLoadCaller() :  gere le lancement de la fonction finale domLoadFunctions();
	domLoadCaller() lances les fonctions contenues dans un array de fonctions et gere le fait que domLoad doit etre lance avant le onload
*/
function domLoadCaller() {
	domLoadFunctionLaunched=true;
	for (var i=0; i<domLoadArrFunctions.length; i++) {
		domLoadArrFunctions[i]();
	}
	domLoadFunctions();
	domLoaded=true;
	if(domMustLaunch) {
		onloadCaller();
	}
};

/* 	onloadCaller() : gere le lancement de la fonction finale onLoadFunctions(); Cet fonction est &eacute;x&eacute;cut&eacute;e une fois que la page est chargee */
function onloadCaller() {
	clearTimeout(domLoadTimer);
	if (!domLoadFunctionLaunched) {
		domLoadCaller();
	}
	if (!domLoaded) {
		domMustLaunch=true;
		return;
	}
	for (var i=0; i<onLoadArrFunctions.length; i++) {
		onLoadArrFunctions[i]();
	}
	onLoadFunctions();
}

/*  addDomLoadFunc() :  permet d'ajouter facilement une fonction qui sera lancee avant avant le chargement complet de la page. 
	ex : 
		function myfunc() {
			//contenu fonction.
		}	
		addDomLoadFunc(myfunc) // il ne faut pas mettre les parentheses, car ici on passe une fonction en parametres.
		
	Si on veut lancer la fonction avec des parametres, il faut passer par une fonction anonyme.
	ex : 	
		addDomLoadFunc(  
			function () {  myfunc("foo", "bar");  }
		);
*/
function addDomLoadFunc(f) {
	domLoadArrFunctions.push(f);
}
/* 	addOnLoadFunc() : permet d'ajouter facilement une fonction qui sera lancee une fois la page chargee. */
function addOnLoadFunc(f) {
	onLoadArrFunctions.push(f);
}

//on lance la fonction onloadCaller une fois la page chargee.
addEvent(window, "load", onloadCaller);


/*  ifrlayer : 
	Cette fonction corrige un probleme sous IE6 lorsqu'un layer passe par dessus un select, le select sera toujours au dessus. Pour corriger ce probl&egrave;me.
	ex : 	
		- afficher un bloc : 
			myBlock.style.display='block';
			ifrlayer.make(myBlock); //genere ou affiche l'iframe
		- cacher un bloc :
			myBlock.style.display='none';
			ifrlayer.hide(myBlock); //cache l'iframe associee au bloc
		-deplacer un bloc : 
			myBlock.style.left = "100px";
			ifrlayer.move(myBlock); // deplace l'iframe associee au bloc
*/
var ifrlayer = {
    make:function(obj) {
        if(!obj) return; obj = (typeof(obj)=="string") ? document.getElementById(obj) : obj; if(!obj) return;
        if(document.all && window.print && document.getElementById && !obj.iframelayer ) {
            if(obj.parentNode && !obj.iframelayer) var ifr = obj.parentNode.insertBefore(document.createElement("iframe"), obj);
            ifr.src = "javascript:false";
            if(obj.currentStyle.zIndex != "" && parseInt(obj.currentStyle.zIndex)>1 ) {
                ifr.style.zIndex = parseInt(obj.currentStyle.zIndex)-1;
            }
            with(ifr.style) {
                filter = "mask()";
                position = "absolute";
            }
            obj.iframelayer = ifr;
        }
        if (obj.iframelayer) {
            obj.iframelayer.style.visibility = "visible";
            ifrlayer.move(obj,true);
        }
    },
    hide:function(obj){
		if(!obj) return; obj = typeof(obj)=="string" ? document.getElementById(obj) : obj; if (!obj) return;
        if(obj.iframelayer) {
            obj.iframelayer.style.visibility="hidden";
        }
    },
    kill:function(obj){
        if(!obj) return; obj = typeof(obj)=="string" ? document.getElementById(obj) : obj; if (!obj) return;
        if(obj.iframelayer) {
            obj.iframelayer.parentNode.removeChild(obj.iframelayer);
			obj.iframelayer = null;
        }
    },
    move:function(obj, size) {
        if(obj && obj.iframelayer) {
            with(obj.iframelayer.style) {
                top = obj.offsetTop+"px";
                left = obj.offsetLeft+"px";
                if (size) {
                    width  =  obj.offsetWidth+"px";
                    height =  obj.offsetHeight+"px";
                }
            }
        }
    }
}
/*  addHover :
   Cette fonction ajoute le fonctionnement de la pseudo classe hover en CSS, et seulement pour IE
   Elle se base sur les evenement propres a IE qui sont les evenements qui ont le comportement le plus proche du :hover en CSS.
   Pour utiliser cette fonction il faut le faire en CSS, on peut en plus ajouter en parametre la classe CSS qui sera ajoutee en CSS
   ex :
       #menu ul li {behavior:expression(addHover(this))}
       #menu ul li {behavior:expression(addHover(this, "maclassehover"))}
       Afin de ne pas prendre en compte IE7 en mode strict il suffit de placer la classe .IS_IE avant, cette classe est ajoutee pendant le chargement de la page.
       .IS_IE #menu ul li {behavior:expression(addHover(this))}
*/
function addHover(elm, className, iframeTag) {
	className = className || "hover";
	elm.style.behavior = " "; //reecriture du style behavior
	elm.hoverClassName = className;
	if (iframeTag) {
		elm.iframeElm = getNode(elm, iframeTag);
	}
	elm.onmouseenter = function() {
	   this.className+= ' ' + this.hoverClassName;
	   if (this.iframeElm) ifrlayer.make(this.iframeElm);
	}
	elm.onmouseleave = function() {
	   this.className = this.className.replace(new RegExp("\\b" + this.hoverClassName + "\\b", "g"),"");
	   if (this.iframeElm) ifrlayer.hide(this.iframeElm);
	}
}

/*************
* Fonctions pour fixer les coins sous IE
* Une fonctions est prevue aussi pour Safari 2.0, Opera 8.5 et FF 1.0 pour certains cas
**************/
var CSSBottomCorners=[]; //array pouvant contenir les coins absolu positionnes en bottom
var CSSHeightCorners=[]; //array pouvant contenir les listes des blocks dont les coins font 100% de la hauteur
var currentBlockToFixCorners=null; //variable gloable utilisee lorsqu'on veux fixer les coins sur un seul bloc

/*  cssRight : 
	fixe les coins positionnes en absolu a droite
	ex : 
		body.IS_IE .tr {right:expression(addHover(this))}
		Il faut afin que cela fonctionne, avoir declare le right dans un selecteur precedent (pour les autres navigateurs).
		ex : .tr {height:5px;  width:5px; right:0}
		Afin de ne pas prendre en compte IE7 en mode strict il suffit de placer la classe .IS_IE avant, cette classe est ajoutee pendant le chargement de la page et n'est ajoutee que pour IE5.x ou 6.
*/
function cssRight(elm) {
	if (elm.currentStyle.right!="auto") {
		elm.style.right = (parseInt(elm.currentStyle.right)-(elm.parentNode.offsetWidth%2))+"px";
	} else {
		elm.style.right = "auto";
	}
}
 
/*  cssBottom :  (comme CSS right avec un parametre supplementaire)
	fixe les coins positionnes en absolu a droite
	ex : 
		body.IS_IE .br {bottom:expression(addHover(this))}
	Il faut afin que cela fonctionne, avoir declare le right dans un selecteur precedent (pour les autres navigateurs).
	Afin de ne pas prendre en compte IE7 en mode strict il suffit de placer la classe .IS_IE avant, cette classe est ajoutee pendant le chargement de la page et n'est ajoutee que pour IE5.x ou 6.
	
	Si on veut rajouter ces coins dans un array qui permettra de les refixer si le bloc s'agrandit ou autre. il suffit de rajouter "true" dans les parametres.
	ex : 
		body.IS_IE .br {bottom:expression(addHover(this, true))}
*/
function cssBottom(elm, pushElement) {
	if (pushElement && !elm.CSSBottomAlreadyCSS) {
		CSSBottomCorners.push(elm);
		elm.CSSBottomAlreadyCSS=true;
	}
	if (elm.currentStyle.bottom!="auto") {
		elm.style.bottom = (parseInt(elm.currentStyle.bottom)-(elm.parentNode.offsetHeight%2))+"px";
	} else {
		elm.style.bottom = "auto";
	}
}

/*  fixCorners : 
	Cette fonction  est appelee lorsque l'on doit fixer tous les coins d'une page ou d'un block.
	ex : 
		fixCorners ();  //Lance la fonction pour fixer tous les blocks, il faut lancer la fonction une fois la page chargee.
		fixCorners(block); //en passant un element en parametre, le traitement ne se fera que sur le bloc et non sur toute la page.
*/
function fixCorners(block) {
	if (IS_IE) {
		for (var i=CSSBottomCorners.length-1; i>-1; --i) {
			CSSBottomCorners[i].style.bottom="";
		}
	} else {
		if (IS_Webkit || /Gecko\/200[56]|Opera 8.5/i.test(navigator.userAgent)) fixCornersOnBlocks(block);
	}
}

/* 
	fixCornersOnBlocks : 
	Ajoute une classe CSS hidecorners afin de cacher les coins puis les reafficher.
	Cette fonction n'est lancee que pour Safari, Le moteur Gecko 2005 (FF1.0) et Opera 8.5), car lorsqu'on agrandit un block en Javascript, les coins en absolu positionnes en bas restent a leur place. Cette fonction corrige le probleme.
*/
function fixCornersOnBlocks(block) {
	currentBlockToFixCorners = block || document.body;
	currentBlockToFixCorners.className+=" hidecorners";
	setTimeout(fixCornersOnBlocksShowCorners,5);
}

/* 
	fixCornersOnBlocksShowCorners : 
	Fonction associee a fixCornersOnBlocks(), cette fonction retire la classe hidecorners qui a ete appliquee a currentBlockToFixCorners
*/
function fixCornersOnBlocksShowCorners() {
	if (currentBlockToFixCorners) currentBlockToFixCorners.className=currentBlockToFixCorners.className.replace(/\bhidecorners\b/g,"");
	currentBlockToFixCorners=null;
}
/* height Corners : coins qui font tout le tour d'un bloc */
function cssHeight(elm, pushElement) {
	if (pushElement && !elm.CSSHeightAlreadyCSS) {
		CSSHeightCorners.push(elm);
		elm.CSSHeightAlreadyCSS=true;
	}
	elm.style.height = elm.parentNode.offsetHeight+"px";
}

function fixHeights(block) {
	if (IS_IE) {
		var array = block ? getNodes(block, {nodeName:"b", className:"tr|bl"}) : CSSHeightCorners;
		array.eachInv(function(x) {
			x.style.height="";
		});
	}
}

/* fixAll(action, element) : fonction raccourci pour lancer tout ce qu'on a besoin (fixHeight, fixColumns, fixCorners)
	action : fonction à lancer
		- 'h' ; fixHeight (fixe les coté spéciaux des blocs sous IE6)
		- 'c' : fixCorners (fixe les corners sous IE6)
		- 'p' : fixColumns (correspond à la page en general;
	on peut aussi cumuler : fixAll('hcp', element)
	element : element parent
	
*/
function fixAll(actions, element) {
	actions = actions ? actions.toLowerCase().split('') : ['c','h','p'];
	actions.each(function(action) {
		switch(action) {
			case 'c' : fixCorners(element); break;
			case 'h' : fixHeights(element); break;
			case 'p' : fixColumns(element); break;
		}
	});
}

/********************
* Extensions d'objets 
 ********************/
var extend = function (object, extender) {
	var props = extender || {}; // fail-safe
	for (var property in props) {
		object.prototype[property] = props[property];
	}
	return object;
};

Array.Utils = {
	each : function(f) {
		var i;
		for(i=0;i<this.length;i++) {
			f(this[i]);
		}
	},
	eachInv : function(f) {
		var i;
		for(i=this.length-1;i>=0;i--) {
			f(this[i]);
		}
	},
	last : function() {
		return this.length>0 ? this[this.length-1] : null;
	}
};
extend(Array,Array.Utils);

/****************
* Validation de formulaires
******************/
var formval = {
    defaultErrorMessage:"Ce champ est erron\u00E9",
    defaultPosition:"beforefield",
    globalErrorMsg : "",
    callbackfunctions : function() {
        fixColumns();
        if (popLayer.pop) {
            popLayer.resize();
        }
    },
    lineInput : {nodeName:"(div|p|li)"},
    validationFunc:{
        requiredgroup:function(field) {
            var self = this;
            var returnMessage = true;
            var allFields = field.getAttribute('requiredgroupothers').split(',');
            allFields.push(field);
            allFields.each(function(field) {
                field = $(field);
                if (self.required(field) != true) {
                    returnMessage = false;
                }
            });
            return returnMessage;
        },
        required:function(field) {
            var returnMessage = true;
            switch (field.type) {
                case "text":
                case "file":
                case "password":
                case "textarea":
                    if (field.value == "") {
                        returnMessage = "text";
                    }
                    break;
                case "checkbox":
                case "radio":
                    var sameElt = formval.getSameElements(field);
                    var onecheck = false;
                    for (var i = 0; i < sameElt.length; i++) {
                        if (sameElt[i].checked) {
                                onecheck = true;
                            }
                    }
                    if (!onecheck) {
                        returnMessage = field.type;
                    }
                    break;
                case "select-one":
                case "select-multiple":
                    if (field.selectedIndex == 0) {
                            returnMessage = "select";
                        }
                    break;
            }
            return returnMessage;
        },
        email:function(field) {
            return (field.value == "" || !!field.value.match(/^[a-z0-9._-]+@[a-z0-9.-]{2,}[.][a-z]{2,3}$/i));
        },
        name:function(field) {
            return (field.value == "" || !!field.value.match(/^([a-zA-Z]|\s|\'|\.|\-)+$/));
        },
        pseudo:function(field) {
            return !!field.value.match(/^[a-zA-Z0-9_\-]{3,20}$/);
        },
        image:function(field) {
            return (field.value == "" || !!field.value.match(/^.+\.(gif|jpe?g|png)$/));
        },
        codepostal:function(field) {
            return !!field.value.match(/\d{5}/);
        },
        cpordep:function(field) {
            if (field.value == "") { return true; }
            return !!field.value.match(/\d{2}(\d{3})?/);
        },
        phonenumber:function(field) {
            if (field.value == "") { return true; }
            return !!field.value.match(/^\d{10}$/);
        },
        rio:function(field) {
            if (field.value == "") { return true; }
            return (!!field.value.replace(/\W|_/gi, "").match(/^[\dA-Za-z]{12}$/));
        },
        phonenumber2:function(field) {
            var val = field.value;
            if (val == "") { return true; }
            var cleanNum = val.match(/(\+)?\d+/g);
            if (!cleanNum) { return false; }
            cleanNum = cleanNum.join(""); //on recupere le numero de telephone en version nettoyee.
            if (!cleanNum.match(/^\+?(33|033|0033)?0?[1-9]\d{8}$/)) { return false; } //on checke reelement le numero de telephone
            return !!val.match(/^(\d|\s|-|\.|\\|\/|_|\+)+$/); //on check si des caract&egrave;res autres que chiffes,-,+,.,_,/,\  sont pr&eacute;sents
        },
			fax:function(field) {
            var val = field.value;
            if (val == "") { return true; }
            var cleanNum = val.match(/(\+)?\d+/g);
            if (!cleanNum) { return false; }
            cleanNum = cleanNum.join(""); //on recupere le numero de telephone en version nettoyee.
            if (!cleanNum.match(/^\+?(33|033|0033)?0?[1-9]\d{8}$/)) { return false; } //on checke reelement le numero de telephone
            return !!val.match(/^(\d|\s|-|\.|\\|\/|_|\+)+$/); //on check si des caract&egrave;res autres que chiffes,-,+,.,_,/,\  sont pr&eacute;sents
        },
        numbers:function(field) {
            if (field.value == "") { return true; }
            return !!field.value.match(/^\d+$/);
        },
        numcommande:function(field) {
            if (field.value == "") { return true; }
            return !!field.value.match(/\d{10}/);
        },
        alphanum:function(field) {
            if (field.value == "") { return true; }
            return !!field.value.match(/^[\dA-Za-z]+$/);
        },
        decimal:function(field) {
            if (field.value == "") { return true; }
            return !!field.value.match(/^\d+([.,]\d+)?$/);
        },
        equalsto:function(field) {
            var equalsFieldId = field.getAttribute("equalsto");
            var equalsField = document.getElementById(equalsFieldId);
            return (field.value == equalsField.value);
        },
        minimum:function(field) {
            if (field.nodeName != "FIELDSET") { return true; }
            var minNum = field.getAttribute("minimum_num") || 1;
            var properties = field.getAttribute("minimum_field") || "text,femail";
            properties = properties.split(/,/g);
            var inputs = field.getElementsByTagName("input");
            var counter = 0;
            for (var i = 0; i < inputs.length; i++) {
                var x = inputs[i];
                if (x.type == properties[0] && new RegExp(properties[1]).test(x.name) && x.offsetHeight > 0) {
                    if (formval.validationFunc["required"](x) === true) {
                        counter++;
                    }
                }
            }
            return counter < minNum ? ([false,minNum]) : true;
        },
        minimumLetter:function(field) {
            if (field.value == "") { return true; }
            var minLength = field.getAttribute("minlength");
            return  (field.value.length >= minLength) ? true : [false,minLength];
        },
        requiredexclusif:function(field) {
            var reqExclusifField = document.getElementById(field.getAttribute("reqexclusiffield"));
            if (!reqExclusifField) {
                alert("Vous n'avez pas associe le bon champ, verifiez l'attribut reqexclusif");
                return false;
            }
            if (field.getAttribute("requiredexclusifcondition")) {
                if (field.getAttribute("requiredexclusifcondition") == "noempty") {
                    return field.value != "" || reqExclusifField.value != "";
                }
            } else
                if ((field.value == "" && reqExclusifField.value == "") || (field.value != "" && reqExclusifField.value != "")) { return false; }
        },
        siret : function(field) {
            var siret = field.value;
            if (siret == "") { return true; }
            var estValide;
            if ((siret.length != 14) || (isNaN(siret))) {
                    estValide = false;
            } else {
                // Donc le SIRET est un numérique à 14 chiffres
                // Les 9 premiers chiffres sont ceux du SIREN (ou RCS), les 4 suivants
                // correspondent au numéro d'établissement
                // et enfin le dernier chiffre est une clef de LUHN.
                var somme = 0;
                var tmp;
                for (var cpt = 0; cpt < siret.length; cpt++) {
                    if ((cpt % 2) == 0) { // Les positions impaires : 1er, 3è, 5è, etc...
                        tmp = siret.charAt(cpt) * 2; // On le multiplie par 2
                        if (tmp > 9) {
                            tmp -= 9; // Si le résultat est supérieur à 9, on lui soustrait 9
                        }
                    } else {
                        tmp = siret.charAt(cpt);
                    }
                    somme += parseInt(tmp);
                }
                estValide = ((somme % 10) == 0 && somme != 0); // Si la somme est un multiple de 10 alors le SIRET est valide
            }
            return estValide;
        }
    },
    errorMessages:{
        required:{
            checkbox:"Cette case doit \u00EAtre coch\u00E9e",
            radio:"Vous devez s\u00E9lectionner une de ces options",
            text:"Attention, ce champ est obligatoire",
            select:"Vous devez s\u00E9lectionner l\u0027objet de votre demande"

        },
        requiredoptional:this.required,
        email:"Cette adresse e-mail est erron\u00E9e",
        name:"Ce champ ne doit comporter que des lettres, et les caract&egrave;res suivants : '-'",
        numbers:"Ce champ ne doit comporter que des chiffres",
        numcommande:"Le num&eacute;ro de commande doit comporter 10 chiffres",
        alphanum:"Ce champ ne doit comporter que des chiffres et/ou des lettres",
        decimal:"Ce champ ne doit comporter que des chiffres",
        phonenumber:"Ce champ ne doit comporter que des chiffres",
        phonenumber2:"Veuillez v\u00E9rifier votre num\u00E9ro de t\u00E9l\u00E9phone",
		fax:"Veuillez v\u00E9rifier votre num\u00E9ro de fax",
        equalsto:"Ce champ doit &ecirc;tre identique au pr&eacute;c&eacute;dent",
        codepostal:"Ce code postal est erron\u00E9",
        cpordep:"Vous ne pouvez mettre qu'un num\u00E9ro de d\u00E9partement ou un code portal",
        pseudo:'Attention, votre pseudo doit contenir uniquement 20 caract&egrave;res, des lettres et des num\u00E9ros et les signes "_" et "-"',
        image:"Votre fichier n'est pas au bon format",
        minimum:"Vous devez remplir au moins ## champ",
        minimumLetter:"Vous devez remplir au moins ## caract&egrave;res",
        requiredexclusif:"Vous devez remplir au moins un des champs",
        siret:"Le num\u00E9ro siret n'est pas valide",
        rio:"Le code rio n\u0027est pas valide (12 caract&egrave;res)"
    },
    getMessagePosition:function(field) {
        var element = field;
        var position = "";
        if (field.getAttribute("position")) {
            position = field.getAttribute("position");
            if (!position.match(/^(before|after)(label|parentnode|field)$/)) {
                position = formval.defaultPosition;
            }
            var arrPos = position.match(/^(before|after)(label|parentnode|field)$/);
            switch (arrPos[2]) {
                case "label" :
                    var node = field;
                    while (node.nodeName != "LABEL") {
                        node = node.previousSibling;
                    }
                    if (node.nodeName == "LABEL") { element = node; }
                    break;
                case "parentnode" :
                    var parentPos = field.getAttribute("parentnode_pos") ? parseInt(field.getAttribute("parentnode_pos")) : 1;
                    element = field;
                    for (var i = 0; i < parentPos; i++) {
                        element = element.parentNode;
                    }
                    break;
            }
            return [arrPos[1],element];
        } else {
            return [formval.defaultPosition.match(/(before|after)(label|parentnode|field)/)[1],element];
        }
    },
    getSameElements:function(field) { //return an array of elements in form who have same nodeName, name and type
        var aReturnElements = [];
        var elt = field.form.elements;
        for (var i = 0; i < elt.length; i++) {
            if (elt[i].nodeName == field.nodeName && elt[i].name == field.name && elt[i].type == field.type) {
                aReturnElements.push(elt[i]);
            }
        }
        return aReturnElements;
    },
    check:function(theForm, showOnlyOneMessage, otherReturnValues) {
        formval.globalErrorMsg = "";
        var scrollTop = document.body.scrollTop;
        var finalErrorMessage = "";
        var hasError = false;
        var elm = theForm.elements;
        for (var i = 0; i < elm.length; i++) {
            var x = elm[i];
            if (x.getAttribute("validation") && x.offsetHeight && x.offsetHeight > 0 && !x.disabled) {
                var validOptions = x.getAttribute("validation").split(/\s+/g);
                finalErrorMessage = "";
                for (var j = validOptions.length - 1; j >= 0; j--) {
                    if (typeof(formval.validationFunc[validOptions[j]]) == "function") {
                        var returnMessage = formval.validationFunc[validOptions[j]](x);
                        var quantity = typeof(returnMessage) == "object" && returnMessage.length ? returnMessage[1] : 0;
                        returnMessage = typeof(returnMessage) == "object" && returnMessage.length ? returnMessage[0] : returnMessage;
                        if (returnMessage == false || typeof(returnMessage) == "string") { //si message erreur ou index de tableau associatif
                            hasError = true;
                            if (x.getAttribute(validOptions[j] + "_em") != null) { //si le champ possede un message personnalis&eacute; pour l'erreur alors on affihce
                                finalErrorMessage = x.getAttribute(validOptions[j] + "_em");
                            } else { //sinon
                                if (typeof(returnMessage) == "string") { //si le message d'erreur est un index de tableau associatif
                                    finalErrorMessage = formval.errorMessages[validOptions[j]][returnMessage]; //on va chercher le message associ&eacute; &agrave; cet index
                                } else {
                                    if (formval.errorMessages[validOptions[j]] && typeof(formval.errorMessages[validOptions[j]]) == "string") { //si le message d'error est false
                                        finalErrorMessage = formval.errorMessages[validOptions[j]]; //alors on retourne le message d'erreur associ&eacute;
                                        if (quantity > 0) {
                                            finalErrorMessage = finalErrorMessage.replace(/\#\#/g, quantity);
                                        }
                                    } else {
                                        finalErrorMessage = formval.defaultErrorMessage;
                                    } //sinon on affiche le message d'erreur par d&eacute;faut pour tout champ
                                }
                            }
                        } else {
                            formval.clearMessage(x);
                        }
                    }
                }
                if (finalErrorMessage != "") {
                    formval.showMessage(x, finalErrorMessage);
                }
            }
        }
        document.body.scrollTop = scrollTop;
        var secondErrorValue = false;
        if (otherReturnValues != null) {
            if (typeof(otherReturnValues) == "boolean") {
                secondErrorValue = !otherReturnValues;
            } else {
                for (var i = 0; i < otherReturnValues.length; i++) {
                    if (!otherReturnValues[i]) {
                        secondErrorValue = true;
                    }
                }
            }
        }

        hasError = hasError || secondErrorValue;
        if (showOnlyOneMessage) {
            if (showOnlyOneMessage == true) {
                elm = null;
            } else {
                elm = document.getElementById(showOnlyOneMessage);
            }
            if (hasError) {
                //elm.className+=" errorAlertShow";
                alert(formval.globalErrorMsg);
            } else {
                if (elm) {
                    elm.className = elm.className.replace(/\berrorAlertShow\b/g, "");
                }
            }
        }
        formval.callbackfunctions();
        popLayer.fixSize();
        fixAll();
        return (!hasError); //return true si aucune erreur sinon false;
    },
    checkIfErrorMessageBefore:function(field) {
        var node = field;
        var i = 0;
        while (node.previousSibling && i <= 2) {
            if (node.nodeType == 1 && node.className.match(/\berrormsg\b/)) {
                return node;
            }
            node = node.previousSibling;
            i++;
        }
        return null;
    },
    clearMessage:function(field) {
        if (field.getAttribute("typemessage") && field.getAttribute("typemessage") == "aspect") {
            if (field.getAttribute("rel") && field.getAttribute("rel") != "") {
                var elm = document.getElementById(field.getAttribute("rel"));
                elm.className = elm.className.replace(/\berror\b/g, "");
            }
        } else {
            if (field.associatedErrorMessage) {
                field.associatedErrorMessage.style.display = "none";
            }
        }
    },
    insertAfter:function(parent, nodeToInsert, nodeInDom) {
        var node = parent.insertBefore(nodeToInsert, nodeInDom);
        parent.insertBefore(nodeInDom, nodeToInsert);
        return nodeToInsert;
    },
    showMessage:function(field, msg) {
        formval.globalErrorMsg += "- " + msg + "\n";
        if (field.getAttribute("typemessage") && field.getAttribute("typemessage") == "aspect") {
            if (field.getAttribute("rel") && field.getAttribute("rel") != "") {
                var elm = document.getElementById(field.getAttribute("rel"));
                elm.className += " error";
            }
        } else {
            if (!field.associatedErrorMessage) {
                if (!formval.checkIfErrorMessageBefore(field)) {
                    var pos = formval.getMessagePosition(field);
                    var parentField = getParent(field, formval.lineInput);
                    /*var label = getNode(parentField, {nodeName:"label"});
                         if (label)
                             var msgField = formval.insertAfter(label.parentNode, document.createElement("span"),label);
                         else*/
                    var msgField = formval.insertAfter(parentField.parentNode, document.createElement("span"), parentField);
                    msgField.className = "errormsg";
                    field.associatedErrorMessage = msgField;
                } else {
                    field.associatedErrorMessage = formval.checkIfErrorMessageBefore(field);
                }
            }
            field.associatedErrorMessage.innerHTML = msg;
            field.associatedErrorMessage.style.display = "";
			//<span class="errormsg">Attention, ce champ est obligatoire</span>
        }
    }
};

/* addFormActions */

/* Add maxlength on textareas */
function maxLengthOntextarea() {
	var container = document.body;
	var textareas = container.getElementsByTagName("textarea");
	for (var i=0; i<textareas.length; i++) {
		var x= textareas[i];
		if (x.getAttribute("maxlength")) {
			addEvent(x, "keyup", checkMaxlength);
			addEvent(x, "keydown", checkMaxlength);
			addEvent(x, "blur", checkMaxlength);
		}
	}
}
function checkMaxlength(e) {
	var maxL = parseInt(this.getAttribute("maxlength"));
	if (this.value.length>maxL) {
		this.value=this.value.substr(0,maxL);
		this.scrollTop = this.scrollHeight;
	}
}
/* /maxlength */


function formInput(inputId, attributes) {
	var inp = document.getElementById(inputId);
	if (!inp) { return; }
	for (var i in attributes) {
		inp.setAttribute(i,attributes[i]);
	}
}

//function initFormInputs() {
/*
	formInput("champemail", { validation : "required email", email_em : "Cette email n'est pas bon", type_message : aspect};
	formInput("champ", { validation : "required"};
*/
//}
//addEvent(window, "load", initFormInputs);

// ensure s is never undefined
var s;
var genericForms = {
    /**
     * Omniture tracking for generic form display/view
     * @param title the title of the generic form being viewed
     */
    'viewStats': function (title) {
        if(s) {
            s.tl(this, "o", "Affichage " + title);
        }
    },
    /**
     * Omniture tracking for generic forms submission
     *
     * @param form The generic form being submitted.
     * Requires that the form has a <code>@title</code> attribute.
     * @param options A map of validation options. The various options are:
     * <ul>
     *  <li><code>onValidates</code>: A function being executed when the form validates, the form is passed as first positional argument</li>
     *  <li><code>onDoesntValidate</code>: A function being executed when the form doesn't validate, the form is passed as first positional argument</li>
     * </ul>
     */
    'submitStats': function (form, options) {
        if(s) {
            s.tl(this, 'o', "Validation " + form.getAttribute("title"));
        }
        if (formval.check(form)) {
            if(options && options['onValidates']) {
                options['onValidates'](form);
            }
            return true;
        } else {
            if(options && options['onDoesntValidate']) {
                options['onDoesntValidate'](form);
            }
            return false;
        }
    }
};

var mires = {
    /**
     * Omniture tracking for mires
     * @param form the login form being submitted, requires that the form has a <code>@title</code> attribute
     */
    'submitStats': function (form) {
        if(s && form.getAttribute("title") && !form.getAttribute("title").match(/^\s+$/)) {
            s.tl(this, 'e', "Mire " + form.getAttribute("title"));
        }
        return true;
    }
};

////////// FIX PNG UNDER IE6 //////////

function pngFix(elm, noOverflow) {
	elm.style.filter = ' ';
	if (!(document.all && window.print && /MSIE [56]/.test(navigator.userAgent))) return;
	var exec = (function(elm, noOverflow, scale) {
		return function() {
			
		
			var options = { noOverflow:noOverflow};
			var repeat = elm.currentStyle.backgroundRepeat.toLowerCase()=='repeat';
			elm.style.filter = ' ';
				// si l'Ã©lÃ©ment est un tag img, on va en faire creer une balise qui encadrera cette image et ensuite traiter la balise comme si c'etait un Ã©lÃ©ment qui avait une image de fond
				if (elm.nodeName.match(/^(IMG|INPUT)$/)) {
					if (!elm.src.match(/.*\.png$/)) return;
					
					elm.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod='image', src='"+ elm.src + "')";
					
					elm.width = elm.offsetWidth;
					elm.height = elm.offsetHeight;
					
					/* recuperation de l'url du pixel transparent */
					var url = elm.currentStyle.backgroundImage.match(/^url\(["'](.*\.gif)["']\)$/); //seulement les .png
					elm.src = url[1];
					elm.className = elm.className.replace(/pngFix/g,'');
					
				}
				else {
					if (elm.currentStyle.backgroundImage == "" || elm.currentStyle.backgroundImage == "url()") return;
					var url = elm.currentStyle.backgroundImage.match(/^url\(["'](.*\.png)["']\)$/); //seulement les .png
					if (!url || url.length<2) return;
					var pngLayer = document.createElement('i'); // on genere un <i> en position:absolute (layer), qui viendra se placer sous le contenu du div  qui avait besoin du style.
					with(pngLayer.style) {
						if (options.noOverflow) {
							width = elm.offsetWidth + 'px';
							height = elm.offsetHeight + 'px';
						} else {
						 	width = '32000px';
							height = '32000px'; 
						}
						position = 'absolute';
						zIndex = -1;
						fontSize = '1%';
						filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod='" + (options.noOverflow ? 'crop' : 'image') + "', src='"+url[1]+"')";
						background = 'none'; //forcing car parfois il peut arriver qu'on ai une CSS qui vienne rajouter des images / couleurs de fond
						/* positionnement de l'image en fonction du background-position sur l'element */
						if (!repeat) {
							switch((elm.currentStyle.backgroundPositionX+'').toLowerCase()) {
								case 'left' : left=0; break; 
								case 'right' : right = 0; break;
								case 'center' : 
									left='50%'; 
									setTimeout(function(pngLayer) {
										return function() {
											pngLayer.style.marginLeft = -(pngLayer.offsetWidth/2)+'px'; 
										}
									}(pngLayer), 50);
									break;
								default : 
									left = elm.currentStyle.backgroundPositionX; 
							}

							switch((elm.currentStyle.backgroundPositionY+'').toLowerCase()) {
								case 'top' : top = 0; break;
								case 'bottom' : bottom = 0; break;
								case 'center' : 
									top='50%'; 
									setTimeout(function(pngLayer) {
										return function() {
											pngLayer.style.marginTop=-(pngLayer.offsetHeight/2)+'px'; 
										}
									}(pngLayer), 100);
									break;
								default : 
									top = elm.currentStyle.backgroundPositionY || 0; 
							}
						} else {
							left = 0; //elm.currentStyle.backgroundPositionX +'';
							top = 0; //elm.currentStyle.backgroundPositionY +'';
						}
					} 
					
						/* gestion automatique du sizingMethod='scale' ou sizingMethod='image', ne pouvant pas tester le backgroundRepeat correctement, on passe par une methode un peu plus tricky */
						setTimeout(function(elmN, pngLayerN, repeatN) {
							return function() {
								if (!elmN || elmN.parentNode || !pngLayerN || !pngLayerN.parentNode) return;
								if (pngLayerN.filters['DXImageTransform.Microsoft.AlphaImageLoader'].sizingMethod=='image') {
									if (pngLayerN.offsetWidth<elmN.offsetWidth && repeatN) {
										pngLayerN.filters['DXImageTransform.Microsoft.AlphaImageLoader'].sizingMethod='scale';
									} else if (pngLayerN.offsetWidth>elmN.offsetWidth && elm.currentStyle.backgroundPositionX.match(/^(left|0%|0px|0)$/) || elm.currentStyle.backgroundPositionY.match(/^(top|0%|0px|0)$/)){
										pngLayerN.filters['DXImageTransform.Microsoft.AlphaImageLoader'].sizingMethod='crop';
									}
								} else {
									pngLayerN.sizingMethod = 'image';
								}
								if (elm.currentStyle.width.match(/^(0|[12](%|px)?)$/)) {
									pngLayerN.filters['DXImageTransform.Microsoft.AlphaImageLoader'].sizingMethod='image';
								}
								if (pngLayerN.style.right != 'auto' && pngLayerN.style.right !='')
									setTimeout(function() {
										pngLayerN.style.right = parseInt(pngLayerN.style.right) - (elm.offsetWidth%2 ? 1 : 0) + 'px';
									}, 50)
							}
						}(elm, pngLayer, repeat), 200);
					
					with (elm.style) {
						position = elm.currentStyle.position=="static" || elm.currentStyle.position=="" ? 'relative' : position;
						if (elm.currentStyle.overflow!='auto' && elm.currentStyle.overflow!='hidden') overflow = options.noOverflow ? 'visible' : (elm.currentStyle.width.match(/^(0|[12](%|px)?)$/) ? 'visible' : 'hidden');
						backgroundImage = 'none';
					}
					elm.appendChild(pngLayer);
			
			}
		}
	})(elm, noOverflow);
	try{
		pngFixLoader.useOnload ? pngFixLoader.addFunc(exec) : exec();
	} catch(e) {};
}



/* pngFixLoader 
	@function 		:	objet pour permet le lancement des modifications des png via pngFix en dÃ©calÃ© sur le onload de la page.
							cela permet de contourner un bug d'internet explorer qui affiche un message d'erreur si le DOM est modifiÃ© pendant le chargement de la page.
*/
var pngFixLoader = {
	useOnload : true, // true : active l'execution du fixPng sur le load, et false, execute le fixPng dÃ¨s qu'il est appelÃ© par la CSS
	functions : [], // toutes les fonctions Ã  Ã©xÃ©cuter sur le onload de la page
	addFunc : function(func) {
		pngFixLoader.functions.push(func);
	},
	launch : function() {
			pngFixLoader.useOnload = false; //une fois la page chargÃ©e, il faut laisser s'executer automatiquement la fonction pour d'autres actions (ex : ouverture layer)
			var counter = 1;
			while(pngFixLoader.functions.length>0) {
				//setTimeout(pngFixLoader.functions.pop(), 20*counter);
				pngFixLoader.functions.pop()();
				counter++;
			}
	},
	init : function() {
		if (pngFixLoader.useOnload && window.attachEvent && document.all) {
			window.attachEvent('onload', function() {
				setTimeout(pngFixLoader.launch, 100);
			});
		}
	}
}
pngFixLoader.init();



var Ajax = function() { this.initialize.apply(this, arguments);}; //only call the initialize
Ajax.prototype = {
	options : {
		method : 'get',
		url : '',
		async : true,
		noCache : true,
		data : {}
	},
	
	constructor : Ajax,
	initialize : function(options) { //constructor
		var _self = this;
		this.setOptions(options);
		this.xhr = this.getXHR();
		this.xhr.onreadystatechange = function() {
			_self.onReadyStateChange();
		};
	},
	
	onReadyStateChange : function(fromAsync) {
		if(!this.options.async && !fromAsync) {return;} //si mode synchrone, alors cette fonction ne doit pas etre executee
		if (this.xhr.readyState == 4) {/* 4 : etat "complete" */
			if (this.xhr.status == 200) { /* 200 : code HTTP pour OK */
				this.fireEvent('onSuccess');
			} else {
				this.fireEvent('onError');
			}
		}
	},
	
	send : function(data) {
		var o = this.options;
		this.setData(data);
		this.fireEvent('onStart');
		try {
		switch(this.options.method.toLowerCase()) {
			case "get":
				var url = this.dataStr.length>0 ? o.url + "?" + this.dataStr : o.url;
				this.xhr.open("GET", this.addNoCache(url), o.async);
				this.xhr.send(null);
				break;
			case "post":
				this.xhr.open("POST", this.addNoCache(o.url), o.async);
				this.xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
				this.xhr.send(this.dataStr);
				break;
			default :
				return false;
		}
		if (!o.async) {
			this.onReadyStateChange(true);
		}
		} catch (ex) {
			alert(ex);
		}
	},
	
	
	addData : function(data) {
		var i;
		if (!data) {return;}
		if (typeof data=='string') {
			var dataArr = data.split('&');
			data={};
			for (i=0; i<dataArr.length; i++) {
				var vals = dataArr[i].split('=');
				data[vals[0]] = vals[1];
			}
		}
		for (i in data) {
			if (data[i]!==null) {
				this.options.data[i] = data[i];
			}
		}
	},
	
	setData : function(data) {
		if (typeof data=='string') {
			this.dataStr = data;
		} else {
			this.addData(data);
			var dataArr = [];
			for (var i in this.options.data) {
				if (typeof this.options.data[i]!='function') {
					dataArr.push(i+'='+this.options.data[i]);
				}
			}
			this.dataStr = dataArr.join('&');
		}
	},
	
	addNoCache : function(url) {
		if (this.options.noCache) {
			if (url.indexOf("?")==-1) {
				url+="?";
			} else if (url.charAt(url.length-1)!="&") {
				url+="&";
			}
			url += "nocache"+ parseInt(Math.random()*1000000,10)+ "=" + parseInt(Math.random()*1000000,10);
		}
		return url;
	},
	
	fireEvent : function(event) {
		if (this.options[event] && typeof this.options[event]=='function') {
			this.options[event](this.xhr);
		}
	},
	
	getXHR : function() {
		if(window.XMLHttpRequest) {
			return new XMLHttpRequest();
		} else {
			if(window.ActiveXObject) {
				var x = ['Msxml2', 'Microsoft'];
				for (var i=0; i<x.length; i++) {
					try {
						return new ActiveXObject(x[i]+'.XMLHTTP');
					} catch (e) {}
				}
			}
		}
		return null;
	},
	
	setOptions : function(options) {
		if (!options){return;}
		var savedOpt = this.options;
		this.options = {};
		for (var i in savedOpt) this.options[i] = savedOpt[i];
		for (var i in options) this.options[i] = options[i];
	}
};
/* ********************************************************************************************************** */
