
// construit une mini BDD pour le moteur de recherche et ajoute les controles javascript (toggles, favoris)
function initDlSpace(){
	var indexables = Amed.DOM.getElementsByAttributeNS('amed', 'indexable', 'true', 'dlSpaceForm'); // itérables
	window.indexes = []; // résultats de l'indexation, variable globale
	var favs = Amed.Cookie.dump('dlFav'), favsl = favs.length; // élèments en favoris
	var togs = Amed.Cookie.dump('dlTog'), togsl = togs.length; // élèments ouverts
	
	function trim(s){
		return s.replace(/^\s+/, '').replace(/\s+$/, '').replace(/\s+/g, ' ');
	}
	function cleanAndIndex(s, db){
		var t = s.toLowerCase().replace(/[éèê]/g, 'e').split(/[\s\(\)\'\,\/\-]+/),
			tl = t.length;
		for (; tl--;) {
			if (t[tl].length > 2) { // si au moins 3 lettres
				var data = {};
				data.explode = t[tl].split(''); // préparation des données pour l'algo de levenshtein
				data.exl = data.explode.length; // préparation des données pour l'algo de levenshtein
				db['"' + t[tl] + '"'] = data;
			}
		}
	}
	function objExtend(o){
    	var F = function() {};
        F.prototype = o;
        return new F();
    };
	
	function appendToggle(el, group, label, guid){
		var opened = false, toggle = document.createElement('a');
		for (var i = togsl; i--;) if (togs[i] === guid) {
			opened = true;
			break;
		}
		if(opened){
			toggle.setAttribute('title', i18n.get('masquer ') + label);
			toggle.className = 'toggleOn';
		}else{
			toggle.setAttribute('title', i18n.get('afficher ') + label);
			toggle.className = 'toggleOff';
			group.style.display = 'none'; // masque une première fois
		}
		toggle.setAttribute('href', '#');
		//Amed.Event.add(toggle, 'click', toggleDlGroup, label, group, guid);
		Amed.Event.add(el, 'click', toggleDlGroup, toggle, label, group, guid);
		el.appendChild(toggle);
	}
	function appendFav(){
		var star = document.createElement('a');
		star.setAttribute('href', '#');
		Amed.Event.add(star, 'click', addRemoveFavData, resultat);
				
		if (resultat.favStatus) {
			star.className = 'favOn';
			star.setAttribute('title', i18n.get('retirer "') + resultat.label + i18n.get('" des favoris'));
		} else {
			star.className = 'favOff';
			star.setAttribute('title', i18n.get('ajouter "') + resultat.label + i18n.get('" aux favoris'));
		}
		return kchilds[k].parentNode.appendChild(star);
	}
	function apendTick(){
		var tick = document.createElement('a');
		tick.setAttribute('href', '#');
		
		if (!resultat.checkbox.checked) {
			tick.className = 'tickOff';
			tick.setAttribute('title', i18n.get('télécharger "') + resultat.label + '"');
			resultat.labelTag.setAttribute('title', i18n.get('télécharger "') + resultat.label + '"');
		} else {
			tick.className = 'tickOn';
			tick.setAttribute('title', i18n.get('ne pas télécharger "') + resultat.label + '"');
			resultat.labelTag.setAttribute('title', i18n.get('ne pas télécharger "') + resultat.label + '"');
		}
		
		Amed.Event.add(tick, 'click', addRemoveData, resultat); // sur la pseudo-checkbox
		Amed.Event.add(resultat.labelTag, 'click', addRemoveData, resultat); // sur le label
		
		return kchilds[k].parentNode.appendChild(tick);
	}
	function appendSearchBox(){
		var f = document.createDocumentFragment(),
			f1 = document.createElement('div'),
			f11 = document.createElement('input'),
			f12 = document.createElement('div'),
			f2 = document.createElement('dl'),
			f21 = document.createElement('dt'),
			f211 = document.createTextNode(i18n.get('Vos favoris :')),
			f22 = document.createElement('dd'),
			f3 = document.createElement('div'),
			f30 = document.createElement('a'),
			f301 = document.createElement('img'),
			f302 = document.createTextNode(i18n.get(' Obtenir de l\'aide')),
			f31 = document.createElement('button'),
			f311 = document.createElement('img'),
			f312 = document.createTextNode(i18n.get(' télécharger les données favorites')),
			f32 = document.createElement('button'),
			f321 = document.createElement('img'),
			f322 = document.createTextNode(i18n.get(' télécharger les données sélectionnées'));
		
		// bloc recherche
		f1.setAttribute('id', 'searchInput');
		f11.setAttribute('type', 'text');
		f11.setAttribute('value', i18n.get('rechercher une donnée…'));
		
		Amed.Event.add(f11, 'focus', flushDefaultValue);
		Amed.Event.add(f11, 'keyup', SE);
		Amed.Event.add(f11, 'keypress', function(e){ if(e.keyCode == 13) e.preventDefault(); }); // pas de submit via la touche entrée
		Amed.Event.add(document, 'click', toggleSearchResults, f1);
		f11.previous = []; // buffer pour la recherche incrémentale
		
		// boutons
		f3.setAttribute('id', 'headSubmit');
		f30.setAttribute('id', 'downloadHelp');
		f30.setAttribute('href', '../services/aide.jsp#espaceDl');
		f301.setAttribute('src', '../../../images/all/all/help_ctn.png');
		f31.setAttribute('type', 'button');
		f311.setAttribute('src', '../../../images/all/all/dl_icon_fav_small.png');
		f311.setAttribute('alt', '');
		f32.setAttribute('type', 'submit');
		f321.setAttribute('src', '../../../images/all/all/icon_data_small.png');
		f321.setAttribute('alt', '');
		
		Amed.Event.add(f31, 'click', requestFavData);
		Amed.Event.add(f32, 'click', function(e){ e.preventDefault(); Amed.DOM.$('dlSpaceForm').submit(); });
		
		f.appendChild(f1);
			f1.appendChild(f11);
			f1.appendChild(f12);
		f.appendChild(f2);
			f2.appendChild(f21);
				f21.appendChild(f211);
			f2.appendChild(f22);
				f22.innerHTML = getFavData();
		f.appendChild(f3);
			f3.appendChild(f30);
				f30.appendChild(f301);
				f30.appendChild(f302);
			f3.appendChild(f31);
				f31.appendChild(f311);
				f31.appendChild(f312);
			f3.appendChild(f32);
				f32.appendChild(f321);
				f32.appendChild(f322);
		
		var insertTarget = Amed.DOM.$('dlSpaceHead');
		insertTarget.innerHTML = '';
		insertTarget.appendChild(f);
		insertTarget.setAttribute('id', 'dlSearch');
		window.favBox = f22;
		window.resultBox = f12;
		
		// duplicata pour le footer
		var f31alt = f31.cloneNode(true);
		Amed.Event.add(f31alt, 'click', requestFavData);
		var dlFoot = document.getElementById('dlSpaceFoot');
		dlFoot.insertBefore(f31alt, dlFoot.getElementsByTagName('button')[0]);
	}
	function getFavData(){
		var tfav = [], tlink = ['<a href="',,i18n.get('" target="_blank" title="visualiser la donnée">'),,'</a>']
		for(var i = favsl; i--;){
			try{
				var data = getDataFromGuid(favs[i]);
				tlink[1] = data.visuLink;
				tlink[3] = data.label;
				tfav.push(tlink.join(''));
			}
			catch(e){
				//alert('fav n' + favs[i] + 'supprime');
			}
		}
		if(!favsl) return i18n.get('<span>vous n\'avez pas de favoris</span>')
		return tfav.join('');
	}
	
	for(var i = indexables.length; i--;){
		var db1 = {}, db2, db3, // variables tampon des mots
			t1,	t2, t3, // variables tampon des valeurs textuelles
			e1, e2, e3; // variables tampon de différents Nodes
		
		Amed.DOM.addClassName(indexables[i], 'jsExtendedDownload'); // pour l'apparence
		
		e1 = indexables[i].getElementsByTagName('dt')[0]; // en-tête de premier niveau
		e2 = indexables[i].getElementsByTagName('dd')[0]; // enveloppe du corps du bloc
		e3 = indexables[i].getElementsByTagName('dl')[0]; // corps du bloc
		
		t1 = trim(Amed.DOM.getAggregateTextValue(e1)); // stocke dans t1
		cleanAndIndex(t1, db1);
		db2 = objExtend(db1); // réinitialise l'index de second niveau pour ne pas hériter du bloc précédent
		
		appendToggle(e1, e2, t1.toLowerCase(), 'lvl1-' + i); // rajoute la bascule
		
		for(var j = 0,
				jchilds = e3.childNodes,
				jlength = jchilds.length; j < jlength; j++){ // pour chaque élèment dans le bloc
			
			if (jchilds[j].tagName == 'DT'){ // si en-tête de second niveau stocke dans t2
				t2 = trim(Amed.DOM.getAggregateTextValue(jchilds[j]));
				db2 = objExtend(db1);
				cleanAndIndex(t2, db2);
				
				var next = jchilds[j].nextSibling;
				while(next.nodeType != Amed.DOM.ELEMENT_NODE && next.tagName != 'DD') next = next.nextSibling;
				appendToggle(jchilds[j], next, t2.toLowerCase(), 'lvl2-' + i + j); // rajoute la bascule
			}
			else if (jchilds[j].tagName == 'DD'){ // si liste de données (troisième niveau)
				for(var k = 0,
						kchilds = jchilds[j].getElementsByTagName('LABEL'),
						klength = kchilds.length; k < klength; k++){
					
					t3 = trim(Amed.DOM.getAggregateTextValue(kchilds[k])); // stocke dans t3
					db3 = objExtend(db2);
					cleanAndIndex(t3, db3);
					
					var resultat = {}; // prépare le résultat pour l'index
					/*
					 * resultat = {
					 * 	path: String[], // toutes les étapes de l'arborescence
					 * 	label: String, // intitulé de l'élèment en bas de casse
					 * 	wdb: { // = word database
					 * 		'word': {
					 * 			explode: Char[], // intitulé de l'élèment nettoyé et splitté pour levenshtein
					 * 			exl: int // explode.length
					 * 		},
					 * 		... avec n 'word' ou n[path.length, POSITIVE_INFINITY]
					 * 	},
					 * 	guid: String, // identifiant de l'élèment
					 * 	favLink: Node<a>, // lien "étoile" rajouter/retirer des favoris
					 * 	favStatus: Boolean, // l'élement est il en favoris ?
					 * 	labelTag: Node<label>, // intitulé de la donnée
					 * 	checkbox: Node<input>, // checkbox
					 * 	visuLink: String, // lien pour visualiser la donnée
					 * 	checkLink: Node<a> // lien "checkbox" sélectionner/déselectionner la donnée
					 * }
					 */
					if(t2) resultat.path = [t1, t2, t3];
					else   resultat.path = [t1, t3];
					resultat.label = t3.toLowerCase();
					resultat.wdb = db3;
					resultat.guid = kchilds[k].getAttribute('for') || kchilds[k].getAttribute('htmlFor');
					resultat.favStatus = false;
					if(Amed.Cookie.isEnabled){
						for (l = favsl; l--;) if (favs[l] === resultat.guid) {
							resultat.favStatus = true;
							break;
						}
						resultat.favLink = appendFav(); // rajoute l'étoile
					}
					resultat.labelTag = kchilds[k];
					resultat.checkbox = kchilds[k].parentNode.getElementsByTagName('input')[0];
					resultat.visuLink = kchilds[k].parentNode.getElementsByTagName('a')[0].getAttribute('href', 2);
					resultat.checkLink = apendTick(); // remplace la checkbox native
					
					indexes.n = indexes.push(resultat);
				}
				t2 = ''; db2 = objExtend(db1); // réinitialise l'en-tête de second niveau
			}	
		}
	}
	appendSearchBox();
}

function getDataFromGuid(guid){
	for(var i = indexes.n; i--;){
		if(indexes[i].guid === guid) return indexes[i];
	}
}

function toggleDlGroup(e, toggle, label, group, guid){
	e.preventDefault();
	if(Amed.DOM.hasClassName(toggle, 'toggleOff')){ // si état courant est fermé
		toggle.className = 'toggleOn';
		toggle.setAttribute('title', i18n.get('masquer ') + label);
		group.style.display = 'block';
		
		Amed.Cookie.insert('dlTog', guid);
	}else{
		toggle.className = 'toggleOff';
		toggle.setAttribute('title', i18n.get('afficher ') + label);
		group.style.display = 'none';
		
		Amed.Cookie.extract('dlTog', guid);
	}
}
function toggleSearchResults(e, searchBox){
	if(e.target != searchBox && !Amed.DOM.isAChildOfB(e.target, searchBox)){
		resultBox.style.display = 'none';
	} else {
		resultBox.style.display = 'block';
	}
}

function addRemoveFavData(e, data){
	e.preventDefault();
	if(data.favStatus){ // si est déjà en favoris : retire
		data.favLink.className = 'favOff';
		data.favLink.setAttribute('title', i18n.get('ajouter "') + data.label + i18n.get('" aux favoris'));
		Amed.Cookie.extract('dlFav', data.guid);
		if (!Amed.Cookie.read('dlFav')) { // si plus de favoris du tout
			favBox.innerHTML = i18n.get('<span>vous n\'avez pas de favoris</span>');
		} else {
			var topFavLink = Amed.DOM.getElementsByAttribute('href', data.visuLink, favBox)[0];
			favBox.removeChild(topFavLink);
		}
		data.favStatus = false;
	}else{ // sinon : ajoute
		if(!Amed.Cookie.read('dlFav')) favBox.innerHTML = ''; // si pas de favoris retire la mention 'vous n'avez pas de favoris'
		data.favLink.className = 'favOn';
		data.favLink.setAttribute('title', i18n.get('retirer "') + data.label + i18n.get('" des favoris'));
		Amed.Cookie.insert('dlFav', data.guid);
		
		var topFavLink = document.createElement('a');
		topFavLink.setAttribute('href', data.visuLink);
		var topFavLabel = document.createTextNode(data.label);
		topFavLink.appendChild(topFavLabel);
		favBox.appendChild(topFavLink);
		data.favStatus = true;
	}
}
function addRemoveFavDataFromSR(guid){ // depuis les résultats de recherche, fonction passerelle
	var data = getDataFromGuid(guid),
		SRfavLink = document.getElementById('SR' + guid).getElementsByTagName('a')[0];
	
	if(data.favStatus){ // si est déjà en favoris : retire
		SRfavLink.className = 'favOff';
		SRfavLink.setAttribute('title', i18n.get('ajouter "') + data.label + i18n.get('" aux favoris'));
	}else{ // sinon : ajoute
		SRfavLink.className = 'favOn';
		SRfavLink.setAttribute('title', i18n.get('retirer "') + data.label + i18n.get('" des favoris'));
	}
	addRemoveFavData(new Amed.Event.DummyEvent, data)
}
function addRemoveData(e, data){
	e.preventDefault();
	if(!data.checkbox.checked){ // si n'est pas coché : coche
		data.checkLink.className = 'tickOn';
		data.checkLink.setAttribute('title', i18n.get('ne pas télécharger "') + data.label.toLowerCase() + '"');
		data.labelTag.setAttribute('title', i18n.get('ne pas télécharger "') + data.label.toLowerCase() + '"');
		data.checkbox.checked = true;
	} else { // sinon : retire
		data.checkLink.className = 'tickOff';
		data.checkbox.setAttribute('title', i18n.get('télécharger "') + data.label.toLowerCase() + '"');
		data.labelTag.setAttribute('title', i18n.get('télécharger "') + data.label.toLowerCase() + '"');
		data.checkbox.checked = false;
	}
}
function addRemoveDataFromSR(guid){ // depuis les résultats de recherche, fonction passerelle
	var data = getDataFromGuid(guid),
		SRcheckLink = document.getElementById('SR' + guid).getElementsByTagName('a')[1];
	
	if(!data.checkbox.checked){ // si n'est pas coché : coche
		SRcheckLink.className = 'tickOn';
		SRcheckLink.setAttribute('title', i18n.get('ne pas télécharger "') + data.label.toLowerCase() + '"');
	}else{ // sinon : retire
		SRcheckLink.className = 'tickOff';
		SRcheckLink.setAttribute('title', i18n.get('télécharger "') + data.label.toLowerCase() + '"');
	}
	addRemoveData(new Amed.Event.DummyEvent, data)
}
function requestFavData(e){ // télécharger les données favorites
	e.preventDefault();
	var favs = Amed.Cookie.dump('dlFav'),
		query = document.location.href;
	if(!favs.length) return;
	
	//query = query.substr(0, query.indexOf('?')) + '?' + favs.join('=on&') + '=on';
	query = document.getElementById('dlSpaceForm').getAttribute('action') + '?' + favs.join('=on&') + '=on';
	document.location.replace(query);
}

function indexMatchWord(ind, wrd){ // fonction de recherche, retourne les index avec une distance de levenshtein =< n (n=2)
	var tInd0 =[], tInd1 =[], tInd2 =[]; // index temporaires ordonnés par précision des résultats
	for(var i = ind.n; i--;){ // pour chaque entrée dans l'index
		for(var j in ind[i].wdb){ // pour chaque mot de cette entrée
			var distance = olevenshtein(wrd, ind[i].wdb[j]); // compare le mot
			if(distance < 3){ // si le mot correspond à au moins deux caractères près
				if(distance == 0) tInd0.push(ind[i]);
				else if(distance == 1) tInd1.push(ind[i]);
				else if(distance == 2) tInd2.push(ind[i]);
				break;
			}
		}
	}
	return tInd2.concat(tInd1, tInd0); // concat du moins au plus précis car résultats itérés à l'envers
}
function SE(e){ // fonction de recherche, prétraitement + print
	e.preventDefault();
	var s = this.value.toLowerCase().replace(/[éèê]/g, 'e').split(/[\s\(\)\'\,\/\-]+/), // nettoie l'entrée utilisateur
		sl = s.length, // optim
		cdb = [], // compare database
		cdbl, // optim
		ind = indexes, // par défaut, toutes les données indexées
		refresh = false; // doit on rafraichir les résultats ?
	
	for (var i = 0; i < sl; i++) if (s[i].length > 2) { // ne compare que les strings d'au moins 3 lettres
		var data = {};
		data.str = s[i]; // mémorise pour faire une recherche incrémentale
		data.explode = s[i].split('');  // préparation des données pour l'algo de levenshtein
		data.exl = data.explode.length; // préparation des données pour l'algo de levenshtein
		cdbl = cdb.push(data);
	}
	//console.time('levenshtein');
	if (cdbl) { // si des entrées à comparer
		for (var i = 0; i < cdbl; i++) {
			if (this.previous[i]) {
				if (this.previous[i].str == cdb[i].str) { // déjà traité
					ind = this.previous[i].ind; // importe les derniers résultats
					continue; // passe au mot suivant
				}
				if (cdb[i].str.indexOf(this.previous[i].str) == 0) {
					ind = this.previous[i].ind; // reprendre à partir de ce niveau
					this.previous = this.previous.slice(0, i); // réinitialise les résultats suivants qui ne sont plus fiables
				}
				else this.previous = this.previous.slice(0, i); // réinitialise les résultats suivants qui ne sont plus fiables
			}
			refresh = true;
			ind = indexMatchWord(ind, cdb[i]);
			ind.n = ind.length;
			this.previous[i] = { // enregistre dans le buffer
				'str': cdb[i].str,
				'ind': ind
			};
		}
	}
	if(refresh){
		//console.log('nombres de résultats trouvée pour "' + this.value + '": ' + ind.n);
		var r = [];
		var tempString1 = ['<div id="SR',,'"><span><img src="../../../images/all/all/small_arrow_gray.gif" alt="" />',,'<img src="../../../images/all/all/small_arrow_gray.gif" alt="" />',,'</span><a href="#" onclick="addRemoveFavDataFromSR(\'',,'\'); return false;" class="fav',,'" title="',,' &quot;',,'&quot; ',,'"></a><a href="#" onclick="addRemoveDataFromSR(\'',,'\'); return false;" class="tick',,'" title="',,' &quot;',,'&quot;"></a>',,'</div>'];
		var tempString2 = ['<div id="SR',,'"><span><img src="../../../images/all/all/small_arrow_gray.gif" alt="" />',,'</span><a href="#" onclick="addRemoveFavDataFromSR(\'',,'\'); return false;" class="fav',,'" title="',,' &quot;',,'&quot; ',,'"></a><a href="#" onclick="addRemoveDataFromSR(\'',,'\'); return false;" class="tick',,'" title="',,' &quot;',,'&quot;"></a>',,'</div>'];
		for(var i = ind.n; i--;){
			if (ind[i].path[2]) {
				tempString1[1] = tempString1[7] = tempString1[17] = ind[i].guid;
				tempString1[3] = ind[i].path[0];
				tempString1[5] = ind[i].path[1];
				if(ind[i].favStatus){
					tempString1[9]  = 'On';
					tempString1[11] = i18n.get('retirer');
					tempString1[15] = i18n.get('des favoris');
				}else{
					tempString1[9]  = 'Off';
					tempString1[11] = i18n.get('ajouter');
					tempString1[15] = i18n.get('aux favoris');
				}
				tempString1[13] = tempString1[23] = tempString1[25] = ind[i].path[2];
				if(ind[i].checkbox.checked){
					tempString1[19] = 'On';
					tempString1[21] = i18n.get('ne pas télécharger');
				}else{
					tempString1[19] = 'Off';
					tempString1[21] = i18n.get('télécharger');
				}
				r.push(tempString1.join(''));
			} else {
				tempString2[1] = tempString2[5] = tempString2[15] = ind[i].guid;
				tempString2[3] = ind[i].path[0];
				if(ind[i].favStatus){
					tempString2[7]  = 'On';
					tempString2[9]  = i18n.get('retirer');
					tempString2[13] = i18n.get('des favoris');
				}else{
					tempString2[7]  = 'Off';
					tempString2[9]  = i18n.get('ajouter');
					tempString2[13] = i18n.get('aux favoris');
				}
				tempString2[11] = tempString2[21] = tempString2[23] = ind[i].path[1];
				if(ind[i].checkbox.checked){
					tempString2[17] = 'On';
					tempString2[19] = i18n.get('ne pas télécharger');
				}else{
					tempString2[17] = 'Off';
					tempString2[19] = i18n.get('télécharger');
				}
				r.push(tempString2.join(''));
			}
		}
		resultBox.innerHTML = r.join('');
	}
	//console.timeEnd('levenshtein');
}
function flushDefaultValue(e){ // reset le champ de recherche
	this.value = '';
	Amed.Event.remove(this, 'focus', flushDefaultValue);
	resultBox.style.display = 'block';
}

/*
 * initialisation
 * 
 */

Amed.Event.add(document, 'DOMContentLoaded', initDlSpace);


/*
 * calcul de la distance de levenshtein
 * 
 */
function olevenshtein(a, b){
	var im, jm, c,
	    as = a.explode, bs = b.explode, al = a.exl, bl = b.exl,
		cl = al, clm = cl - 1, // on compare les chaines par rapport à la longueur de l'entrée utilisateur
		LV = 0, FLV = 0, LC = [],
		x, y, z;
	
	for (var i = 0; i < cl;) LC[i] = ++i;
	for (var j = 1; j <= cl; j++){
		jm = j - 1;
		for (var i = 0; i < cl; i++){
			im = i - 1;
			c = as[jm] === bs[i];
			if (c){
				FLV = LV;
				if (i){
					LV = LC[im];
					LC[im] = FLV;
					if (i === clm) LC[i] = LV;
				}
				else LV = jm;
			} else {
				if (i){
					x = LV + 1;
					y = LC[i] + 1;
					z = LC[im] + 1;
					
					FLV = LV;
					LV = Math.min(x, y, z);
					LC[im] = FLV;
					if (i === clm) LC[i] = LV;
				} else {
					x = j + 1;
					y = LC[i] + 1;
					z = j;
					
					FLV = LV;
					LV = Math.min(x, y, z);
				}
			}
		}
	}
	return LV;
}

