/* ajout classe hasJS des le chargement du fichier JS, cette classe sert à l'accessibilite et permet de cacher des elements seulement quand le JS existe */
document.documentElement.className += ' hasJS';
/*************************
* classes de fonctions
*************************/
var $n = {
	/* 	$n.hasAttr : 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 elements
		ex : if ($n.hasAttr(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) {
		if (n.nodeType!=1 && not && this.check(n,not)) return false;
		if (this.check(n,a)) return true;
		return false;
	},
	check:function(n,attr) {
		for (var i in attr) {
			if (typeof attr[i].test=='function' && !attr[i].test(n[i]))
				return false;
		}
		return true;
	},
	setAttr : function(attr) {
		for (var i in attr) {
			attr[i] = (typeof (attr[i])=='string') ?  new RegExp("\\b" + attr[i] + "\\b") : attr[i];
		}
		return attr;
	},
	/* 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(tag);
	},
	/* fonction qui retourne le premier element correspondant aux attributs donnes */
	node : function(n, a, not) {
		return this.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 caracteres passee en parametre, cela signifie qu'on ne veut que recuperer des tags
		if (a.nodeName && a.nodeName=="*") delete a.nodeName;
		if (a.nodeName instanceof RegExp) {
			var elms = this.getByTagName(n, "*");
		} else {
			var elms = arrElms || this.getByTagName(n, (a.nodeName || "*"));
		}
		if (elms.length>0) delete a.nodeName;
		a=this.setAttr(a); not=this.setAttr(not);
		for (var i=0; i<elms.length; i++) {
			var x = elms[i];
			if (this.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 this.nodes(n, a, not, false, n.childNodes);
	},
	firstChild : function(n, a, not) {
		return this.nodes(n, a, not, true, n.childNodes);
	},
	lastChild : function(n, a, not) {
		var node = this.nodes(n, a, not, false, n.childNodes);
		return node[node.length-1];
	},
	move : function(n, a, not, action) {
		a=this.setAttr(a); not=this.setAttr(not);
		do { n = n[action];} while(!this.hasAttr(n, a, not));
		return n;
	},
	previous : function(n, a, not) {
		return this.move(n, a, not, "previousSibling");
	},
	next : function(n, a, not) {
		return this.move(n, a, not, "nextSibling");
	},
	parent : function(n, a, not) {
		return this.move(n, a, not, "parentNode");
	}

}

if (!window.$extend) {
	function $extend(original, extended){
		for (var key in (extended || {})) original[key] = extended[key];
		return original;
	};
}

function $protoTypeExtend(original, extended){
	for (var key in (extended || {})) {
		if (!original[key]) original[key] = extended[key];
	}
	return original;
};

/* Array extend */
$protoTypeExtend(Array.prototype, {
	forEach : function(fun) {
		var len = this.length;
		if (typeof fun != "function") throw new TypeError();
		var thisp = arguments[1];
		for (var i = 0; i<len; i++) {
			if (i in this)
				fun.call(thisp, this[i], i, this);
		}
		return this;
	},
	each : function(fun) {
		this.forEach.call(this, fun);
		return this;
	},
	map : function(fun) {
		var len = this.length;
	    if (typeof fun != "function")
	      throw new TypeError();

	    var res = new Array(len);
	    var thisp = arguments[1];
	    for (var i = 0; i < len; i++)
	    {
	      if (i in this)
	        res[i] = fun.call(thisp, this[i], i, this);
	    }
	    return res;
	},
	indexOf: function (str){
		if (typeof str != "string")
	      throw new TypeError();
		for(var i=0,l=this.length;i<l;i++){
			if(this[i] == str) return i;
		}
		return -1;
	}
});

/* String Extends */
$protoTypeExtend(String.prototype, {
	trim : function() { return this.replace(/^\s+|\s+$/g, '')}
});

/************************
* Framework
*************************/
var FW  = function(){return FW.$.apply(this, arguments)};


/* browser : objet browser contenant des booleens propres aux navigateurs, tous ne sont pas integres car pas utiles en temps normal
	@use: if (FW.browser.ie) // msie
*/
FW.browser = {
	ie : (document.all && window.print && !window.opera) || false,
	opera : window.opera  || false,
	gecko : /Firefox/.test(navigator.userAgent),
	FF2 : /Firefox.2/.test(navigator.userAgent),
	webkit: /AppleWebKit/.test(navigator.userAgent)
	
	
};
FW.browser.ie6 = (FW.browser.ie && /MSIE [56]/.test(navigator.userAgent))  || false;
FW.browser.ieQuirks = (FW.browser.ie6 && document.compatMode && document.compatMode=="BackCompat")  || false;

FW.capabilities = {
	check: function (){
		// CSS
		var div = document.createElement("div");
		div.style.width = "1000px";
		document.body.appendChild(div);
		this.gotCSS = div.offsetWidth == 1000 ? true : false;
		//log("this.gotCSS= "+this.gotCSS)
		
		this.gotImg = true
	}
}


/* globales : quelques variables globales utilisees */
FW.heightStyle = FW.browser.ieQuirks || FW.browser.ie6 ? 'height' : 'minHeight';


/* decorations */
FW.decoration = function(name, attributes, firstChilds, lastChilds, childBeforeAfter) {
	//if (attributes.nodeName) FW.initializer.addNodeName(attributes.nodeName);
	firstChilds = FW.strToNodes(firstChilds);
	lastChilds = FW.strToNodes(lastChilds);
	FW.Module(
		'decoration_'+ name,
		attributes,
		{
			initialize : function(elm) {
				FW.createDecorations(elm,  firstChilds, lastChilds, childBeforeAfter);
			}
		}
	)
}
FW.createDecorations = function(element, firstChilds, lastChilds, childBeforeAfter) {
	if (childBeforeAfter) { //si la requete pour trouver un noeud existe
		childBeforeAfter = FW(element).getElement(childBeforeAfter).el;
		if (childBeforeAfter) {
			var parent = childBeforeAfter.parentNode;
			var newChild = childBeforeAfter;
			for (var i=firstChilds.length-1; i>=0; i--) {
				newChild = parent.insertBefore(firstChilds[i].cloneNode(true), newChild);
			}
			if (childBeforeAfter.nextSibling) {
				i = lastChilds.length-1;
				newChild = childBeforeAfter.nextSibling;
			} else {
				i = lastChilds.length-2;
				newChild = parent.appendChild(lastChilds[lastChilds.length-1].cloneNode(true));
			}
			for (; i>=0; i--) {
				newChild = parent.insertBefore(lastChilds[i].cloneNode(true), newChild);
			}
		}
	} else {
		for (var i=lastChilds.length-1; i>=0; i--) {
			element.appendChild(lastChilds[i].cloneNode(true));
		}
		for (var i=0; i<firstChilds.length; i++) {
			if (!element.firstChild) {
				element.appendChild(firstChilds[i].cloneNode(true));
			} else 
				element.insertBefore(firstChilds[i].cloneNode(true), element.firstChild);
		}
	}
}
FW.strToNodes = function(str) {
	if (!str) return [];
	var div = document.createElement('div');
	div.innerHTML = str;
	var returns = [];
	while(div.firstChild)
		returns.push(div.removeChild(div.firstChild));
	return returns;
}
FW.initAttributes = function(attr) {
	for (var i in attr) 
		attr[i] = (typeof (attr[i])=='string') ?  new RegExp("\\b(" + attr[i].replace(/,/g,'|') + ")\\b") : attr[i];
	return attr;
}

/* Modules : gestion des modules du framework */
FW.modules = [];
FW.Module = function(moduleName,attributes, modProto) {
	if (attributes.nodeName) FW.initializer.addNodeName(attributes.nodeName);
	try {delete attributes.nodeName} catch(e){attributes.nodeName=null} //suppression du nodeName qui devient inutile a checker
	attributes = FW.initAttributes(attributes);
	var ModuleObj = function() {
		this.initialize.apply(this, arguments);
	};
	ModuleObj.prototype = modProto;
	FW.modules.push({
		name : moduleName,
		attributes : attributes,
		moduleObject : ModuleObj
	})
}
FW.initializer = {
	nodeNames : [],
	launch : function(parent) {
		parent = parent || document.body;
		for (var i=0; i<this.nodeNames.length; i++) {
			var nodes = parent.getElementsByTagName(this.nodeNames[i]);
			for (var j=0; j<nodes.length; j++) {
				for (var m=0; m<FW.modules.length; m++) {
					if (this.check(nodes[j], FW.modules[m].attributes)) {
						new FW.modules[m].moduleObject(nodes[j]);
					}
				}
			}
		}
	},
	addNodeName : function(nodeName) {
		if (nodeName=='*') return;
		nodeName = nodeName.toLowerCase();
		for (var i=0; i<this.nodeNames.length; i++) {
			if (this.nodeNames[i]==nodeName)
				return;
		}
		this.nodeNames.push(nodeName);
	},
	check:function(n,attr) {
		for (var i in attr) {
			if (typeof attr[i].test=='function' && attr[i].test(n[i]))
				return true;
		}
		return false;
	}
}


/* FW.$ : Equivalent du $ des library en general, mais celui retourne un objet avec l'element associe 
  cela permet de ne pas etendre l'element et de ne pas rentrer en conflit avec d'autre libs
  
*/
FW.$ = function() {
	var aArgs = arguments;
	if(aArgs.length > 1 && typeof aArgs[1] == 'string') {
		return new FW.Wrap(typeof aArgs[0] == 'string' ?
			document.getElementById(aArgs[0]).getElementsByTagName(aArgs[1]):
			aArgs[0].getElementsByTagName(aArgs[1])
		);
	}
	else switch(typeof aArgs[0]) {
		case 'string':
			return new FW.Wrap(document.getElementById(aArgs[0]));
		case 'object':
			return new FW.Wrap(aArgs[0]);
	}
	return false;
}


/* FW.Wrap : objet associe a un DOM Element, sur lequel toutes les methodes s'appliquement sur l'element associe et retourneront ce wrapper
  ex : FW.$(elm).addClass('sample').addEvent('click', function() {}).removeClass('sample');
*/
FW.Wrap = function(el) {
	this.el = el;
}
FW.Wrap.prototype = {
	/* === className functions ===  */
	removeClass: function(sClass) {
		if(this.el!=null) {
			var rep = this.el.className.match(' ' + sClass) ? ' ' + sClass : sClass;
			this.el.className = this.el.className.replace(rep, '');
		}
		return this;
	},
	addClass: function(sClass) {
		if(!this.hasClass(sClass) && (this.el!=null) )
			this.el.className += this.el.className ? ' ' + sClass : sClass;
		return this;
	},
	swapClass: function(sClass1, sClass2) {
		this.el.className = this.hasClass(sClass1) ?
			this.el.className.replace(sClass1, sClass2):
			this.el.className.replace(sClass2, sClass1);
		return this;
	},
	toggleClass: function(sClass) {
		this.hasClass(sClass) ? this.removeClass(sClass) : this.addClass(sClass);
		return this;
	},
	hasClass: function(sClass) {
		if(this.el!=null) {
			return typeof sClass == 'string' ?
				new RegExp('\\b' + sClass + '\\b').test(this.el.className):
				sClass.test(this.el.className);
		} 
		
		return false;
	},
	
	/* === events Functions ===  */
	addEvent: function(evType, func, bCapture) {
		if(evType == 'domready' && this.el==window)
			FW.event.domready(func);
		document.addEventListener ?
			this.el.addEventListener(evType, func, bCapture || false):
			this.el.attachEvent ?
				this.el.attachEvent('on' + evType, func):
				false;
		return this;
	},
	// Suppression d'un gestionnaire d'evenement sur un element pour un evenement donne
	removeEvent: function(sEvType, fn, bCapture) {
		document.addEventListener ?
			this.el.removeEventListener(sEvType, fn, bCapture || false):
			this.el.detachEvent ?
				this.el.detachEvent('on' + sEvType, fn):
				false;
		return this;
	},
	
	/* === dom functions ===  */
	getElement:function(attr, not) {
		return new FW.Wrap($n.node(this.el, attr, not));
	},
	getElements:function(attr, not) {
		return $n.nodes(this.el, attr, not);
	},
	getParent : function(attr, not) {
		var el = $n.parent(this.el, attr, not);
		return el ? new FW.Wrap(el) : null;
	},
	getNext : function(attr,not) {
		var el = $n.next(this.el, attr, not);
		return el ? new FW.Wrap(el) : null;
	},
	getPrevious : function(attr,not) {
		var el = $n.previous(this.el, attr, not);
		return el ? new FW.Wrap(el) : null;
	},
	getChildsNodes : function(attr, not) {
		return $n.childs(this.el, attr, not);
		
	},
	
	/* styles CSS functions */
	getStyle: function(strCssRule) {
		var oElm = this.el;
		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;
	},
	
	getIntStyle: function(strCSSRule) {
		var val = parseInt(this.getStyle(strCSSRule));
		if (isNaN(val)) val=0;
		return val;
	},
	getVStyle: function(elm) {
		return FW.browser.ieQuirks ?
			0 :
			this.getIntStyle("padding-top") + this.getIntStyle("padding-bottom") +
			this.getIntStyle("border-top-width") + this.getIntStyle("border-bottom-width");
	},
	// Retourne la somme de tous les styles horizontaux appliques (border-width+padding)
	getHStyle: function(elm) {
		return FW.browser.ieQuirks ?
			0 :
			this.getIntStyle("padding-left") + this.getIntStyle("padding-right") +
			this.getIntStyle("border-left-width") + this.getIntStyle("border-right-width");
	},
	
	getPosition : function(overflown) {
		var obj = this.el;
		var curleft = 0,
			 curtop = 0;
		if (obj.offsetParent) {
			do {
				curleft += obj.offsetLeft + (overflown ? -obj.scrollLeft : 0) ;
				curtop += obj.offsetTop + (overflown ? -obj.scrollTop : 0) ;
			} while (obj = obj.offsetParent);
			return {x:curleft,y:curtop};
		}
	}
}

/* FW.event : extendeur de l'objet event. Dans un premier temps ce ne seront que des fonctions liées aux events */
FW.event = {
	domready: function(fn) {
		// Internet Explorer 
		if(window.attachEvent) {
			document.write('<script id="ieScriptLoad" defer src="//:"><\/script>');
			document.getElementById('ieScriptLoad').onreadystatechange = function() {
				if(this.readyState == 'complete')
					FW.event.init(fn);
			};
		}
		// Mozilla/Opera 9 
		if(document.addEventListener)
			document.addEventListener('DOMContentLoaded', function() { FW.event.init(fn); }, false);
		// Safari 
		if(navigator.userAgent.search(/WebKit/i) != -1){
		    FW.event.loadTimer = setInterval(function (){
				if(document.readyState.search(/loaded|complete/i) != -1)
					FW.event.init(fn);
			}, 10);
		}
		// Other web browsers
		FW.$(window).addEvent('load', function() { FW.event.init(fn); });
	},
	
	// Initialise le script
	init: function(fn) {
		if (arguments.callee.done) return;
		arguments.callee.done = true;
		if (FW.event.loadTimer) clearInterval(FW.event.loadTimer);
			fn();
	},
	
	// Annulation de la propagation d'un evenement et de l'action par defaut d'un element
	stop: function(e) {
		if(e && e.stopPropagation && e.preventDefault) {
			e.stopPropagation();
			e.preventDefault();
		}
		else if(e && window.event) {
			window.event.cancelBubble = true;
			window.event.returnValue = false;
		}
		return false; // Indispensable pour Safari
	},
	// Retourne la source de l'evenement
	getSrc: function(e) {
		return e.target || e.srcElement;
	},
	relSrc: function(e) {
		switch(e.type) {
			case 'mouseover': // Retourne l'element survole precedent l'element source de l'evenement
				return e.relatedTarget || e.fromElement;
			case 'mouseout': // Retourne l'element survole suivant l'element source de l'evenement
				return e.relatedTarget || e.toElement;
		}
	}
}
FW.$(window).addEvent('domready', function() {FW.initializer.launch()});
