/**
 * Fonction anonyme de déclaration de classe(s) utiles.
 * Certaines classes/fonctions ne sont visible que par
 * la(es) classe(s) concernée(s) (déclarée(s) ici).
 * Ce mécanisme de fonction anonyme permet de reproduire
 * un système d'encapsulation digne d'un langage de
 * programmation évolué (comme le Java).
 */
(function(){
	// Si les namespaces/classes nécessaires ne sont pas chargées : exception
	if(!window.ev){throw new Error("Le namespace 'ev' doit exister");}
	if(!ev.tools){throw new Error("Le namespace 'ev.tools' doit exister");}
	if(!ev.log){throw new Error("Le namespace 'ev.log' doit exister");}

	var

	/**
	 * Expression régulière permettant de trouver le début des paramètres.
	 */
	RE_PARAMS=/^[^#]*\?([^#]*)(#|$)/,

	/**
	 * Expression régulière constante représentant un séparateur
	 * de paramètres.<br>
	 * Permet de "spliter" une chaine contenant plusiseurs
	 * paramètres (dans une URL)
	 */
	RE_PARAM_SEPARATOR=/&/,

	/**
	 * Expression régulière constante représentant un séparateur
	 * de paramètres situé dans une ancre.<br>
	 * Permet de "spliter" une chaine contenant plusiseurs
	 * paramètres séparés par des '/'.
	 */
	RE_HASH_PARAM_SEPARATOR=/\//,

	/**
	 * Expression régulière représentant la fin d'une URL
	 * (à partir de l'ancre s'il y en a une).
	 */
	RE_HASH_PARAMS=/(#([^\/]*(\/([^\/]*))*)?)?$/,

	/**
	 * Expression régulière représentant l'ancre entière.
	 */
	RE_ANCHOR=/(#(.*))?$/,
	
	/**
	 * Expression régulière représentant des doubles slash
	 * ('//') dans l'ancre.
	 */
	RE_ANCHOR_SLASHES=/(#.*)\/\/+/g;

	/**
	 * Méthode utile d'ajout d'une entrée dans une
	 * map d'éléments 'property=value'.
	 * @param {Object} m map dans laquelle sera ajouté le paramètre
	 * @param {String} a séparateur d'affectation (ex: '=' dans 'property=value')
	 * @param {Object} p entrée de type 'property=value'
	 */
	function put(m, a, p){
		if(!p.length){
			ev.log.warn('ev.tools.params.js#__put(): un param vide (2 séparateurs de paramètres côte à côte, ou séparateur en début/fin de chaîne)');
			return;
		}
//		ev.log.debug('ev.tools.params.js#__put(Map, Param): inserting paramètre "'+p+'"...');
		var nv=p.split(new RegExp(a)), l=nv.length;
		if(--l){
			if(!nv[0].length){
				ev.log.error('ev.tools.params.js#__put(Map, Param): paramètre "'+p+'" mal renseigné [manque le nom du paramètre]');
				return;
			}
			if(m[nv[0]]){
				ev.log.warn('ev.tools.params.js#__put(Map, Param): paramètre "'+nv[0]+'" renseigné plusieurs fois (on utilise la dernière valeur donnée "'+m[nv[0]]+'")');
				return;
			}
			while(--l){
				// si plusieurs séparateurs d'affectation, on considère le premier comme séparateur, et les suivants sont compris dans la valeur
				nv[l]+=a+nv[l+1];
			}
			m[nv[0]]=nv[1];
			return;
		}
		ev.log.warn('ev.tools.params.js#__put(Map, Param): paramètre "'+p+'" mal renseigné [manque caractère \''+a+'\']');
		m[p]='';
	}

	/**
	 * Méthode permettant de construire une map avec tous les
	 * paramètres du tableau donné.
	 * @param {String} a séparateur d'affectation (ex: '=' dans 'property=value')
	 * @param {Object} ps tableau de paramètres à ajouter
	 * @return la map ainsi créée
	 */
	function map(a, ps){
		if(!ps||!ps.length){
			ev.log.info('Rien trouvé');
			return {};
		}
//		ev.log.debug('ev.tools#getJsParameters(): Parameters array ['+ps+']');
		var m={}, n=ps.length;
		while(n--){
			put(m, a, ps[n]);
		}
		return m;
	}

	/**
	 * Fonction permettant de récupérer les paramètres
	 * fournis dans l'URL donnée (ou l'URL de la page si
	 * rien n'est précisé).<br>
	 * NOTA : cette méthode ne gère pas de cache, à chaque appel
	 * elle refait le traitement.
	 *
	 * @param {String} u [optionel] url à lire [par défaut: document.location.href]
	 */
	ev.tools.getUrlParameters=function(u){
		u=(u||window.location.search);
		u=u&&RE_PARAMS.test(u)&&RegExp.$1;
		if(!u){return {};}
		return map('=', u.split(RE_PARAM_SEPARATOR));
	};

	/**
	 * Fonction permettant de récupérer les paramètres fournis sur
	 * un appel d'un fichier js donné.<br>
	 * Le premier paramètre est optionel et permet simplement de
	 * préciser si besoin le nom du tag contenant le script
	 * concerné. Cela permet, comme cela est souvent le cas d'avoir
	 * la possibilité de traiter les fichiers étant en fin de page
	 * (dans le tag body).
	 * NOTA : cette méthode ne gère pas de cache, à chaque appel
	 * elle refait le traitement.
	 *
	 * @param {String} pt [optionel] : tag parent [par défaut: head]
	 * @param {String} jsf : nom du fichier js
	 */
	ev.tools.getJsParameters=function(pt, jsf){
		if(!jsf){jsf=pt;pt='head';}
		/** regexp */
		var RE_JS_PARAMS=new RegExp(jsf.replace(/\./g,'\\.')+'\\?([a-zA-Z0-9_:\\./=&]*)$'),
		/** script nodes */
		scripts=ev.dom.tags('script', ev.dom.tags(pt)[0]), i=scripts.length, src, params;
		while(i--){
			src=scripts[i].src;
			//ev.log.debug('ev.tools#getJsParameters(): looking for file '+jsf+': '+src);
			if(!(src&&RE_JS_PARAMS.test(src))){continue;}
			params=RegExp.$1;
			//ev.log.debug('ev.tools#getJsParameters(): Found parameters for file "'+jsf+'": "'+src+'"\n    => "'+params+'"');
			return map('=', params.split(RE_PARAM_SEPARATOR));
		}
		return {};
	};

	/**
	 * Fonction permettant de récupérer les paramètres fournis
	 * dans l'ancre d'une URL.<br>
	 *
	 * @param {String} u URL dans laquelle on doit récupérer les paramètres passés dans l'ancre
	 */
	ev.tools.getAnchorParameters=function (u){
		if(!u||!RE_HASH_PARAMS.test(u)){
			ev.log.warn('tools#getAnchorParameters()> URL impossible à lire ('+u+')');
			return {};
		}
		var params=RegExp.$2.replace(/^\/+/, '').replace(/\/+$/, '');
		if(!params){
			// en cas de chaine vide, on renvoi une map vide
			return {};
		}
//		ev.log.debug('tools#getAnchorParameters()> Found parameters in anchor : "'+u+'"\n    => "'+params+'"');
		return map(':', params.split(RE_HASH_PARAM_SEPARATOR));
	};

	/**
	 * Méthode d'ajout / mise à jour d'un paramètre
	 * de l'ancre.
	 * @param {Object} url URL à modifier
	 * @param {Object} name nom du paramètre à ajouter/changer
	 * @param {Object} value valeur du paramètre à ajouter/changer
	 */
	ev.tools.setParamInAnchor=function (url, name, value){
//		ev.log.debug('tools#setParamInAnchor()> Modification de l\'ancre dans l\'URL... ('+name+'='+value+')');
		var oldValue=ev.tools.getAnchorParameters(url)[name];
		if(oldValue){
			if(oldValue===value){
				// Si l'ancienne valeur du paramètre est égale à la nouvelle, on ne change rien et on sort
//				ev.log.debug('tools#setParamInAnchor()> L\'ancre est déjà à jour pour le paramètre. ('+name+'='+oldValue+')');				
				return url;
			}
//			ev.log.debug('tools#setParamInAnchor()> Paramètre \''+name+'\' trouvé dans l\'ancre: '+oldValue+' [on l\'enlève]');
			// si le paramètre était présent dans l'url, on l'enlève
			url=url.replace(new RegExp('(#.*\\/)('+name+':)[^\\/]*\\/', 'g'), '$1');
		}
		if(value||value===0){
			// Ajout du nouveau paramètre dans l'ancre et suppression des doubles slashs ('//')
			url=url.replace(RE_ANCHOR, '#$2/'+name+':'+value+'/').replace(RE_ANCHOR_SLASHES, '$1/');
		}
//		ev.log.debug('tools#setParamInAnchor()> Paramètre \''+name+'\' modifié dans l\'ancre de l\'URL : '+url);
		return url;
	};
}()); // exécution de la fonction anonyme ici