

(function () {
	var window = this,
			ev = window.ev;

	if (!ev) { throw 'mev.searchHistoryManager#<init>: Needs ev.core module!'; }
	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;
	}

	/**
	 * 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) {
			//  // FIXME Ajouter la date de la recherche si définie pour la mise à jour.
			//}
			return url + (s.filtre || '');
		}
		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 '';
	}

	/**
	 * @param {Object} s
	 */
	Search.prototype.searchToString = searchToString;

	/**---------------- 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 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.
			function onSuccess(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.
			function onError() {
				_param.listener.call(_param.parentController, {history: [], infoFiltre: [], exception: 'MAX_RETRY_REACHED'});
			}

			// envoi de la requête.
			ev.requestManager.invokeEra(mHistLoc, ERA_URL_GET_SEARCH, {onSuccess: onSuccess, onError: 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 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;
			}
			//
			function onSuccess(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
			function onError() {
				_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, {onSuccess: onSuccess, onError: 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 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;
			}
			//
			function onSuccess(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.
			function onError() {
				_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, {onSuccess: onSuccess, onError: 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 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;
			}
			//
			function onSuccess(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.
			function onError() {
				_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, {onSuccess: onSuccess, onError: onError},true);
		}
	};

  // ---------------------------------------------------------------------
  // ------------------ Search History Manager ---------------------------
  // ---------------------------------------------------------------------
	if (!ev.mev) {throw "Le namespace 'ev.mev' doit exister";}
	if (!ev.mev.VolNew) {throw "Le namespace 'ev.mev.VolNew' doit exister";}
	if (!ev.mev.VolSegment) {throw "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 = function() {
		var url;
		if(window.evData&&window.evData.esvVolRecherche) {
			url=window.evData.esvVolRecherche;
		}else if(ev.me.ContextFormulaire.getUrlResults) {
			url=ev.me.ContextFormulaire.getUrlResults();
		}
		return url;
		} ;

	/**
	 * 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) {
		var i;
		for (i = 0; i < history.length; i++) {
			ev.log.info('mev.searchHistoryManager#findSearchById(): history.date=' + history[i].date);
			ev.log.info('mev.searchHistoryManager#findSearchById(): 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, i;
		if (tab.length === 1) {
			return tab[0];
		}
		for (i = 0; i < tab.length - 1; i++) {
			string = string + tab[i] + SEP;
		}
		string = string + tab[tab.length - 1];
		return string;
	}
	/**
	 * 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() {
		/**
		 *  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 'SearchManager.prototype.add_Le jeu de critères doit être valide';}
				if (!vol) {throw 'Le vol doit être non nul';}
				var reloadParam = '';
				if (refreshDisplay === true) {
					reloadParam = '&reload=true';
				}
				var filtreStr = '', i;
				if (presetFiltre && presetFiltre.length) {
					for (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 >= 0) {
			var s = this.histories[index],
					url = $getURLResult() + '?' + s.criteres.inUrlParams(),
					f = s.filtreTab,
					i, values;

			if (f && f.length) {
				for (i = 0; i < f.length; i++) {
					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');
}());

