			
(function (){
	if(!ev.me){ev.me={};}
	if(!ev.me.widget){ev.me.widget={};}
	if(!ev.me.widget.searchHistory){ev.me.widget.searchHistory={};}
	
	/**
	 * Locator propre à l'historique des recherches.
	 */
	var mHistLoc = new ev.rjs.Locator(10000,'mHistLoc'); // Lecture de la recherche	
	
	/**
	 * Constante d'erreur. 
	 */
	var TIME_OUT_ERROR='0',
		
	/**
	 * Séparateur de champs d'une recherche.
	 */
	SEP_SEARCH='~';
	
/**---------------- objet search ( Recherche historisée ) ------------------------*/	
	/**
	 * Constructeur 
	 * @param _param.criteres objet critere définissant les critères de recherche.
	 * @param _param.vol	Objet VolNew définissant le meilleur vol pour la recherche.
	 * @param _param.date date de la recherche au format long, est aussi utilisé commé indentifiant unique par internaute.
	 * @param _param.filtre String contenant les fitlres appliqués pour la recherche. 
	 */
	function Search(_param) {
		this.criteres=_param.criteres;
		this.vol=_param.vol;		
		this.date=_param.date;
		this.filtre=_param.filtre;
	}
	/** 
	 * @param {Object} s
	 */
	Search.prototype.searchToString=function(s) {
			if(s.criteres&&s.vol){
			var url =s.criteres.ukey+SEP_SEARCH+s.vol.ukey+SEP_SEARCH;
			if(s.date) {
				// Ajouter la date de la recherche si définie pour la mise à jour.
			}
			if(s.filtre) {
				url=url+s.filtre;
			}else {
				url=url+'';
			}
			return  url;
		}
		ev.log.error('mev.searchHistoryManager.__searchToString()> Malformed search history entry! ['+(s.criteres&&'criteres ok'||'criteres nuls')+','+(s.vol&&'vol ok'||'vol nul')+','+(s.date&&'date ok'||'date nulle')+']');
		return '';
	};
	
/**---------------- Publication des objets dans ev.me.widget.searchHistory.bo ----------------*/
	ev.me.widget.searchHistory.bo={
		Search:Search
	};

/**---------------- Publication des objets dans ev.me.widget.searchHistory.dao ----------------*/
	/**
	 *  Méthodes d'accès aux données.
	 *  Cette surcouche  permet de rendre transparent et de centraliser le requetage ERA pour la lecture de données.
	 *  	- Définissions de URL du service.	  
	 *   	- Parse de la réponse.
	 *   	- Instanciation des objets de données.
	 */	
	ev.me.widget.searchHistory.dao={	
		/** Définissions de code erreur pour les retours de méthodes.*/		
		TIME_OUT_ERROR:TIME_OUT_ERROR,		
		
		/** Permet de récupérer la liste complête des recherches de l'internaute.
		 * @param {function} _param.listener methode à appeler lors de la reception de réponse. Cette méthode recevra en parametre un objet contenant
		 * un tableau de recherches.		 
		 */						  
		getAll:function(_param) {
			var This=this,
			ERA_URL_GET_SEARCH = '/vols/profil/getSearches.rjs?id=mHistLoc';			
			if(!_param.listener) {
				ev.log.error('ev.me.widget.searchHistory.dao_get_all_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) {
				var history=[],
				infoFiltre=[],
				i;
				if(r.searchHistories) {
					for(i=0;i<r.searchHistories.length;i++) {
						history.push(r.searchHistories[i]);
					}
				}
				if(r.infoFiltre) {
					for(i=0;i<r.infoFiltre.length;i++) {
						infoFiltre.push(r.infoFiltre[i]);
					}
				}
				_param.listener.call(_param.parentController,{history:history,infoFiltre:infoFiltre});
			};
			// Requête en erreur.
			this.onError=function(r) {						
				_param.listener.call(_param.parentController,{history:[],infoFiltre:[],exception:'MAX_RETRY_REACHED'});				
			};
			// envoi de la requête.								
			ev.requestManager.invokeEra(mHistLoc,ERA_URL_GET_SEARCH, {onSucces:This.onSucces,onError:This.onError},true);				
		},
		
		
		/** @param  _param.onreceive 	= function called when answer is received.
		*   @param  _param.ontimeout 	= function called when timeout is reached.
		*   @param  _param.id 			= id of the target history to delete.
		*   @param  _param.reload   	=	boolean, tell if search list have to be in answer.  ( Optionnel )
		*/
		remove:function(_param) {
			var This=this;			
			var reload=false;
			if(_param.reload && (_param.reload===true)) {reload=true;}
			if(!_param.listener) {
				ev.log.error('ev.me.widget.searchHistory.dao_deleteTarget_no_receive_method_specified');
				return;
			}
			//
			this.onSucces=function(r) {
				var history=[],
				infoFiltre=[],
				i;
				if(r.searchHistories) {
					for(i=0;i<r.searchHistories.length;i++) {
						history.push(r.searchHistories[i]);
					}
				}
				if(r.infoFiltre) {
					for(i=0;i<r.infoFiltre.length;i++) {
						infoFiltre.push(r.infoFiltre[i]);
					}
				}
				//_param.listener({history:history,infoFiltre:infoFiltre});
				_param.listener.call(_param.parentController,{history:history,infoFiltre:infoFiltre});
			};
			// Méthode appelée lorsque la requête est en erreur. cf requestManager.invokeEra
			this.onError=function(r) {				
				_param.listener.call(_param.parentController,{error:TIME_OUT_ERROR});							
			};			
			// envoi de la requête.				
			var url = '/vols/profil/deleteSearch.rjs?id=mHistLoc&searchDate='+_param.sid+'&reload='+reload;				
			ev.requestManager.invokeEra(mHistLoc,url, {onSucces:This.onSucces,onError:This.onError},true);				
		},
		/** 
		 * @param  _param.search 		
		 * @param  _param.listener		
		 * @param  _param.reload   	=	boolean, tell if search list have to be in answer.( Optionnel )
		*/
		add:function(_param) {
			var This=this;			
			var reload=false;
			if(_param.reload && (_param.reload===true)) {reload=true;}
			if(!_param.listener) {
				ev.log.error('ev.me.widget.searchHistory.dao_add_no_receive_method_specified');
				return;
			}
			//
			this.onSucces=function(r) {
				var history=[],
				infoFiltre=[],
				i;
				if(r.searchHistories) {
					for(i=0;i<r.searchHistories.length;i++) {
						history.push(r.searchHistories[i]);
					}
				}
				if(r.infoFiltre) {
					for(i=0;i<r.infoFiltre.length;i++) {
						infoFiltre.push(r.infoFiltre[i]);
					}
				}
				//_param.listener({history:history,infoFiltre:infoFiltre});
				//_param.listener.apply(_param.parentController,[{history:history,infoFiltre:infoFiltre}]);
				_param.listener.call(_param.parentController,{history:history,infoFiltre:infoFiltre});
			};
			// Méthode appelée lorsque la requête est en erreur. Cf. ev.requestManager.invokeEra.
			this.onError=function(r) {																	
				_param.listener.call(_param.parentController,{error:TIME_OUT_ERROR});				
			};
			//	Envoi de la requête.						
			var url = '/vols/profil/addSearch.rjs?id=mHistLoc&hString='+_param.search.toString()+ '&reload='+reload;					
			ev.requestManager.invokeEra(mHistLoc,url, {onSucces:This.onSucces,onError:This.onError},true);				
		},
		
			/** 
		 * @param  _param.search 		
		 * @param  _param.listener		
		 * @param  _param.reload   	=	boolean, tell if search list have to be in answer.( Optionnel )
		*/
		update:function(_param) {
			var This=this;			
			var reload=false;
			if(_param.reload && (_param.reload===true)) {reload=true;}
			if(!_param.listener) {
				ev.log.error('ev.me.widget.searchHistory.dao_deleteTarget_no_receive_method_specified');
				return;
			}
			//
			this.onSucces=function(r) {
				var history=[],
				infoFiltre=[],
				i;
				if(r.searchHistories) {
					for(i=0;i<r.searchHistories.length;i++) {
						history.push(r.searchHistories[i]);
					}
				}
				if(r.infoFiltre) {
					for(i=0;i<r.infoFiltre.length;i++) {
						infoFiltre.push(r.infoFiltre[i]);
					}
				}				
				_param.listener.call(_param.parentController,{history:history,infoFiltre:infoFiltre});
			};
			// Méthode appelée lorsque la requête est en erreur.
			this.onError=function(r) {							
				_param.listener.call(_param.parentController,{error:TIME_OUT_ERROR});									
			};
			//	Envoi de la requête.			
			var url = '/vols/profil/updateSearch.rjs?id=mHistLoc&hString='+_param.search.toString()+'&searchDate='+_param.search.date+'&reload='+ reload;					
			ev.requestManager.invokeEra(mHistLoc,url, {onSucces:This.onSucces,onError:This.onError},true);				
		}
	};
}());

(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.mev){throw new Error("Le namespace 'ev.mev' doit exister");}
	if(!ev.mev.VolNew){throw new Error("Le namespace 'ev.mev.VolNew' doit exister");}
	if(!ev.mev.VolSegment){throw new Error("Le namespace 'ev.mev.VolSegment' doit exister");}
	//Si l'objet ev.mev.searchHistoryManager est défini on sort
	if(ev.mev.searchHistoryManager){return;}
	// Renvoi l'url de la page de résultat courante, en fonction de la langue et du site.
	var $getURLResult=ev.me.ContextFormulaire.getUrlResults;
		
	/**
	 * Séparateur des éléments de vol (dans le moteur vol).
	 */
	var SEP_VOL=';',

	/**
	 * Séparateur des éléments de vol (pour remplacer
	 * les points-virgule qui posent problème avec les
	 * cookies).
	 */
	SEP_VOL2='-',

	/**
	 * Séparateur de recherche dans l'historique.
	 */
	SEP_HISTORY='|',

	/**
	 * Séparateur de champs d'une recherche.
	 */
	SEP_SEARCH='~',

	/**
	 * Expression régulière représentant le point-virgule
	 * (vrai séparateur des éléments de vol).
	 */
	REGEXP_SEP_VOL=new RegExp(SEP_VOL, 'g'),

	/**
	 * Expression régulière représentant le séparateur
	 * des éléments de vol.
	 */
	REGEXP_SEP_VOL2=new RegExp(SEP_VOL2, 'g'),

	/**
	 * Expression régulière représentant le séparateur
	 * de recherche dans l'historique.
	 */
	REGEXP_SEP_HISTORY=new RegExp(SEP_HISTORY),

	/**
	 * Expression régulière représentant le séparateur
	 * de champs dans une recherche.
	 */
	REGEXP_SEP_SEARCH=new RegExp(SEP_SEARCH);

	

	/**
	 * Permet de retrouver l'indice d'une recherche déjà
	 * sauvegardée à partir du jeu de critères et des filtres donnés
	 * @param {ev.mev.Criteres} cr critères de la recherche
	 * @param chaine de caractère représentant les filtres.
	 * @return l'indice de la recherche demandée dans le tableau
	 *   (ou -1 si non trouvé)
	 */
	function indexOfSearch(cr,filtre,history){
		if(!cr){return -1;}
		var l=history.length, s;
		while(l--){
			s=history[l];
			if(s.criteres&&s.criteres.ukey===cr.ukey){		
				//ev.log.info("critere indetique test des filtres");					
				if(filtre && s.filtre && s.filtre == filtre) {
					ev.log.info("indexOfSearch_filtre="+filtre + ' s.filtre='+s.filtre);
					return l;
				}else if(!filtre && !s.filtre) {
					ev.log.info("indexoSearch_tous filtres sont nuls");					
					return l;
				}				
			}
		}
		return -1;
	}	
	/**
	 * Permet de retrouver une recherche déjà sauvegardée
	 * à partir du jeu de critères donné.
	 * @param {ev.mev.Criteres} cr critères de la recherche
	 * @return l'objet représentant la recherche demandée
	 *   (ou 0/null si non trouvé)
	 */
	function findSearchByCriteres(criteres,filtre,history){	
		var i=indexOfSearch(criteres,filtre,history);				
		if(i<0){return 0;}		
		return history[i];
	}	
	/**
	 * Recherche de recherche par id parmis une liste donnée.
	 * On assimile id et date de la recherche, car la date au format long est utilisé comme identifiant unique de recherche pour un internaute.
	 * @param {long} id identifiant unique de la recherche.
	 * @param {list<recherche>} history liste des recherches dans lesquelles recherchée.
	 */
	function findSearchById(id,history) {
		for(var i=0;i<history.length;i++) {
			ev.log.info('history.date='+history.date);
			ev.log.info('id='+id);
			if(history[i].date.toString() == id) {
				return i;
			}
		}	
		return -1;
	}	
	/**
	 * A utiliser sur un tableau de chaine de caractères.
	 * Permet de concatener toutes les valeures du tableau, en utilisant un séparateur spécifique.
	 * @param {Object} tab tableaau de chaine de caractères à utilisé.
	 * @param {Object} SEP séparateur à utilisé entre les différentes valeures du tableau.
	 */
	function concatValues(tab,SEP) {
		if(!tab) {
			return '';
		}
		var string;
		if(tab.length ==1) {
			return tab[0]; 
		}
		for(ari=0;i<tab.length-1;i++) {
			string = string + tab[i]+SEP;
		}
		string=string+tab[tab.length-1];
		return string;
	}	
	/**
	 * Fonction permettant de convertir une recherche
	 * en chaine de caractères (format
	 * date|criteres|meilleur vol|filtre).
	 * @param {Object} s recherche à convertir
	 * @return {String} chaine représentant la recherche 
	 */
	function searchToString(s){	
		if(s.criteres&&s.vol){ 
			var url =s.criteres.ukey+SEP_SEARCH+s.vol.ukey+SEP_SEARCH;
			if(s.date) {
				// Ajouter la date de la recherche si définie pour la mise à jour.
			}
			if(s.filtre) {
				url=url+s.filtre;
			}else {
				url=url+'';
			}
			return  url;
		}
		ev.log.error('mev.searchHistoryManager.__searchToString()> Malformed search history entry! ['+(s.criteres&&'criteres ok'||'criteres nuls')+','+(s.vol&&'vol ok'||'vol nul')+','+(s.date&&'date ok'||'date nulle')+']');
		return '';
	}
	/**
	 * Gestionnaires de recherche stockée  ( Historique des recherches ).
	 * Globalement, gère toutes les actions en relation avec l'historique des recherches. 
	 * Après instanciation del'objet il est indispensable de lancer la métode d'initialisation.
	 *  obj.init(true), pour création du composant graphique ou  obj.init(false), pour ne pas activer l'affichage.
	 * @param {Object} _params Pour le moment aucun paramètre n'est nécessaire en entrée.
	 */
	function SearchManager(_params) {
		/**
		 *  Instance de l'UI courante.
		 */
		this.UI={};
		/**
		 *  Contient des informations générales communes sur les aéroports, compagnie des différentes recherches stockées. 
		 */
		this.infofiltre=[];	
		/**
		 * Indicateur d'état pour la méthode d'initialisation.
		 */
		this.initStep=0;
		/**
		 * Indicateur d'état pour la méthode d'ajout de historiques.
		 */			
		this.addStep=0;
		/**
		 * Indicateur d'état pour la méthode de suppression d'historiques.
		 */
		this.removeStep=0;
		/**
		 *  Membre d'instance qui stocke la liste des recherches de l'internaute.
		 */
		this.histories=[];
	}
	
	/**
	 * Méthode d'initialisation.
	 * case 0: appel à DAO pour lecture de toutes les recherches de l'internaute. Attente en case 1.
	 * case 1:
	 * @param {Object} _params
	 */
	SearchManager.prototype.init=function(_params) {			
		switch(this.initStep) {
			// On lance la requete de recupération des recherches.
			case 0:
				this.initParams=_params;
				this.initStep=1;
				ev.me.widget.searchHistory.dao.getAll({listener:this.init,parentController:this});
			break;
			// On traite les recherches reçues et mises en forme par le dao.
			case 1:
				var h=[];
				if(_params.history && _params.history.length && _params.history.length>0) {
					h=_params.history;
					this.histories=_params.history;
				}
				this.initStep=2;
				this.UI=ev.tpl.mev.searchHistory.create({htmlID:'searchHistory',render:true,histories:h,parentController:this});				
				this.add(this.initParams);
			break;
			}
		};		
	/**
	 * Service d'ajout de recherche dans l'historique des recherches.
	 * @param {mev.criteres} criteres de la recherche à ajouter.
	 * @param {mev.volNew} vol meilleur prix pour la recherche.
	 * @param {long} date date de la recherche.
	 * @param {Array} presetFiltre tableau contenant tous les filtres apliqués à la recherche.
	 * @param {Boolean} refreshDisplay indique si l'on rafraichir l'affichage avec la nouvelle liste d'éléments.
	 */			
	SearchManager.prototype.add=function(_params) {
		/** Lecture des paramètres.*/
		switch(this.addStep) {
			//
			case 0:
				var criteres=_params.criteres;
				var vol=_params.vol;
				var presetFiltre=_params.presetFiltre;
				var refreshDisplay=_params.refresh;
			
				if(!criteres){throw new Error('SearchManager.prototype.add_Le jeu de critères doit être valide');}
				if(!vol){throw new Error('Le vol doit être non nul');}
				var reloadParam='';
				if(refreshDisplay === true) {
					reloadParam = '&reload=true';
				}
				var filtreStr='';
					if(presetFiltre && presetFiltre.length) {
						for(var i=0;i<presetFiltre.length;i++) {
							filtreStr=filtreStr+ presetFiltre[i].cle+':'+presetFiltre[i].value+';';
						}
				}
				var s0=findSearchByCriteres(criteres,filtreStr,this.histories);
				this.addStep=1;
				if(s0) {
					s0.toString=function (){
							return searchToString(this);
					};
					ev.me.widget.searchHistory.dao.update({search:s0,listener:this.add,parentController:this,reload:true});	
				}else {
					var	s1={
						criteres: criteres,
						vol: vol,
						date: '',
						filtre:filtreStr,
						toString: function (){
							return searchToString(this);
						}
					};
					ev.me.widget.searchHistory.dao.add({search:s1,listener:this.add,parentController:this,reload:true});
				}
			break;
			// TODO gestion des exceptions de la requête.
			case 1:
				this.addStep=2;
				var h=[];
				if(_params.history && _params.history.length && _params.history.length>0) {
					h=_params.history;
				}
				this.histories=h;
				ev.mev.searchHistoryManager.UI.refresh({histories:h});
			break;
		}
	};	
	/**
	 * Service de suppression de recherches.
	 * @param {String} _params.sid id de la recherche.
	 * @param {Boolean} _params.refresh indique si le comosant graphique doit être rafraichi avec la nouvelle liste de recherche.	 
	 */
	SearchManager.prototype.remove=function(_params) {
		/** Lecture des paramètres.*/		
		switch(this.removeStep) {
			//
			case 0:
				this.removeStep=1;
				var refreshDisplay=_params.refresh;
				var reloadParam='';
				if(refreshDisplay === true) {
					reloadParam = '&reload=true';
				}
				ev.me.widget.searchHistory.dao.remove({sid:_params.sid,listener:this.remove,parentController:this,reload:true});
			break;

			case 1:
				this.removeStep=0;
				var h=[];
				if(_params.history && _params.history.length && _params.history.length>0) {
					h=_params.history;
				}
				this.histories=h;
				ev.mev.searchHistoryManager.UI.refresh({histories:h});
			break;
		}
	};		
	/**
	 * Relance la recherche stockée, avec les mêmes parametres et même filtres.
	 * @param {Object} _params.sid id de la recherche ( date au format long ) 
	 */
	SearchManager.prototype.throwSearch=function(_params) {
		if(!_params.sid) {
			ev.log.error('SearchManager.prototype.throwSearch_search_id_undefined');
			return;
		}	
		var index=findSearchById(_params.sid,this.histories);
		if(index !=-1) {
			var s=this.histories[index];
			
			var url = $getURLResult()+'?'+s.criteres.inUrlParams();
			var f=s.filtreTab;
			
			if(f && f.length ) {
				for(var i=0;i<f.length;i++) {
					var values=concatValues(f[i].value);
					url=ev.tools.setParamInAnchor(url,f[i].nom,f[i].type+'|'+values+'|');
				}
			}
			window.location.href='';
			window.location.href=ev.requestManager.encodeAnchor(url);
		}else {
			ev.log.error('SearchManager.prototype.throwSearch_no_search_found');
		}
	};
	/**
	 * Définissions de locator pour les différentes requêtes liées à l'historique des recherches.
	 * FIXME:Peut être possible d'utiliser le même.
	 */ 
	ev.mev.searchHistoryManager= new SearchManager();
	ev.log.debug('ev.mev.searchHistoryManager ok');
	ev.tools.onFileLoad('ev/mev/searchHistoryManager.js');
}());