var timer1;
var timer2;
var timer21;
var timer22;
var timer3;



/**
 * Cette classe gère le contexte des pages de formulaire des moteurs (mev et meh)
 */
(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.rjs){throw new Error("Le namespace 'ev.rjs' doit exister");}
	if(!ev.requestManager){throw new Error("Le 'ev.requestManager' doit exister");}
	// On s'assure que le namespace ev.me existe
	if(!ev.me){ ev.me={}; }
	//Si la classe ContextFormulaire est définie on sort
	if(ev.me.ContextFormulaire){return;}

	/**
	 * Compte client courant.
	 */
	var compte,
	
	/**
	 * Tableau de listener de compte.<br>
	 * Ces listeners seront notifiés lorsque le
	 * compte sera disponible.
	 */
	compteListeners=[],

	/**
	 * Chemin du moteur courant.
	 */
	enginePath,

	/**
	 * Chemin du service de recherche du moteur courant.
	 */
	searchPath,

	/**
	 * Jeu de critères de la recherche actuelle.
	 * (Quelque soit le moteur)
	 */
	criteres,
	
	/**
	 * Tableau de listener de criteres.<br>
	 * Ces listeners seront notifiés lorsque les
	 * critères sont disponibles.
	 */
	crListeners=[],

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

	/**
	 * Expression régulière permettant de retrouver
	 * les criteres dans l'URL (s'ils y sont).
	 */
	REGEXP_URL_CRITERES=/#(([^\/]*\/)*)(cr:([^\/]*))((\/[^\/]*)*)$/,

	/**
	 * Expression régulière permettant de voir lorsque
	 * le serveur est un serveur local (de dev ou de
	 * pré-prod).
	 */
	REGEXP_LOCAL_DN=/(seoul|tokyo|test)\.[^\.]*\.l[^\.:]*(:[0-9]+)?\/.*$/,

	/**
	 * Raccourci vers méthode de récupération d'éléments
	 * DOM par identifiant.
	 */
	byId=ev.dom.element,

	/**
	 * Chemin de la page de résultats seulement pour vol.
	 * FIXME A mettre dans mev (ou trouver un autre système
	 *   hierarchique)
	 */
	URL_RESULTS;


	/**
	 * 
	 */
	var requestM;
	
	
	/**
	 * Methode executée une fois que le compte est en session.
	 * @param {Object} r tableau de resultat retourné par le serveur
	 */
	function onCompteSet(r){
		if(r.exception) {
			ev.log.fatal('me.ContextFormulaire.__onCompteSet()_compte_undefined');
			window.location.href="/errors/500.html";
			return;
		}
		if(r.compte){
			compte.updateFrom(r.compte);
		}
		fireCompteEvent(compte);
	}

	/**
	 * Méthode d'envoi de l'événement de réception
	 * de compte valable.<br>
	 * @param {Object} compte compte disponible
	 */
	function fireCompteEvent(compte){
		var l=compteListeners.length;
		// si aucun listener, on sort
		if(!l){return;}
		while(l--){
			try{
				compteListeners[l].onCompteEvent(compte);
			}
			catch(e){
				ev.log.error('me.ContextFormulaire.fireCompteEvent()> Erreur sur listener de compte : '+e);
			}
		}
	}
	
	/**
	 * Méthode d'envoi de l'événement de réception
	 * de critères valables.<br>
	 * @param {Object} cr jeu de critères disponible
	 */
	function fireCriteresEvent(cr){
		var l=crListeners.length;
		// si aucun listener, on sort
		if(!l){return;}
		while(l--){
			try{
				crListeners[l].onCriteresEvent(cr);
			}
			catch(e){
				ev.log.error('me.ContextFormulaire.__fireCriteresEvent()> Erreur sur listener de critères : '+e);
			}
		}
	}
	
	/**
	 * Méthode de stockage d'un jeu de critères reçu.<br>
	 * Une fois les critères stockés, on envoie un événement.
	 * @param {Object} cr jeu de critères valide
	 */
	function onCriteresOk(cr){
		criteres.updateFrom(cr);
		fireCriteresEvent(criteres);
	}

	/**
	 * Méthode de traitement de critères.<br>
	 * Si les critères sont reçus, on envoie un événement.
	 * Si les critères sont mauvais ou non reçu, on va tenter de les poster
	 * à nouveau vers le serveur (à partir de l'URL).
	 * FIXME à factoriser + placer parties vols dans le package ev.mev 
	 * @param {Object} r resultat de la requete RJS
	 */
	onCriteresReceived={		   
			onSucces:function(r){
				if(!r.exception){
					onCriteresOk(r.criteres);
					return;
				}
				ev.log.fatal('me.ContextFormulaire.__onCriteresReceived()> Wrong criteres in URL!');
				window.location.href="/errors/500.html";
           },
		   /**
		    * Méthode appelée lorsque la requête est en erreur. cf ev.requestManager.invokeEra. 
			* @param {ev.rjs.Event} e
			*/
           onError:function(e){
		   	// FIXME erreur 500 ??			
           }
	};

	/**
	 * FIXME à mettre dans le Context vol
	 * Envoi les criteres au serveur.
	 * 
	 * @param cr jeu de critères sous forme d'un objet JSON
	 * @param callback fonction à exécuter après la création de critères en session
	 */
	function sendCriteres(cr, callback){
		criteres=new ev.mev.Criteres();
		criteres.type=cr.type;		
		criteres.paxAdultes=cr.paxAdultes;
		criteres.paxEnfants=cr.paxEnfants;
		criteres.paxBebes=cr.paxBebes;
		criteres.classe=cr.classe;
		criteres.dataDepartAller=cr.dataDepartAller;
		criteres.dataArriveeAller=cr.dataArriveeAller;
		if(!cr.dataDepartAller){
			criteres.departAller=cr.departAller;
		}
		if(!cr.dataArriveeAller){
			criteres.arriveeAller=cr.arriveeAller;
		}
		criteres.dateAller=cr.dateAller;
		switch(criteres.type){ // type autre que aller simple
		case 1: // aller retour, on recopie les lieux de l'aller
			criteres.dataDepartRetour=criteres.dataArriveeAller;
			criteres.dataArriveeRetour=criteres.dataDepartAller;
			criteres.departRetour=criteres.arriveeAller;
			criteres.arriveeRetour=criteres.departAller;
			criteres.dateRetour=cr.dateRetour;
			break;
		case 2: // parcours circulaire
			criteres.dataDepartRetour=cr.dataDepartRetour;
			criteres.dataArriveeRetour=cr.dataArriveeRetour;
			if(!cr.dataDepartRetour){
				criteres.departRetour=cr.departRetour;
			}
			if(!cr.dataArriveeRetour){
				criteres.arriveeRetour=cr.arriveeRetour;
			}
			criteres.dateRetour=cr.dateRetour;
			break;
		// case 0: // aller simple
		default: // ou autre (valeur erronée)
			criteres.dataDepartRetour='';
			criteres.dataArriveeRetour='';
			criteres.departRetour='';
			criteres.arriveeRetour='';
			criteres.dateRetour='';
			break;
		}
		// Requete ERA de validation des lieux.
		// Set du critere si valide.
		// creation du critere.
		/*
		if(criteres.departAller && criteres.arriveeAller) {
			new interrogationDirectValidation(criteres.departAller,criteres.arriveeAller,callback,criteres).send();
		}else {
			ev.requestManager.invokeEra(searchPath+"/criteres/creer.rjs?"+criteres.inUrlParams(), callback);
		}
		*/
		ev.requestManager.invokeEra(searchPath+"/criteres/creer.rjs?"+criteres.inUrlParams(), callback);
		
	}	
	
	/**
	 *  Méthode à utiliser pour activer l'interrogation par ville en mode accès direct sur page de résultat.
	 *  - Envoi une requete de validation des deux lieux données en paramètres.
	 *  - Si matching direct des lieux, mise à jour du critere avec ces données + creation du critere coté serveur ( Requête ERA )
	 *   + ( TODO ) Mise à jour des ancres de filtres aeroports éventuels.
	 *  - si pas de matching direct, envoi d'une erreur 500, criteres non valide.
	 */
	function interrogationDirectValidation(departAller,arriveeAller,callback,criteres) {
		var mLocator = new ev.rjs.Locator(10000,'DAVC');
		// Callback sur la requête de validation des lieux.
		function onReceive(r) {
			if(r.dataMEVArriveeAller && r.dataMEVDepartAller) {
				if(r.dataMEVDepartAller2) {
					criteres.dataDepartAller=r.dataMEVDepartAller2;
				}else{
					criteres.dataDepartAller=r.dataMEVDepartAller;
				}
				if(r.dataMEVArriveeAller2) {
					criteres.dataArriveeAller=r.dataMEVArriveeAller2;
				}else{
					criteres.dataArriveeAller=r.dataMEVArriveeAller;
				}
				// Mise à jour du critere et creation de celui ci..;
				ev.requestManager.invokeEra(searchPath+"/criteres/creer.rjs?"+criteres.inUrlParams(), callback);
			}else {
				ev.log.fatal('me.ContextFormulaire.__onCriteresReceived()> Wrong criteres in URL!');
				window.location.href="/errors/500.html";
			}
		}
		// Envoi de la requête de validation des lieux de départ et d'arrivée.
		this.send=function() {
			var url = '/vols/geo/lieux/valider.rjs?departAller=' + departAller+'&arriveeAller=' + arriveeAller+'&id=DAVC';
			ev.requestManager.invokeEra(mLocator,url, onReceive,true);
		};
	}

	/**
	 * Méthode de récupération/vérification de champ
	 * de formulaire.
	 *
	 * @param f id du champ demandé
	 * @return le champ demandé.
	 * @throws Error si le champ n'existe pas
	 */
	function fld(f){
		var fe=byId(f);
		if(!fe){throw new Error('Le champ \''+f+'\' (du formulaire) doit exister.');}
		return fe;
	}

	/**
	 * Méthode conversion des informations disponibles
	 * dans le formulaire, en jeu de critères.
	 * FIXME pas à sa place ! à mettre dans mev
	 * @param {Object} frm formulaire à lire
	 */
	function formToCriteres(frm){
		// objet Critères à retourner
		var c=new ev.mev.Criteres();
		// FIXME traiter les parcours circulaires (2)
		if(fld('typeMEVAS').checked){
			c.type=0;
		}
		else{
			c.type=1;
		}
		c.paxAdultes=fld('paxMEVAdultes').value;
		c.paxEnfants=fld('paxMEVEnfants').value;
		c.paxBebes=fld('paxMEVBebes').value;
		c.classe=0; // classe voyageur indiférente
		if(fld("classeMEVEco").checked){
			c.classe=1;
		}
		else if(fld("classeMEVPre").checked){
			c.classe=2;
		}
		else if(fld("classeMEVAff").checked){
			c.classe=3;
		}
		// Aller
		c.dateAller=Date.convertSelectorToStringFr("jourMEVAller", "moisMEVAller");
		/** Gestion des formulaires ancien format
	  	  *	Remplace les deux lignes suivantes, laissées en commentaires pour le moment au cas ou....
	  	  	c.dataDepartAller=fld("dataMEVDepartAller").value;
			c.dataArriveeAller=fld("dataMEVArriveeAller").value;
	  	*/
		var dataMEVDepartAllerNode = byId("dataMEVDepartAller") || byId("iataMEVDepartAller");
		if(!dataMEVDepartAllerNode) {
			throw new Error('Le champ \''+dataMEVDepartAllerNode+'\' (du formulaire) doit exister.');
		}
		/**Recherche si données présentes dans les attributs aData et vdata du champs texte de saisie du départ.*/
		var node = ev.dom.element('lieuMEVDepartAller');
		if(node) {
			var adata = node.getAttribute('adata');
			var vdata = node.getAttribute('vdata');
			if(  adata && vdata ) {	
				//ev.log.warn('ContextFormulaire__adata && vdata');
				c.dataDepartAller=vdata;
				c.dataDepartAller2=adata;
			}else {// FIXME  on continu d'utiliser l'ancien format pour les datas, utilisation du champs caché....
				c.dataDepartAller= dataMEVDepartAllerNode.value;
			}
		}
		var dataMEVArriveeAllerNode = byId("dataMEVArriveeAller") || byId("iataMEVArriveeAller");
		if(!dataMEVArriveeAllerNode) {
			throw new Error('Le champ \''+dataMEVArriveeAllerNode+'\' (du formulaire) doit exister.');
		}	
		//Recherche si données présentes dans les attributs aData et vdata du champs texte de saisie du départ.
		var node2 = ev.dom.element('lieuMEVArriveeAller');
		if(node2) {
			var adata2 = node2.getAttribute('adata');
			var vdata2 = node2.getAttribute('vdata');
			if(  adata2 && vdata2 ) {
				c.dataArriveeAller=vdata2;
				c.dataArriveeAller2=adata2;
			}else {// FIXME  on continu d'utiliser l'ancien format pour les datas, utilisation du champs caché....
				c.dataArriveeAller= dataMEVArriveeAllerNode.value;
			}
		}
		c.departAller=fld("lieuMEVDepartAller").value;
		c.arriveeAller=fld("lieuMEVArriveeAller").value;
		// Retour
		c.dateRetour='';
		c.dataDepartRetour='';
		c.dataArriveeRetour='';
		c.departRetour='';
		c.arriveeRetour='';
		if(c.type){
			c.dateRetour=Date.convertSelectorToStringFr("jourMEVRetour", "moisMEVRetour");
			if(c.type===2){
				// les champs de formulaire ne sont nécessaires que lors des parcours circulaires
				c.dataDepartRetour=fld("dataMEVDepartRetour").value;
				c.dataArriveeRetour=fld("dataMEVArriveeRetour").value;
				c.departRetour=fld("lieuMEVDepartRetour").value;
				c.arriveeRetour=fld("lieuMEVArriveeRetour").value;
			}
		}
		
		return c;
	}
	/**
	 * Fonction permettant de formater une chaine
	 * de 2 caractères pour le nombre donné.
	 * @param {Integer} n nombre à formater
	 */
	function fmt2dgt(n){
		if(n<10){
			return '0'+n;
		}
		return n;
	}
	/**
	 * Convertit les valeurs des chaines de date
	 * (jour et mois/année) en date sous forme texte
	 * au format fr_FR (dd/m/yyyy)
	 * @param {String} day jour au format dd
	 * @param {String} monthYear mois et année au format MM/yyyy 
	 */
	function convertToStringFr(day, monthYear) {
		try{
			var monthYearArray=monthYear.split("/"),
				year=parseInt(monthYearArray[1], 10),
				month=parseInt(monthYearArray[0], 10);
			return fmt2dgt(day)+"/"+fmt2dgt(month)+"/"+year;
		}
		catch(e){
			ev.log.error(e);
		}
	}

	/**
	 *  Parcours la chaine passée en paramètre et remplace les valeurs suivantes par le caractère correspondant.
	 *  	- %E9 - 'é'
	 *  	- %E8 - 'è'
	 *  	- %EF - 'ï'
	 *  	- %FC - 'ü'
	 *   
	 * @param {Object} url
	 */
	function unscapeSpecialChar(url) {		
		var out;//%ED
		out=url.replace(/%E9/g, 'é').replace(/%E8/g, 'è').replace(/%EF/g,'ï').replace(/%FC/g,'ü').replace(/%ED/g,'í'); 
		//out=url.replace(/%/g, '');	// empeche les erreurs JS pour les caractères non gérés.	
		return out;
	}
	/**
	 * Méthode conversion des informations disponibles
	 * dans l'URL en jeu de critères.
	 * FIXME pas à sa place ! à mettre dans mev
	 * @param {String} url URL à lire
	 */
	function urlToCriteres(url){
		// objet Critères à retourner
		
		var c=new ev.mev.Criteres(), params=ev.tools.getUrlParameters(decodeURIComponent(unscapeSpecialChar(url)));			
		
		if(params.type===0||params.type==='0'){
			c.type=0;
		}
		else{
			c.type=params.type&&parseInt(params.type, 10)||1;
		}
		c.paxAdultes=params.paxAdultes;
		c.paxEnfants=params.paxEnfants;
		c.paxBebes=params.paxBebes;
		c.classe=params.classe;
		c.dataDepartAller=  ( params.departAllerData&&params.departAllerData.replace(/\+/g," ") ) ||  ( params.departAllerIata&&params.departAllerIata.replace(/\+/g," ") );
		c.dataArriveeAller=  ( params.arriveeAllerData&&params.arriveeAllerData.replace(/\+/g," ")) || ( params.arriveeAllerIata&&params.arriveeAllerIata.replace(/\+/g," "));
		
		if(params.departAllerData2) {
			c.dataDepartAller2=params.departAllerData2;
		}
		if(params.arriveeAllerData2) {
			c.dataArriveeAller2=params.arriveeAllerData2;
		}				
		/** Ces deux champs doivent contenir le texte du data2 si défini, c'est à dire intérgogation par ville d'un aeroport.*/
		c.departAller=ev.mev.Criteres.getTextFromData(c.dataDepartAller)||params.departAller;
		c.arriveeAller=ev.mev.Criteres.getTextFromData(c.dataArriveeAller)||params.arriveeAller;
		c.dateAller=params.dateAller||params.jourAller&&params.moisAller&&convertToStringFr(params.jourAller, params.moisAller);
		c.dataDepartRetour=params.departRetourData&&params.departRetourData.replace(/\+/g," ");
		c.dataArriveeRetour=params.arriveeRetourData&&params.arriveeRetourData.replace(/\+/g," ");
		c.departRetour=ev.mev.Criteres.getTextFromData(c.dataDepartRetour)||params.departRetour;
		c.arriveeRetour=ev.mev.Criteres.getTextFromData(c.dataArriveeRetour)||params.arriveeRetour;
		c.dateRetour=params.dateRetour||params.jourRetour&&params.moisRetour&&convertToStringFr(params.jourRetour, params.moisRetour);
		return c;
	}

	/**
	* Permet d'extraire le nom de lieu depuis une chaine de code correctement structurée...
	* Format du code ville de Londres : v:4173|c:LON|t:Londres,
	* @param {Object} dataMEV code complet correctement formé correspondant au lieu
	*/
	function extractNomLieuFromReponse(dataMEV) {
	       var refString = '|t:';
	       var indexNomLieu = dataMEV.indexOf(refString);
	       var nomLieu = dataMEV.substring(indexNomLieu +refString.length ,dataMEV.length);
	       return  nomLieu;
	}

	/**
	 * FIXME à mettre dans le Context vol
	 * 
	 * Surcharge de la mï¿½thode de soumission de formulaire.
	 * @param frm : formulaire ï¿½ soumettre
	 *
	 * Convertir les valeurs du formulaire en criteres de recherche
	 * Puis lancer un rjs setCritere (qui lance la recherche)
	 */
	function doSubmitFormMEV3(frm){			
		var c=formToCriteres(frm), unknowns=[];
		timer1=new Date();
		if(!c.dataDepartAller){
			unknowns.push('departAller='+c.departAller);
		}
		if(!c.dataArriveeAller){
			unknowns.push('arriveeAller='+c.arriveeAller);
		}
		if(c.type===2){ // les retours pour les parcours circulaires seulement
			if(!c.dataDepartRetour){
				unknowns.push('departRetour='+c.departRetour);
			}
			if(!c.dataArriveeRetour){
				unknowns.push('arriveeRetour='+c.arriveeRetour);
			}
		}
		
		if(unknowns.length){
			unknowns=unknowns.join('&');
			if(requestM) {
				requestM.check();
			}
		}
		else{
//			ev.log.info('Vrai submit du formulaire...');
//			ev.requestManager.addFieldSIDtoForm(frm.ev_SID);
//			frm.submit();
			// Envoi vers page de résultats avec encodage de l'URL (pour être sûr d'avoir la session ERA sur la page suivante)
			//FIXME [ygally] à valider
			
			/*FIXME[poblin]: Ce hack permet d'envoyer sur une page de résultat MEV2 en utilisant un formulaire MEV3
			 * C'est temporaire pour des besoins de l'intégration (cf avec Bruno). C'est déstiné à être supprimé.
			 */
			if(window.versionMEV===3){
				var url = URL_RESULTS+'?'+c.inUrlParams();
				//TEMPORAIRE: patch pour valider la transmission du clientId sur la page info (cf http://bug.lcom/issues/1012)
				var clientIdUrl=ev.tools.getParameter('clientId');
				if(clientIdUrl){
					url+="&clientId="+clientIdUrl;
				}
				//fin TEMPORAIRE
				window.location.href=ev.requestManager.encodeAnchor(url);
				//window.location.href=ev.requestManager.encodeAnchor(URL_RESULTS+'?'+c.inUrlParams());
			}
			else if(window.versionMEV===2){
				window.location.href=ev.requestManager.encodeAnchor(URL_RESULTS+'?clientId='+(ev.tools.getParameter('clientId')||'')+'&'+c.inUrlParams());
			}
			else{
				ev.log.error("ev.me.ContextFormulaire#doSubmitFormMEV3: Cette version du moteur de vol n'existe pas: "+window.versionMEV);
			}
		}
	}

	/**
	 * FIXME à mettre dans le Context vol
	 * Méthode d'enregistrement de critères.
	 * Elle utilise l'URL pour récupérer les paramètres.
	 * @param c fonction de (c)allback à exécuter après la création de critères en session
	 */
	function setCriteres(c){
		sendCriteres(urlToCriteres(window.location.search), c);
	}

	/**
	 * FIXME à mettre dans le Context vol
	 * 
	 * Prépare la soumission du formulaire pour MEV3.
	 */
	function initFormMEV3(){
		var e=byId('formMEV');
		if(e){
			e.action=URL_RESULTS;
		}
		// déclaration du système de proposition. Cf documentation.
		var propManager = new ev.me.PropositionManager.ValidationRequest({'str':'lieuMEVDepartAller','code':'dataMEVDepartAller'});
		var propManager2 = new ev.me.PropositionManager.ValidationRequest({'str':'lieuMEVArriveeAller','code':'dataMEVArriveeAller'});
		// requestM permet de controler les champs auquel on a associé le système de proposition. cf Documentation.
		requestM = new ev.me.PropositionManager.RequestManager('formMEV','submitMEV');
		requestM.addField(propManager);
		requestM.addField(propManager2);
		requestM.setOnAfter(doSubmitFormMEV3); // set de la méthode submit du formulaire.
		/**
		 * Surcharge de la méthode de soumission de formulaire.
		 * @param f : formulaire à soumettre
		 */
		window.doSubmitFormMEV=function(f){
			doSubmitFormMEV3(f);
			return false;
		};
	}
	/**
	 * Package contenant les fonctions d'accès aux service ERA utilisé dans ce fichier.
	 */
	ev.era ={};
	/**
	 * Lance la requête ERA de création de compte et appel la méthode listener donnée en paramètre à reception de la réponse. Le listener prend en paramètre 
	 * le résultat de la réponse.	 
	 * @param {Object} _param.site id du site.
	 * @param {Object} _param.code code client.
	 * @param {Object} _param.force paramètre force, à déterminer
	 * @param {Object} _param.listener méthode à appeler à la réception de la réponse et en cas de timeout répété.
	 * @param {Object} _param.parentController instance de l'objet qui appel cette méthode.
	 */	
	ev.era.setCompte=function(_param) {
		var This=this;
		var nbRequest=0;
		var regexp=/^\d{0,6}$/;
		if(!_param.listener) {
			ev.log.error('ev.era.setCompte_no_receive_method_specified');
			return;
		}
		// Parse de la réponse et appel du listener avec la liste de recherche en paramètre.
		this.onSucces=function(r) {
			_param.listener(r);
		};
		// Méthode appelée lorsque la requête est en erreur. Cf. ev.requestManager.invokeEra.
		this.onError=function(r) {		
			_param.listener({exception:'MAX_RETRY_REACHED'});		
		};
		this.send=function() {
			if(!(_param.site&&_param.site.toString().match(regexp))){
				ev.requestManager.invokeEra(enginePath+"/compte/choisir.rjs?urlInfos=infos.jsp&force="+_param.force,{onSucces:This.onSucces,onError:This.onError});
			}else if(_param.code&&_param.code.toString().match(regexp)){
				ev.requestManager.invokeEra(enginePath+"/compte/choisir.rjs?urlInfos=infos.jsp&site="+_param.site+"&codeClient="+_param.code+"&force="+_param.force, {onSucces:This.onSucces,onError:This.onError});
			}else{
				ev.requestManager.invokeEra(enginePath+"/compte/choisir.rjs?urlInfos=infos.jsp&site="+_param.site+"&force="+_param.force,{onSucces:This.onSucces,onError:This.onError});
			}
		};
		this.send();
	};

	/**
	 * Classe permettant de stoker les
	 * informations générales du moteur
	 * MEV3.
	 */
	ev.me.ContextFormulaire={
		/**
		 * Crée un compte en session quelque soit les arguments.
		 * @param {Object} _site identifiant numérique du site (compte client courant)
		 * @param {Object} _code code client du compte client
		 */
		setCompte: function(_site, _code, _force){
			ev.era.setCompte({site:_site,code:_code,force:_force,listener:onCompteSet});
		},
		/**
		 * Récupération du jeu de critère en session.
		 * Si on les a déjà récupérés, on garde le jeu stocké.
		 */
		retreiveCriteres: function (){
			if(!criteres||!criteres.isSet()){
				setCriteres(onCriteresReceived);
			}
			else{
				fireCriteresEvent(criteres);
			}
		},
		/**
		 * Permet de récupérer le compte client courant de la page.
		 */
		getCompte: function(){
			return compte;
		},

		/**
		 * Permet de récupérer le jeu de criteres courant de la page.
		 */
		getCriteres: function(){
			return criteres;
		},

		/**
		 * Permet d'ajouter un listener de critères au
		 * contexte.<br>
		 * Ce listener doit contenir une méthode
		 * #onCriteresEvent(Criteres).<br>
		 * Le type de jeu de critères n'est pas contrôlé.
		 * Il pourra être de type vol, hotel, voiture,...
		 * sans distinction, et sera envoyé au listener.
		 * @param {Object} l un listener de critères
		 * @throws If l is null or undefined.
		 * @throws If l does not contain a #onCriteresEvent method.
		 */
		addCriteresListener: function (l){
			if(!l){throw new Error('me.ContextFormulaire#addCriteresListener()> Un listener ne doit pas être nul.');}
			if(typeof(l.onCriteresEvent)!=='function'){throw new Error('me.ContextFormulaire#addCriteresListener()> Un listener doit posséder une méthode #onCriteresEvent().');}

			// Si l'objet criteres est encore non défini (ou pas initilialisé)
			// on ajoute le listener à la liste (il sera notifié dés que les critères sont bons)
			if(!criteres||!criteres.isSet()){
				crListeners.push(l);
			}
			else{
				l.onCriteresEvent(criteres);
			}
		},
		
		/**
		 * Permet d'ajouter un listener de commpte au
		 * contexte.<br>
		 * Ce listener doit contenir une méthode
		 * #onCompteEvent(Compte).<br>
		 * @param {Object} l un listener de compte
		 * @throws If l is null or undefined.
		 * @throws If l does not contain a #onCompteEvent method.
		 */
		addCompteListener: function (l){
			if(!l){throw new Error('me.ContextFormulaire#addCompteListener()> Un listener ne doit pas être nul.');}
			if(typeof(l.onCompteEvent)!=='function'){throw new Error('me.ContextFormulaire#addCompteListener()> Un listener doit posséder une méthode #onCompteEvent().');}

			// Si l'objet compte est encore non défini (ou pas initilialisé)
			// on ajoute le listener à la liste (il sera notifié dés que le compte sera bon)
			if(!compte||!compte.isSet()){
				compteListeners.push(l);
			}
			else{
				l.onCompteEvent(compte);
			}
		},
		/**
		 * Permet de choisir l'url de la page de résultats.
		 * @param {String} path chemin vers la page à utiliser.
		 */
		setUrlResults: function (path){
			URL_RESULTS=path;
		},
		/**
		 * Accesseur publique sur la propriété URL_RESULTS.
		 * @return {String} URL_RESULTS chemin de la page de résultats à utiliser.
		 */
		getUrlResults:function() {
			return URL_RESULTS;	
		},
		
		/**
		 * Initialisation du formulaire en fonction des paramètres de recherche.
		 * L'initialisation du formulaire utilise les informations issues du crit
		 * @param {Object} url
		 */
		initMEV3FormDataFromCritere:function(url,critere){			
			/**On génère un critere à partir de l'URL pour véri*/
			var critereURL=urlToCriteres(url);
			
			if(!critere) {
				throw new Error("Initialisation du formulaire impossible");
			}			
			/** Initialisation du type */
			switch(critere.type){
				case 2: fld('typeMEVPC').checked = true; break;
				case 1: fld('typeMEVAR').checked = true; break;
				//case 0:
				default: fld('typeMEVAS').checked = true; break;
			}

			/** Initialisation du nmbre de passager */
			fld('paxMEVAdultes').value = critere.paxAdultes;
			fld('paxMEVEnfants').value = critere.paxEnfants;
			fld('paxMEVBebes').value   = critere.paxBebes;
			/** Initialisation de la classe de voyage*/
			if(critere.classe==1){
				fld("classeMEVEco").checked = true;				
			}
			else if(critere.classe==2){
				fld("classeMEVPre").checked = true;				
			}
			else if(critere.classe ==3){
				fld("classeMEVAff").checked = true;				
			}
			/** Initialisation des champs DATA destination et depart.  */
			/** fld("iataMEVDepartAller") || fld("dataMEVDepartAller") => Pour gestion des anciens formulaire...*/
			var dataMEVDepartAller = byId("iataMEVDepartAller") || byId("dataMEVDepartAller");
			dataMEVDepartAller.value   = critere.dataDepartAller || critere.iataDepartAller;			
			var dataMEVArriveeAller = byId("iataMEVArriveeAller") || byId("dataMEVArriveeAller");
			dataMEVArriveeAller.value = critere.dataArriveeAller || critere.iataArriveeAller;							
			
			/** La valeure de data2 dans les deux champs qui suivent si data définis !!!!!!!!!**/
			/*
			fld("lieuMEVDepartAller").value  =critere.getNomVilleDepartAller();
			fld("lieuMEVArriveeAller").value = critere.getNomVilleArriveeAller();			
			*/
			
			if(critereURL.dataDepartAller2 && critereURL.dataDepartAller2.length>0) {
				fld("lieuMEVDepartAller").value  =critereURL.getNomLieuDepartAller();
			}else {
				fld("lieuMEVDepartAller").value  =critere.getNomLieuDepartAller();
			}
			
			if(critereURL.dataArriveeAller2 && critereURL.dataArriveeAller2.length>0) {
				fld("lieuMEVArriveeAller").value = critereURL.getNomLieuArriveeAller();
			}else {
				fld("lieuMEVArriveeAller").value = critere.getNomLieuArriveeAller();
			}
			
			
			
			
			/** Set les valeures de vdata et adata ( optionnel pour ce dernier ).**/
			fld("lieuMEVDepartAller").setAttribute('vdata',critere.dataDepartAller || critere.iataDepartAller);
			if(critereURL.dataDepartAller2) {				
				fld("lieuMEVDepartAller").setAttribute('adata',critereURL.dataDepartAller2);
			}
			fld("lieuMEVArriveeAller").setAttribute('vdata',critere.dataArriveeAller || critere.iataArriveeAller);
			if(critereURL.dataArriveeAller2) {				
				fld("lieuMEVArriveeAller").setAttribute('adata',critereURL.dataArriveeAller2);
			}
		

			
			/** Initialisation des dates */					
			var dateAller = Date.convertStringFrToDate(critere.dateAller); 
			Date.convertDateToSelector(dateAller,"jourMEVAller","moisMEVAller");			
			if(critere.type ==1) {
				var dateRetour = Date.convertStringFrToDate(critere.dateRetour); 
				Date.convertDateToSelector(dateRetour,"jourMEVRetour","moisMEVRetour");	
			}								
			/** Initialisation des champs data dans le cas des parcours circulaire*/
			if(critere.type===2){
				// les champs de formulaire ne sont nécessaires que lors des parcours circulaires
				fld("dataMEVDepartRetour").value= critere.dataDepartRetour;
				fld("dataMEVArriveeRetour").value = critere.dataArriveeRetour;
				fld("lieuMEVDepartRetour").value  = critere.departRetour;
				fld("lieuMEVArriveeRetour").value = critere.arriveeRetour;
			}	
			/** Mis à jour des styles calendrier, en particulier pour le cas des aller simple..*/		
			setMEVType();							
		},

		/**
		 * Initialise le contexte de la page formulaire
		 * avec les paramètres donnés.
		 * @param {Object} _tckSiteId code site de la page
		 * @param {Object} _refVols répertoire /mev/ (mappé dans la bonne langue si besoin)
		 * @param {Object} _refHotels répertoire /meh/ (mappé dans la bonne langue si besoin)
		 */
		load: function(_tckSiteId, _refVols, _refHotels){
			if(!_tckSiteId){
				throw new Error("me.ContextFormulaire#initialize()> Le paramètre tckSiteId est nécessaire!");
			}
			//FIXME gérer vols et hotels ??? surcharge ?!
			if(_refVols){
				// seulement pour http://www.easyvols.org/avionfr/mev2/
				if(/^http:\/\/www\.easyvols\.org\/avionfr\/mev2\/$/.test(_refVols)&&REGEXP_LOCAL_DN.test(window.location.href)){
					this.setUrlResults(window.location.href.replace(REGEXP_LOCAL_DN, RegExp.$1+'.mev.lorg'+RegExp.$2+'/avionfr/mev2/results.jsp'));					
				}
				// seulement pour http://www.easyvols.fr/mev2/
				else if(/^http:\/\/www\.easyvols\.fr\/mev2\/$/.test(_refVols)&&REGEXP_LOCAL_DN.test(window.location.href)){
					this.setUrlResults(window.location.href.replace(REGEXP_LOCAL_DN, RegExp.$1+'.mev.lfr'+RegExp.$2+'/mev2/results.jsp'));					
				}
				// pour tous les autres
				else{
					this.setUrlResults(_refVols+"results.jsp");
				}
			}
			else{ // si rien n'est précisé voici le chemin par défaut
				//this.setUrlResults("resultsMEV3.jsp");
				//this.setUrlResults("/mevInt.jsp");
				this.setUrlResults("/mev/results.jsp");
			}
			if(_refHotels){
				if(/^http:\/\/www\.easyvols\.org\/avionfr\/mev2\/$/.test(_refVols)&&REGEXP_LOCAL_DN.test(window.location.href)){
					ev.meh.Context().setPageResults(window.location.href.replace(REGEXP_LOCAL_DN, RegExp.$1+'.mev.lorg'+RegExp.$2+'/avionfr/meh2/results.jsp'));
				}else{
					ev.meh.Context().setPageResults(_refHotels+"results.jsp");
//					ev.meh.Context().setPageResults(_refHotels+"resultsMeh3.jsp");
				}
			}
			// Initialisation des chemins utiles pour ERA
			enginePath="/vols";
			searchPath=enginePath+"/recherche/MEV";
			// on initialise le compte client
			compte=new ev.me.Compte();
			var clientId=ev.tools.getParameter("clientId"); // on recupere la valeur du parametre clientId s'il existe dans l'url			
			if(clientId){				
				this.setCompte(_tckSiteId, clientId, true);
			}else if(window.CODE_CLIENT) {					
				this.setCompte(_tckSiteId,window.CODE_CLIENT, true);
			}else {
				this.setCompte(_tckSiteId, 1, true);
			}												
			// On initialise le formulaire (partie commune aux 2 versions du moteur)
			initFormMEV();
			// On initialise le formulaire MEV3
			initFormMEV3();
			// Initialisation du jeu de critères courant
			criteres=new ev.mev.Criteres();
		}
	};
	
	ev.log.debug('ev.me.ContextFormulaire ok');
	ev.tools.onFileLoad('ev/me/ContextFormulaire.js');
}());
