/**
 * Le gestionnaire d'id de session.<br>
 * <br>
 * Il permet de conserver le lien avec le serveur
 * qui a créé la session pour l'internaute courant.<br>
 * <br>
 * A chaque nouvelle requête/redirection, il est
 * recommandé d'encoder le lien via la méthode
 * {ev.CookieSessionManager#encodeUrlWithSession(String)}
 * afin de dirigé chacune des requêtes HTTP vers le
 * même serveur.<br>
 * <br>
 * Au retour de chaque requête, il est également
 * recommandé de vérifier le numéro de session renvoyé
 * par le serveur. Cela se fait grâce à la méthode
 * {ev.CookieSessionManager#checkSession(String)}.<br>
 * (au démarrage d'une nouvelle page cela sera fait
 * automatiquement grâce à l'initialisation de départ ;
 * il suffit de faire appel au présent fichier)
 */
(function(){
	// Si les namespaces/classes nécessaires ne sont pas chargées : exception
	if(!window.ev){ window.ev={}; }
	if(!ev.rjs){throw new Error("Le namespace 'ev.rjs' doit exister");}
	// nom du cookie qui contient l'id de session 
	var cookieName = "esv_sessionId",

	/**
	 * Nom du cookie de session de Mod_JK.
	 */
	mod_jk_cookieName = "JSESSIONID",

	/**
	 * On stocke le numéro de session.
	 * Cela permet d'éviter de fonctionner avec les cookies
	 * tant qu'on reste dans la même page.
	 */
	sessionId,

	/**
	 * Expression régulière permettant de trouver l'id de session dans l'url.
	 */
	regexUrlSession=/;jsessionid=([^#\?]*)[#\?]?/,

	/**
	 * Expression régulière permettant de trouver l'id de session dans l'url.
	 */
	regexCookieSession=new RegExp("(?:; )?"+cookieName+"=([^;]*);?"),
	
	/**
	 * Identifiant du locator utilisé par le gestionnaire
	 * d'id de sessions.
	 */
	RJS_ID='CookieSessionManager';

	/**
	 * Définition d'un seul Locator RJS (au cas où il y
	 * ait plusieurs requête sur le numéro de session).
	 */
	RJS_LOCATOR=new ev.rjs.Locator(10000, 'CookieSessionManager');

	/**
	 * retourne l'id de session qui se trouve dans le cookie.
	 */
	function getSessionInUrl(){
		// on recupere l'id de session dans un cookie s'il existe
		if(regexUrlSession.test(window.location.href)){
			return RegExp.$1;
		}
		return '';
	}

	/**
	 * retourne l'id de session qui se trouve dans le cookie.
	 */
	function getSessionInCookie(){
		// on recupere l'id de session dans un cookie s'il existe
		if(regexCookieSession.test(document.cookie)){
			return decodeURIComponent(RegExp.$1);
		}
		return '';
	}

	/**
	 * inscrit l'id de session dans le cookie.
	 * FIXME : penser a uen solution si les cookies ne sont pas pris en compte par le client
	 * 
	 * @param sId : id de session à enregistrer dans le cookie
	 */
	function setSessionInCookie(sId){
		// on enregistre l'id de session dans un cookie pour pouvoir le réutiliser plus tard
		document.cookie = cookieName + "=" + sId + "; path=/";
		// on écrase le cookie de session de Mod_JK (JSESSIONID)
		document.cookie = mod_jk_cookieName + "=" + sId + "; path=/";
	}

	/**
	 * Permet de comparer le numéro de session donné
	 * à celui qui était précédemment stocké.<br>
	 * S'il est différent, le numéro de session donné
	 * sera retenu et remplacera le numéro courant
	 * (variable locale + cookie).
	 * 
	 * @param {String} sId id de session à comparer à la dernière session
	 *   connue du gestionnaire
	 * @return {boolean} true si la session est inchangée ; false si la session
	 *   donnée est différente ou nulle
	 */
	function chkAndUpd(sId){
//		ev.log.debug('ev.CookieSessionManager.__chkAndUpd()> Checking session Id : '+sId);
		if(!sId){
			ev.log.error('ev.CookieSessionManager.__chkAndUpd()> Given session Id is undefined');
			return false;
		}
		if(sId===sessionId){
//			ev.log.info('ev.CookieSessionManager.__chkAndUpd()> Session Id is good : '+sessionId);
			return true;
		}
		// si le numéro de session donné est différent, on le garde en remplacement de l'ancien
		sessionId=sId;
		setSessionInCookie(sId);
		ev.log.warn('ev.CookieSessionManager.__chkAndUpd()> Session Id replaced by : '+sessionId);
		return false;
	}

	/**
	 * Methode executée une fois qu'on a recuperer l'id de seesion dans le rjs session.
	 * @param {Object} r session resultat retourné par le serveur
	 */
	function onSessionRetrieved(r){
//		ev.log.info('ev.CookieSessionManager.__onSessionRetrieved()> Session Id retreived : '+r.sessionId);
		chkAndUpd(r.sessionId);
	}

	/**
	 * Récupère l'identifiant de la session courante ou de la nouvelle session.
	 */
	function retrieveSessionId(){
		sessionId=getSessionInUrl();
//		ev.log.info('ev.CookieSessionManager.__retrieveSessionId()> Session found in url : '+sessionId);
		if(!sessionId){
			sessionId=getSessionInCookie();
//			ev.log.info('ev.CookieSessionManager.__retrieveSessionId()> Session found in cookie : '+sessionId);
		}
		else{
			// si on trouve l'id de session dans l'URL, on le stocke dans le cookie
			setSessionInCookie(sessionId);
		}
		var url=ev.rjs.URL_ERA_ROOT+'/session.rjs;jsessionid='+sessionId+'?id='+RJS_ID;
//		ev.log.info('ev.CookieSessionManager.__retrieveSessionId()> Retreiving Session Id... [request: '+url+']');
		ev.rjs.simpleInvoke(RJS_LOCATOR, url, onSessionRetrieved);
	}
	
	/**
	 * Déclaration de la partie visible (publique)
	 * du gestionnaire d'id de session.
	 */
	ev.CookieSessionManager={
		/**
		 * Permet d'encoder l'url passée en paramètre en
		 * lui ajoutant le 'jsessionid' permettant de
		 * contacter le bon serveur (load balancing
		 * d'Apache + ModJK) et de retrouver la session
		 * courante dans la page suivante (ou requête
		 * asynchrone).
		 * 
		 * @param u url à encoder
		 */
		encodeUrlWithSession: function(u){
			var s=sessionId, indexParam;
			if(!s){return u;}
			indexParam = u.indexOf("?", 0);
			if(indexParam != -1){// si il y a des parametre dans l'url alors on ajoute le jsessionid juste avant le ?
				return u.substring(0, indexParam) + ";jsessionid=" + s + u.substring(indexParam, u.length);  
			}else{// aucun parametre dans l'url on rajoute le jsessionid à la fin de l'url
				return u + ";jsessionid=" +  s;
			}
		},

		/**
		 * Permet de comparer le numéro de session donné
		 * à celui qui était précédemment stocké.<br>
		 * S'il est différent, le numéro de session donné
		 * sera retenu et remplacera le numéro courant
		 * (variable locale + cookie).
		 * 
		 * @param {String} sId id de session à comparer à la dernière session
		 *   connue du gestionnaire
		 * @return {boolean} true si la session est inchangée ; false si la session
		 *   donnée est différente ou nulle
		 */
		checkSession: function(sId){
			return chkAndUpd(sId);
		},

		/**
		 * Permet d'initialiser la session courante.<br>
		 * S'il n'y a pas de session active encore valide
		 * une nouvelle session sera créée.
		 */
		initialize: function(){
			retrieveSessionId();
		}
	};

	// Première initialisation dés maintenant
	ev.CookieSessionManager.initialize();
}());