/**
 * Script principal.
 * 
 * @require	jQuery
 * @require jScrollPane
 * @require PAGE.utf8
 */
(function($) {
	
	/**
	 * Création ou récupération d'espaces de noms spécifiques.
	 */
	
	var P = window.PAGE || (window.PAGE = {});
	var $util = P.util || (P.util = {});
	var $utf8 = P.utf8 || (P.utf8 = {});
	
	/**
	 * Variables
	 */
	
	var sScrollClass = "scroll";
	var sCheckPunctClass = "check-punct";
	
	/**
	 * Variabilisation de chaînes de caractères. Les motifs {...} dans la chaîne de
	 * caractères sont remplacés par leur valeur (chaîne de caractères ou numérique)
	 * issue de la table de hash fournie.
	 * 
	 * "<div id='{id}'></div>".supplant({"id": "myId"}) => "<div id='myId'></div>"
	 * 
	 * Issu de http://javascript.crockford.com/remedial.html
	 * 
	 * @param	Hash	h	Couples clés/valeur pour remplacement dans la chaîne.
	 */
	String.prototype.supplant = function(h) {
		
	    return this.replace(/{([^{}]*)}/g, function (a, b) {
	    	
	    	var r = h[b];
	    	return typeof r === "string" || typeof r === "number" ? r : a;
	    });
	};
	
	/**
	 * Copie (profonde) d'un objet, au lieu d'une référence vers l'objet
	 * d'origine.
	 * 
	 * @param	Object|Array	origObj		Un objet ou tableau à copier.
	 * @return	Object|Array	Un nouvel objet ou tableau, identique à
	 * 			l'argument, mais alloué séparément.
	 */
	function getDeepObjCopy(origObj) {
		
		var retObj;
		
		// Cette fonction est inutile si le premier argument n'est pas un
		// objet ou tableau.
		
		if (typeof origObj === "object") {
			
			if (typeof origObj.length !== "undefined") {
				retObj = [];
			} else {
				retObj = {};
			}
			
			for (var key in origObj) if (origObj.hasOwnProperty(key)) {
				
				switch (typeof origObj[key]) {
				
				case "object":
					retObj[key] = getDeepObjCopy(origObj[key]);
					break;
				case "boolean":
					retObj[key] = origObj[key] ? true : false;
					break;
				default:
					retObj[key] = origObj[key];					
				}
			}
		}
		else {
			retObj = origObj;
		}
		
		return retObj;
	}
	
	$util.getDeepObjCopy = getDeepObjCopy;
	
	/**
	 * Etend un objet par le contenu, prioritaire, d'un second.
	 * 
	 * Dans le cas où des entrées conflictuelles des deux objets ou tableaux
	 * sont elles-mêmes des objets ou tableaux, la même extension a lieu
	 * récursivement.
	 * 
	 * @param	Object|Array	hOrig	Un objet à étendre (directement affecté).
	 * @param	Object|Array	hPrio	Un objet source d'extensions (non affecté).
	 */
	function extendInPlace(hOrig, hPrio) {
		
		// Cette fonction est inutile si les deux arguments ne sont pas des
		// objets ou tableaux.
		
		if (typeof hOrig === "object" && typeof hPrio === "object") {
			
			for (var key in hPrio) if (hPrio.hasOwnProperty(key)) {
			
				// En cas de conflit, l'entrée du deuxième objet est
				// prioritaire, sauf s'il faut fusionner deux objets ou tableaux.
				
				if (hOrig.hasOwnProperty(key) &&
					typeof hOrig[key] === "object" &&
					typeof hPrio[key] === "object") {
					extendInPlace(hOrig[key], hPrio[key]);
				} else {
					hOrig[key] = hPrio[key];
				}			
			}
		}
	}
	
	$util.extendInPlace = extendInPlace; 
	
	/**
	 * Etend la copie objet par le contenu, prioritaire, d'un second.
	 * 
	 * Voir {@link extendInPlace}.
	 * 
	 * @param	Object|Array	hOrig	Un objet à étendre (non affecté).
	 * @param	Object|Array	hPrio	Un objet source d'extensions (non affecté).
	 * @return	Object|Array	Une copie étendue de l'objet source.
	 */
	function extend(hOrig, hPrio) {
		
		var hRes;
		
		// Cette fonction est inutile si les deux arguments ne sont pas des
		// objets ou tableaux.
		
		if (typeof hOrig === "object" && typeof hPrio === "object") {
		
			hRes = getDeepObjCopy(hOrig);
			extendInPlace(hRes, hPrio);
		}
		else {
			hRes = hOrig;
		}
		
		return hRes;
	}
	
	$util.extend = extend;
	
	/**
	 * Indique si le navigateur gère a priori les images PNG24 transparentes. 
	 * @return	bool	La non-présence d'IE6, en général.
	 */
	var _bUAHandlesPNG24;
	
	function uaHandlesPNG24() {
		
		if (typeof _bUAHandlesPNG24 === "undefined") {
		
			if (typeof $.browser !== "undefined") {
				
				var sVer = $.browser.version;			
				_bUAHandlesPNG24 = !$.browser.msie ||
					sVer.substring(0, sVer.indexOf(".")) >= 7;
			}
			else {
				_bUAHandlesPNG24 = $.support.opacity;
			}
		}
		
		return _bUAHandlesPNG24;
	}
	
	$util.uaHandlesPNG24 = uaHandlesPNG24;
	
	/**
	 * Met des &nbsp; à la place d'espaces devant certains caractères de
	 * ponctuation.
	 * 
	 * @param	str	sText	Du texte à transformer.
	 * @return	str	Le texte transformé, avec des espaces insécables.
	 */
	function getNbspBeforePunct(sText) {
		return sText.replace(/\s([:;!?])/g, "&nbsp;$1");
	}
	
	$util.getNbspBeforePunct = getNbspBeforePunct;
	
	/**
	 * Remplace positionnellement des caractères dans une cha?ne.
	 * 
	 * @param String sSubject 	La chaîne dans laquelle effectuer des remplacements.
	 * @param String sFrom		Tous les caractères à remplacer.		
	 * @param String sTo		Les caractères de remplacement.
	 */
	function translate(sSubject, sFrom, sTo) {
		
		var sResult = sSubject;
		
		if (typeof sFrom !== "undefined" && !!sFrom &&
			typeof sTo !== "undefined" && !!sTo) {
				
			// Create a lookup table for the translatable characters. If sFrom
			// is shorter than sTo, then the excess characters in sTo are
			// ignored. If sFrom is longer than sTo, then the excess characters
			// in sFrom are ignored (not translated).
		
			var iFromLen = sFrom.length, iToLen = sTo.length;
			var iMinLen = Math.min(iFromLen, iToLen);
			var hTable = {};
			
			for (var i = 0; i < iMinLen; ++i) {
				hTable[sFrom.charAt(i)] = sTo.charAt(i);
			}
			
			// Translate the subject string.
			
			var c, iSubjLen = sSubject.length;
			sResult = "";
			
			for (var i = 0; i < iSubjLen; ++i) {
				
				c = sSubject.charAt(i);
				sResult += (hTable[c] || c);
			}
		}
		
		return sResult; 
	}
	
	$util.translate = translate;
	
	/**
	 * Retire toute forme d'accent, cédille, etc. des caractères d'une chaîne.
	 * 
	 * @param String sText	La chaîne de caractères à "simplifier".
	 */
	function removeDiacritics(sText) {
		return translate(sText, $utf8.sCharsWithDiacritics, $utf8.sCharsWithoutDiacritics); 
	}
	
	$util.removeDiacritics = removeDiacritics;
	
	/**
	 * Mise en place au chargement de la page.
	 */
	$(document).ready(function() {
		
		// Les liens externes s'ouvrent tous dans une nouvelle fenêtre.
		// Les liens qui ne contiennent qu'une référence à une ancre concernent
		// la page actuelle (plutôt que d'être relatifs à la <base href />).
		
		$("a, area").each(function() {
			
			var jThis = $(this);
			var sHref = jThis.attr("href");
			var sRel = jThis.attr("rel");
			
			var bExternal = !!sRel && sRel === "external";
			
			if (bExternal || !!sHref) {
			
				if (bExternal || sHref.indexOf("http://") == 0 || sHref.indexOf("https://") == 0) {
					jThis.attr("target", "_blank");
				}
				else if (sHref.indexOf("#") == 0) {
					
					jThis.click(function(evt) {
						evt.preventDefault();
						window.location.hash = sHref.substring(1);
					});
				}
			}
		});
		
		// Utilisation dynamique de jScrollPane.
		
		$("." + sScrollClass).jScrollPane({
			showArrows:true,
			scrollbarWidth: 7,
			arrowSize: 7, // height
			dragMinHeight: 7,
			dragMaxHeight: 7
		});
		
		// Vérification dynamique de contenus textuels à ponctuation.
		
		$("." + sCheckPunctClass).each(function() {
			
			var jThis = $(this);
			jThis.html(getNbspBeforePunct(jThis.html()));
		});
	});
	
})
(jQuery);
