// lib.js

var BrowserDetect = {
	init: function () {
		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
		this.version = this.searchVersion(navigator.userAgent)
			|| this.searchVersion(navigator.appVersion)
			|| "an unknown version";
		this.OS = this.searchString(this.dataOS) || "an unknown OS";
	},
	searchString: function (data) {
		for (var i=0; i < data.length; i++)	{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1)
					return data[i].identity;
			}
			else if (dataProp)
				return data[i].identity;
		}
	},
	searchVersion: function (dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) return;
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	},
	dataBrowser: [
		{
			string: navigator.userAgent,
			subString: "Chrome",
			identity: "Chrome"
		},
		{	string: navigator.userAgent,
			subString: "OmniWeb",
			versionSearch: "OmniWeb/",
			identity: "OmniWeb"
		},
		{
			string: navigator.vendor,
			subString: "Apple",
			identity: "Safari",
			versionSearch: "Version"
		},
		{
			prop: window.opera,
			identity: "Opera"
		},
		{
			string: navigator.vendor,
			subString: "iCab",
			identity: "iCab"
		},
		{
			string: navigator.vendor,
			subString: "KDE",
			identity: "Konqueror"
		},
		{
			string: navigator.userAgent,
			subString: "Firefox",
			identity: "Firefox"
		},
		{
			string: navigator.vendor,
			subString: "Camino",
			identity: "Camino"
		},
		{		// for newer Netscapes (6+)
			string: navigator.userAgent,
			subString: "Netscape",
			identity: "Netscape"
		},
		{
			string: navigator.userAgent,
			subString: "MSIE",
			identity: "Explorer",
			versionSearch: "MSIE"
		},
		{
			string: navigator.userAgent,
			subString: "Gecko",
			identity: "Mozilla",
			versionSearch: "rv"
		},
		{		// for older Netscapes (4-)
			string: navigator.userAgent,
			subString: "Mozilla",
			identity: "Netscape",
			versionSearch: "Mozilla"
		}
	],
	dataOS : [
		{
			string: navigator.platform,
			subString: "Win",
			identity: "Windows"
		},
		{
			string: navigator.platform,
			subString: "Mac",
			identity: "Mac"
		},
		{
			string: navigator.userAgent,
			subString: "iPhone",
			identity: "iPhone/iPod"
		},
		{
			string: navigator.platform,
			subString: "Linux",
			identity: "Linux"
		}
	]

};

BrowserDetect.init();


// --------------------------------


function IEgetElementsByClassName(className) {
	var hasClassName = new RegExp("(?:^|\\s)" + className + "(?:$|\\s)");
	var allElements = document.getElementsByTagName("*");
	var results = [];

	var element;
	for (var i = 0; (element = allElements[i]) != null; i++) {
		var elementClass = element.className;
		if (elementClass && elementClass.indexOf(className) != -1 && hasClassName.test(elementClass))
			results.push(element);
	}

	return results;
}


// --------------------------------


function print_r(obj) {
	win_print_r = window.open('about:blank', 'win_print_r');
	win_print_r.document.write('<html><body>');
	r_print_r(obj, win_print_r);
	win_print_r.document.write('</body></html>');
}

function r_print_r(theObj, win_print_r) {

	if(theObj.constructor == Array || theObj.constructor == Object) {
		if (win_print_r == null)
		win_print_r = window.open('about:blank', 'win_print_r');
	}

	for (var p in theObj) {
		if(theObj[p].constructor == Array|| theObj[p].constructor == Object) {
			win_print_r.document.write("<li>["+p+"] =>"+typeof(theObj)+"</li>");
			win_print_r.document.write("<ul>")
			r_print_r(theObj[p], win_print_r);
			win_print_r.document.write("</ul>")
		} else {
			win_print_r.document.write("<li>["+p+"] =>"+theObj[p]+"</li>");
		}
	}

	win_print_r.document.write("</ul>")
}


// --------------------------------


function XHRConnection() {
// + --------------------------------------------------------------------------------------
// + XHRConnection
// + V1.3
// + Thanh Nguyen, http://www.sutekidane.net
// + 20.10.2005
// + http://creativecommons.org/licenses/by-nc-sa/2.0/fr/deed.fr
// + --------------------------------------------------------------------------------------

	// + ----------------------------------------------------------------------------------
	var conn = false;
	var debug = false;
	var datas = new String();
	var areaId = new String();
	// Objet XML
	var xmlObj;
	// Type de comportement au chargement du XML
	var xmlLoad;

	// + ----------------------------------------------------------------------------------
	try {
		conn = new XMLHttpRequest();
	}
	catch (error) {
		if (debug) { alert('Erreur lors de la tentative de création de l\'objet \nnew XMLHttpRequest()\n\n' + error); }
		try {
			conn = new ActiveXObject("Microsoft.XMLHTTP");
		}
		catch (error) {
			if (debug) { alert('Erreur lors de la tentative de création de l\'objet \nnew ActiveXObject("Microsoft.XMLHTTP")\n\n' + error); }
			try {
				conn = new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch (error) {
				if (debug) { alert('Erreur lors de la tentative de création de l\'objet \nnew ActiveXObject("Msxml2.XMLHTTP")\n\n' + error); }
				conn = false;
			}
		}
	}

	// + ----------------------------------------------------------------------------------
	// + setDebugOff
	// + Désactive l'affichage des exceptions
	// + ----------------------------------------------------------------------------------
	this.setDebugOff = function() {
		debug = false;
	};

	// + ----------------------------------------------------------------------------------
	// + setDebugOn
	// + Active l'affichage des exceptions
	// + ----------------------------------------------------------------------------------
	this.setDebugOn = function() {
		debug = true;
	};

	// + ----------------------------------------------------------------------------------
	// + resetData
	// + Permet de vider la pile des données
	// + ----------------------------------------------------------------------------------
	this.resetData = function() {
		datas = new String();
		datas = '';
	};

	// + ----------------------------------------------------------------------------------
	// + appendData
	// + Permet d'empiler des données afin de les envoyer
	// + ----------------------------------------------------------------------------------
	this.appendData = function(pfield, pvalue) {
		datas += (datas.length == 0) ? pfield+ "=" + escape(pvalue) : "&" + pfield + "=" + escape(pvalue);
	};

	// + ----------------------------------------------------------------------------------
	// + setRefreshArea
	// + Indique quel elment identifié par id est valoris lorsque l'objet XHR reoit une réponse
	// + ----------------------------------------------------------------------------------
	this.setRefreshArea = function(id) {
		areaId = id;
	};

	// + ----------------------------------------------------------------------------------
	// + createXMLObject
	// + Méthode permettant de créer un objet DOM, retourne la réfrence
	// + Inspiré de: http://www.quirksmode.org/dom/importxml.html
	// + ----------------------------------------------------------------------------------
	this.createXMLObject = function() {
		try {
				xmlDoc = document.implementation.createDocument("", "", null);
				xmlLoad = 'onload';
		}
		catch (error) {
			try {
				xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
				xmlLoad = 'onreadystatechange ';
			}
			catch (error) {
				if (debug) { alert('Erreur lors de la tentative de création de l\'objet XML\n\n'); }
				return false;
			}
		}
		return xmlDoc;
	}

	// + ----------------------------------------------------------------------------------
	// + Permet de définir l'objet XML qui doit être valorisé lorsque l'objet XHR reoit une réponse
	// + ----------------------------------------------------------------------------------
	this.setXMLObject = function(obj) {
		if (obj == undefined) {
				if (debug) { alert('Paramètre manquant lors de l\'appel de la méthode setXMLObject'); }
				return false;
		}
		try {
			//xmlObj = this.createXMLObject();
			xmlObj = obj;
		}
		catch (error) {
				if (debug) { alert('Erreur lors de l\'affectation de l\'objet XML dans la méthode setXMLObject'); }
		}
	}

	// + ----------------------------------------------------------------------------------
	// + loadXML
	// + Charge un fichier XML
	// + Entrées
	// +	xml			String		Le fichier XML à charger
	// + ----------------------------------------------------------------------------------
	this.loadXML = function(xml, callBack) {
		if (!conn) return false;
		// Chargement pour alimenter un objet DOM
		if (xmlObj && xml) {
			if (typeof callBack == "function") {
				if (xmlLoad == 'onload') {
					xmlObj.onload = function() {
						callBack(xmlObj);
					}
				}
				else {
					xmlObj.onreadystatechange = function() {
						if (xmlObj.readyState == 4) callBack(xmlObj)
					}
				}
			}
			xmlObj.load(xml);
			return;
		}
	}

	// + ----------------------------------------------------------------------------------
	// + sendAndLoad
	// + Connexion à la page désirée avec envoie des données, puis mise en attente de la réponse
	// + Entrées
	// +	Url			String		L'url de la page à laquelle l'objet doit se connecter
	// +	httpMode		String		La méthode de communication HTTP : GET, HEAD ou POST
	// +	callBack		Objet		Le nom de la fonction de callback
	// + ----------------------------------------------------------------------------------
	this.sendAndLoad = function(Url, httpMode, callBack) {
		httpMode = httpMode.toUpperCase();
		conn.onreadystatechange = function() {
			if (conn.readyState == 4 && conn.status == 200) {
				// Si une fonction de callBack a été définie
				if (typeof callBack == "function") {
					callBack(conn);
					return;
				}
				// Si une zone destinée à récupérer le résultat a été définie
				else if (areaId.length > 0){
					try {
						document.getElementById(areaId).innerHTML = conn.responseText;
					}
					catch(error) {
						if (debug) { alert('Echec, ' + areaId + ' n\'est pas un objet valide'); }
					}
					return;
				}
			}
		};
		switch(httpMode) {
			case "GET":
				try {
					Url = (datas.length > 0) ? Url + "?" + datas : Url;
					conn.open("GET", Url);
					conn.send(null);
				}
				catch(error) {
					if (debug) { alert('Echec lors de la transaction avec ' + Url + ' via la méthode GET'); }
					return false;
				}
			break;
			case "POST":
				try {
					conn.open("POST", Url);
					conn.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
					conn.send(datas);
				}
				catch(error) {
					if (debug) { alert('Echec lors de la transaction avec ' + Url + ' via la mthode POST'); }
					return false;
				}
			break;
			default :
				return false;
			break;
		}
		return true;
	};
	return this;
}


// --------------------------------


function addOnLoadEvent(func) {
	var oldOnLoad = window.onload;
	window.onload = (typeof window.onload != 'function') ? func : function () {if (oldOnLoad) oldOnLoad(); func()};
}


// --------------------------------


function hideItem(obj) {obj.style.visibility = 'hidden'}
function showItem(obj) {obj.style.visibility = 'visible'}


// --------------------------------


function setCursorAtEnd(obj) {
	if (obj) {
		if (obj.collapse) { // IE
//			var r = (obj.createTextRange());
//			r.moveStart('character', (obj.value.length));
			r.collapse(false);
//			r.select();
		} else if (obj.setSelectionRange) { // moz
			obj.setSelectionRange(obj.value.length, obj.value.length);
		}
	}
}


// --------------------------------


function getMouseCoords(ev) {
	ev = window.event || ev;
	clientx = ev.clientX;
	clienty = ev.clientY;
}


// --------------------------------
// common section
// --------------------------------


// constants
var LANG, PATH;

var search_form_name = 'search_form';
var search_form;
var search_field_name = 'search_field';
var search_field;
var search_result_name = 'search_result';
var search_result;

var li_select;		// line selected
var mli_select;		// memory of line selected; used when switching line
var li_over;		// line highlighted;
var mli_over;		// memory of line highlighted; used when switching line
var mvalue;			// memory of value entered; used when returning to entered value (first position or escape)
var fvalue;			// memory of input field; used for field change detection (before and after key)

// used to avoid unwanted over trigger
var clientx, clienty, mclientx, mclienty;


// --------------------------------


function initSearch(lang, path) {
	LANG = lang;
	PATH = path;

	search_form = document.getElementById(search_form_name);
	search_field = document.getElementById(search_field_name);
	search_result = document.getElementById(search_result_name);

	search_form.onsubmit = resetSearch;
	search_field.setAttribute('autocomplete', 'off');
	if (BrowserDetect.browser == 'Firefox') {
		search_field.onkeypress = function(event) {navigateList(this, event)};
	} else {
		search_field.onkeydown = function(event) {navigateList(this, event)};
	}
	search_field.onkeyup = function(event) {updateList(this, event)};
	search_field.onblur = function() {hideItem(search_result)};

	resetSearch();
}

function resetSearch() {
	search_result.innerHTML = '';
	li_select = -1;
	mli_select = li_select;
	li_over = -1;
	mli_over = li_over;
	mvalue = '';
	hideItem(search_result);
}


// --------------------------------


function navigateList(obj, ev) {
	ev = window.event || ev;
	var eCode = (ev.keyCode != '0') ? ev.keyCode : ev.charCode;
	fvalue = obj.value;

	switch (eCode) {

	case 38:	// up key
	case 40:	// down key
		var li_offset = 1;

		// try to make list visible by any mean ...

		if (search_result.style.visibility == 'hidden') { // list invisible
			li_offset = 0;

			if (search_result.getElementsByTagName('div').length == 0) { // list empty
				if (obj.value != '')
					queryResult(obj, ev); // if value non-empty query result
			} else { // list non-empty
				showItem(search_result);
			} // if list empty/non-empty
		} // if list invisible

		// ... then eventually process list

		if (search_result.style.visibility == 'visible') { // list visible
			var r_length = search_result.getElementsByTagName('div').length;

			li_select = (eCode == '38') ?
				(((li_select - li_offset) > -2) ? li_select - li_offset	 : r_length - 1) :
				(((li_select + li_offset) < r_length) ? li_select + li_offset : -1);

			if (mli_select != li_select) {
				if (mli_select > -1)
					search_result.getElementsByTagName('div')[mli_select].className = 'passive';
				if (li_select > -1)
					search_result.getElementsByTagName('div')[li_select].className = 'active';

				mli_select = li_select;
				li_over = li_select;
				mli_over = li_over;
			} // if mli_select != li_select

			obj.value = (li_select == -1) ?
				mvalue :
				search_result.getElementsByTagName('div')[li_select].innerHTML;

			if (ev.preventDefault) ev.preventDefault(); // moz only
//			setCursorAtEnd(obj);

			mclientx = clientx;
			mclienty = clienty;
		} // if list visible

		break;

	case 27:	// escape key
		obj.value = mvalue;
		hideItem(search_result);
		break;

	} // switch key
}


// --------------------------------


function updateList(obj, ev) {
	ev = window.event || ev;
	var eCode = (ev.keyCode != '0') ? ev.keyCode : ev.charCode;

	switch (eCode) { // key

	case 37:	// left
	case 38:	// up
	case 39:	// right
	case 40:	// down

	case 16:	// shift
	case 17:	// ctrl
	case 18:	// alt
	case 224:	// cmd

	case 27:	// esc
		break;

	case 13:	// enter
		hideItem(search_result);
		resetSearch();
		break;

	default:
		if (obj.value != fvalue) {
			if (obj.value != '') { // entry not empty
				queryResult(obj, ev);

			} else { // entry empty
				search_result.innerHTML = '';
				hideItem(search_result);

			} // if entry not empty/empty

			fvalue = obj.value;
			mvalue = obj.value;
			li_select = -1;
			li_over = -1;
			mli_select = li_select;
			mli_over = li_over;
		}
	} // switch key
}


// --------------------------------


function queryResult(obj, ev) {
	var XHR = new XHRConnection();
	XHR.appendData('lang', LANG);
	XHR.appendData('key', obj.value);
	XHR.sendAndLoad(PATH + 'search/php/query_words.php', 'GET', function(obj, ev) {updateResult(obj)});
}

// --------------------------------


function updateResult(obj) {
	obj = obj.responseText;
	search_result.innerHTML = '';

	if (obj != '') { // result non empty
		var o_items = eval('(' + obj + ')');

		for (i in o_items.items) {
			var li_item = document.createElement('div');
			li_item.id = 'srli_' + i;
			li_item.className = 'passive';
			li_item.onmouseover = function() {highLightItem(this)};
			li_item.onmousedown = function() {search_field.value = this.innerHTML; search_form.submit()};
			li_item.appendChild(document.createTextNode(o_items.items[i].value));
			search_result.appendChild(li_item);
		}

		if (search_result.style.visibility == 'hidden')
			showItem(search_result);

	} else { // result empty
		if (search_result.style.visibility == 'visible')
			hideItem(search_result);

	} // if result non empty/empty

	mvalue = search_field.value;
	mclientx = clientx;
	mclienty = clienty;
}


// --------------------------------


function highLightItem(obj) {
	if (clientx != mclientx || clienty != mclienty) {
		li_over = Number(obj.id.substr(obj.id.length - 1, 1));

		if (mli_over != li_over) {
			if (mli_over != -1)
				search_result.getElementsByTagName('div')[mli_over].className = 'passive';
			obj.className = 'active';
			mli_over = li_over;
			li_select = li_over;
			mli_select = li_select;
		}

		mclientx = clientx;
		mclienty = clienty;
	}
}
