/*
 * OpenSearch ajax suggestion engine for MediaWiki
 *
 * uses core MediaWiki open search support to fetch suggestions
 * and show them below search boxes and other inputs
 *
 * by Robert Stojnic (April 2008)
 */

// search_box_id -> Results object
var os_map = {};
// cached data, url -> json_text
var os_cache = {};
// global variables for suggest_keypress
var os_cur_keypressed = 0;
var os_last_keypress = 0;
var os_keypressed_count = 0;
// type: Timer
var os_timer = null;
// tie mousedown/up events
var os_mouse_pressed = false;
var os_mouse_num = -1;
// if true, the last change was made by mouse (and not keyboard)
var os_mouse_moved = false;
// delay between keypress and suggestion (in ms)
var os_search_timeout = 250;
// these pairs of inputs/forms will be autoloaded at startup
var os_autoload_inputs = new (Array)('searchInput', 'searchInput2', 'powerSearchText', 'searchText');
var os_autoload_forms = new (Array)('searchform', 'searchform2', 'powersearch', 'search' );
// if we stopped the service
var os_is_stopped = false;
// max lines to show in suggest table
var os_max_lines_per_suggest = 7;
// number of steps to animate expansion/contraction of container width
var os_animation_steps = 6;
// num of pixels of smallest step
var os_animation_min_step = 2;
// delay between steps (in ms)
var os_animation_delay = 30;
// max width of container in percent of normal size (1 == 100%)
var os_container_max_width = 2;
// currently active animation timer
var os_animation_timer = null;

/** Timeout timer class that will fetch the results */
function os_Timer(id,r,query) {
	this.id = id;
	this.r = r;
	this.query = query;
}

/** Timer user to animate expansion/contraction of container width */
function os_AnimationTimer(r, target) {
	this.r = r;
	var current =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.container).offsetWidth;
	this.inc = Math.round((target-current) / os_animation_steps);
	if(this.inc < os_animation_min_step && this.inc >=0)
		this.inc = os_animation_min_step; // minimal animation step
	if(this.inc > -os_animation_min_step && this.inc <0)
		this.inc = -os_animation_min_step;
	this.target = target;
}

/** Property class for single search box */
function os_Results(name, formname) {
	this.searchform = formname; // id of the searchform
	this.searchbox = name; // id of the searchbox
	this.container = name+"Suggest"; // div that holds results
	this.resultTable = name+"Result"; // id base for the result table (+num = table row)
	this.resultText = name+"ResultText"; // id base for the spans within result tables (+num)
	this.toggle = name+"Toggle"; // div that has the toggle (enable/disable) link
	this.query = null; // last processed query
	this.results = null;  // parsed titles
	this.resultCount = 0; // number of results
	this.original = null; // query that user entered
	this.selected = -1; // which result is selected
	this.containerCount = 0; // number of results visible in container
	this.containerRow = 0; // height of result field in the container
	this.containerTotal = 0; // total height of the container will all results
	this.visible = false; // if container is visible
}

/** Hide results div */
function os_hideResults(r) {
	var c =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.container);
	if(c != null)
		c.style.visibility = "hidden";
	r.visible = false;
	r.selected = -1;
}

/** Show results div */
function os_showResults(r) {
	if(os_is_stopped)
		return;
	os_fitContainer(r);
	var c =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.container);
	r.selected = -1;
	if(c != null){
		c.scrollTop = 0;
		c.style.visibility = "visible";
		r.visible = true;
	}
}

function os_operaWidthFix(x) {
	// TODO: better css2 incompatibility detection here
	if(is_opera || is_khtml || navigator.userAgent.toLowerCase().indexOf('firefox/1')!=-1){
		return 30; // opera&konqueror & old firefox don't understand overflow-x, estimate scrollbar width
	}
	return 0;
}

function os_encodeQuery(value) {
  if (encodeURIComponent) {
    return encodeURIComponent( _proxy_jslib_handle(null, 'value', value, 0, 0));
  }
  if(escape) {
    return escape( _proxy_jslib_handle(null, 'value', value, 0, 0));
  }
  return null;
}
function os_decodeValue(value) {
  if (decodeURIComponent) {
    return decodeURIComponent( _proxy_jslib_handle(null, 'value', value, 0, 0));
  }
  if(unescape){
  	return unescape( _proxy_jslib_handle(null, 'value', value, 0, 0));
  }
  return null;
}

/** Brower-dependent functions to find window inner size, and scroll status */
function f_clientWidth() {
	return f_filterResults (
		window.innerWidth ? window.innerWidth : 0,
		document.documentElement ? document.documentElement.clientWidth : 0,
		 _proxy_jslib_handle(document, 'body', '', 0, 0) ?  _proxy_jslib_handle(document, 'body', '', 0, 0).clientWidth : 0
 );
}
function f_clientHeight() {
	return f_filterResults (
		window.innerHeight ? window.innerHeight : 0,
		document.documentElement ? document.documentElement.clientHeight : 0,
		 _proxy_jslib_handle(document, 'body', '', 0, 0) ?  _proxy_jslib_handle(document, 'body', '', 0, 0).clientHeight : 0
 );
}
function f_scrollLeft() {
	return f_filterResults (
		window.pageXOffset ? window.pageXOffset : 0,
		document.documentElement ? document.documentElement.scrollLeft : 0,
		 _proxy_jslib_handle(document, 'body', '', 0, 0) ?  _proxy_jslib_handle(document, 'body', '', 0, 0).scrollLeft : 0
 );
}
function f_scrollTop() {
	return f_filterResults (
		window.pageYOffset ? window.pageYOffset : 0,
		document.documentElement ? document.documentElement.scrollTop : 0,
		 _proxy_jslib_handle(document, 'body', '', 0, 0) ?  _proxy_jslib_handle(document, 'body', '', 0, 0).scrollTop : 0
 );
}
function f_filterResults(n_win, n_docel, n_body) {
	var n_result = n_win ? n_win : 0;
	if (n_docel && (!n_result || (n_result > n_docel)))
		n_result = n_docel;
	return n_body && (!n_result || (n_result > n_body)) ? n_body : n_result;
}

/** Get the height available for the results container */
function os_availableHeight(r) {
	var absTop =  _proxy_jslib_handle( _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.container).style, 'top', '', 0, 0);
	var px = absTop.lastIndexOf("px");
	if(px > 0)
		absTop = absTop.substring(0,px);
	return f_clientHeight() - (absTop - f_scrollTop());
}


/** Get element absolute position {left,top} */
function os_getElementPosition(elemID) {
	var offsetTrail =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(elemID);
	var offsetLeft = 0;
	var offsetTop = 0;
	while (offsetTrail){
		offsetLeft += offsetTrail.offsetLeft;
		offsetTop += offsetTrail.offsetTop;
		offsetTrail = offsetTrail.offsetParent;
	}
	if (navigator.userAgent.indexOf('Mac') != -1 && typeof  _proxy_jslib_handle(document, 'body', '', 0, 0).leftMargin != 'undefined'){
		offsetLeft +=  _proxy_jslib_handle(document, 'body', '', 0, 0).leftMargin;
		offsetTop +=  _proxy_jslib_handle(document, 'body', '', 0, 0).topMargin;
	}
	return {left:offsetLeft,top:offsetTop};
}

/** Create the container div that will hold the suggested titles */
function os_createContainer(r) {
	var c = document.createElement("div");
	var s =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.searchbox);
	var pos = os_getElementPosition(r.searchbox);
	var left = pos.left;
	var top =  _proxy_jslib_handle(pos, 'top', '', 0, 0) + s.offsetHeight;
	c.className = "os-suggest";
	 _proxy_jslib_handle(c, 'setAttribute', '', 1, 0)("id", r.container);
	 _proxy_jslib_handle(document, 'body', '', 0, 0).appendChild(c);

	// dynamically generated style params
	// IE workaround, cannot explicitely set "style" attribute
	c =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.container);
	 _proxy_jslib_assign('', c.style, 'top', '=', (  _proxy_jslib_handle(null, 'top', top, 0, 0)+"px"));
	c.style.left = left+"px";
	c.style.width = s.offsetWidth+"px";

	// mouse event handlers
	c.onmouseover = function(event) { os_eventMouseover(r.searchbox, event); };
	c.onmousemove = function(event) { os_eventMousemove(r.searchbox, event); };
	c.onmousedown = function(event) { return os_eventMousedown(r.searchbox, event); };
	c.onmouseup = function(event) { os_eventMouseup(r.searchbox, event); };
	return c;
}

/** change container height to fit to screen */
function os_fitContainer(r) {
	var c =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.container);
	var h = os_availableHeight(r) - 20;
	var inc = r.containerRow;
	h = parseInt(h/inc) * inc;
	if(h < (2 * inc) && r.resultCount > 1) // min: two results
		h = 2 * inc;
	if((h/inc) > os_max_lines_per_suggest )
		h = inc * os_max_lines_per_suggest;
	if(h < r.containerTotal){
		c.style.height = h +"px";
		r.containerCount = parseInt(Math.round(h/inc));
	} else{
		c.style.height = r.containerTotal+"px";
		r.containerCount = r.resultCount;
	}
}
/** If some entries are longer than the box, replace text with "..." */
function os_trimResultText(r) {
	// find max width, first see if we could expand the container to fit it
	var maxW = 0;
	for(var i=0;i<r.resultCount;i++){
		var e =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.resultText+i);
		if(e.offsetWidth > maxW)
			maxW = e.offsetWidth;
	}
	var w =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.container).offsetWidth;
	var fix = 0;
	if(r.containerCount < r.resultCount){
		fix = 20; // give 20px for scrollbar
	} else
		fix = os_operaWidthFix(w);
	if(fix < 4)
		fix = 4; // basic padding
	maxW += fix;

	// resize container to fit more data if permitted
	var normW =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.searchbox).offsetWidth;
	var prop = maxW / normW;
	if(prop > os_container_max_width)
		prop = os_container_max_width;
	else if(prop < 1)
		prop = 1;
	var newW = Math.round( normW * prop );
	if( w != newW ){
		w = newW;
		if( os_animation_timer != null )
			clearInterval(os_animation_timer.id)
 os_animation_timer = new (os_AnimationTimer)(r,w);
		os_animation_timer.id =  _proxy_jslib_handle(null, 'setInterval', setInterval, 1, 0)("os_animateChangeWidth()",os_animation_delay);
		w -= fix; // this much is reserved
	}

	// trim results
	if(w < 10)
		return;
	for(var i=0;i<r.resultCount;i++){
		var e =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.resultText+i);
		var replace = 1;
		var lastW = e.offsetWidth+1;
		var iteration = 0;
		var changedText = false;
		while(e.offsetWidth > w && (e.offsetWidth < lastW || iteration<2)){
			changedText = true;
			lastW = e.offsetWidth;
			var l =  _proxy_jslib_handle(e, 'innerHTML', '', 0, 0);
			 _proxy_jslib_assign('', e, 'innerHTML', '=', ( l.substring(0,l.length- _proxy_jslib_handle(null, 'replace', replace, 0, 0))+"..."));
			iteration++;
			 replace= _proxy_jslib_assign_rval('', 'replace', '=', ( 4), replace); // how many chars to replace
		}
		if(changedText){
			// show hint for trimmed titles
			 _proxy_jslib_handle( _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.resultTable+i), 'setAttribute', '', 1, 0)("title", _proxy_jslib_handle(r.results, (i), 0, 0));
		}
	}
}

/** Invoked on timer to animate change in container width */
function os_animateChangeWidth() {
	var r = os_animation_timer.r;
	var c =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.container);
	var w = c.offsetWidth;
	var normW =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.searchbox).offsetWidth;
	var normL = os_getElementPosition(r.searchbox).left;
	var inc = os_animation_timer.inc;
	var target = os_animation_timer.target;
	var nw = w + inc;
	if( (inc > 0 && nw >= target) || (inc <= 0 && nw <= target) ){
		// finished !
		c.style.width = target+"px";
		clearInterval(os_animation_timer.id)
 os_animation_timer = null;
	} else{
		// in-progress
		c.style.width = nw+"px";
		if(document.documentElement.dir == "rtl")
			c.style.left = (normL + normW + (target - nw) - os_animation_timer.target - 1)+"px";
	}
}

/** Handles data from XMLHttpRequest, and updates the suggest results */
function os_updateResults(r, query, text, cacheKey) {
	 _proxy_jslib_assign('', os_cache, (cacheKey), '=', ( text));
	r.query = query;
	r.original = query;
	if(text == ""){
		r.results = null;
		r.resultCount = 0;
		os_hideResults(r);
	} else{
		try {
			var p = eval(_proxy_jslib_proxify_js(('('+text+')'), 0, 0) ); // simple json parse, could do a safer one
			if(p.length<2 || p[1].length == 0){
				r.results = null;
				r.resultCount = 0;
				os_hideResults(r);
				return;
			}
			var c =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.container);
			if(c == null)
				c = os_createContainer(r);
			 _proxy_jslib_assign('', c, 'innerHTML', '=', ( os_createResultTable(r,p[1])));
			// init container table sizes
			var t =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.resultTable);
			r.containerTotal = t.offsetHeight;
			r.containerRow = t.offsetHeight / r.resultCount;
			os_fitContainer(r);
			os_trimResultText(r);
			os_showResults(r);
		} catch(e){
			// bad response from server or such
			os_hideResults(r);
			 _proxy_jslib_assign('', os_cache, (cacheKey), '=', ( null));
		}
	}
}

/** Create the result table to be placed in the container div */
function os_createResultTable(r, results) {
	var c =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.container);
	var width = c.offsetWidth - os_operaWidthFix(c.offsetWidth);
	var html = "<table class=\"os-suggest-results\" id=\""+r.resultTable+"\" style=\"width: "+width+"px;\">";
	r.results = new (Array)();
	r.resultCount = results.length;
	for(i=0;i<results.length;i++){
		var title = os_decodeValue( _proxy_jslib_handle(results, (i), 0, 0));
		 _proxy_jslib_assign('', r.results, (i), '=', ( title));
		html += "<tr><td class=\"os-suggest-result\" id=\""+r.resultTable+i+"\"><span id=\""+r.resultText+i+"\">"+title+"</span></td></tr>";
	}
	html+="</table>"
 return html;
}

/** Fetch namespaces from checkboxes or hidden fields in the search form,
    if none defined use wgSearchNamespaces global */
function os_getNamespaces(r) {
	var namespaces = "";
	var elements = document.forms[(r.searchform)].elements;
	for(i=0; i < elements.length; i++){
		var name =  _proxy_jslib_handle(elements, (i), 0, 0).name;
		if(typeof name != 'undefined' && name.length > 2
 && name[0]=='n' && name[1]=='s'
 && (( _proxy_jslib_handle(elements, (i), 0, 0).type=='checkbox' &&  _proxy_jslib_handle(elements, (i), 0, 0).checked)
 || ( _proxy_jslib_handle(elements, (i), 0, 0).type=='hidden' &&  _proxy_jslib_handle( _proxy_jslib_handle(elements, (i), 0, 0), 'value', '', 0, 0)=="1")) ){
			if(namespaces!="")
				namespaces+="|";
			namespaces+=name.substring(2);
		}
	}
	if(namespaces == "")
		namespaces = wgSearchNamespaces.join("|");
	return namespaces;
}

/** Update results if user hasn't already typed something else */
function os_updateIfRelevant(r, query, text, cacheKey) {
	var t =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.searchbox);
	if(t != null &&  _proxy_jslib_handle(t, 'value', '', 0, 0) == query){ // check if response is still relevant
		os_updateResults(r, query, text, cacheKey);
	}
	r.query = query;
}

/** Fetch results after some timeout */
function os_delayedFetch() {
	if(os_timer == null)
		return;
	var r = os_timer.r;
	var query = os_timer.query;
	os_timer = null;
	var path =  _proxy_jslib_handle( _proxy_jslib_handle( _proxy_jslib_handle(wgMWSuggestTemplate, 'replace', '', 1, 0)("{namespaces}",os_getNamespaces(r))
 , 'replace', '', 1, 0)("{dbname}",wgDBname)
 , 'replace', '', 1, 0)("{searchTerms}",os_encodeQuery(query));

	// try to get from cache, if not fetch using ajax
	var cached =  _proxy_jslib_handle(os_cache, (path), 0, 0);
	if(cached != null){
		os_updateIfRelevant(r, query, cached, path);
	} else{
		var xmlhttp = sajax_init_object();
		if(xmlhttp){
			try {
				 _proxy_jslib_handle(xmlhttp, 'open', '', 1, 0)("GET", path, true);
				xmlhttp.onreadystatechange=function() {
		        	if (xmlhttp.readyState==4 && typeof os_updateIfRelevant == 'function') {
		        		os_updateIfRelevant(r, query, xmlhttp.responseText, path);
	        		}
	      		};
	     		xmlhttp.send(null);
	     	} catch (e) {
				if ( _proxy_jslib_handle( _proxy_jslib_handle(window, 'location', '', 0, 0), 'hostname', '', 0, 0) == "localhost") {
					alert("Your browser blocks XMLHttpRequest to 'localhost', try using a real hostname for development/testing.");
				}
				throw e;
			}
		}
	}
}

/** Init timed update via os_delayedUpdate() */
function os_fetchResults(r, query, timeout) {
	if(query == ""){
		os_hideResults(r);
		return;
	} else if(query == r.query)
		return; // no change

	os_is_stopped = false; // make sure we're running

	/* var cacheKey = wgDBname+":"+query;
	var cached = os_cache[cacheKey];
	if(cached != null){
		os_updateResults(r,wgDBname,query,cached);
		return;
	} */

	// cancel any pending fetches
	if(os_timer != null && os_timer.id != null)
		clearTimeout(os_timer.id);
	// schedule delayed fetching of results
	if(timeout != 0){
		os_timer = new (os_Timer)( _proxy_jslib_handle(null, 'setTimeout', setTimeout, 1, 0)("os_delayedFetch()",timeout),r,query);
	} else{
		os_timer = new (os_Timer)(null,r,query);
		os_delayedFetch(); // do it now!
	}

}
/** Change the highlighted row (i.e. suggestion), from position cur to next */
function os_changeHighlight(r, cur, next, updateSearchBox) {
	if (next >= r.resultCount)
		next = r.resultCount-1;
	if (next < -1)
		next = -1;
	r.selected = next;
   	if (cur == next)
    	return; // nothing to do.

    if(cur >= 0){
    	var curRow =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.resultTable + cur);
    	if(curRow != null)
    		curRow.className = "os-suggest-result";
    }
    var newText;
    if(next >= 0){
    	var nextRow =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.resultTable + next);
    	if(nextRow != null)
    		nextRow.className = os_HighlightClass();
    	newText =  _proxy_jslib_handle(r.results, (next), 0, 0);
    } else
    	newText = r.original;

    // adjust the scrollbar if any
    if(r.containerCount < r.resultCount){
    	var c =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.container);
    	var vStart = c.scrollTop / r.containerRow;
    	var vEnd = vStart + r.containerCount;
    	if(next < vStart)
    		c.scrollTop = next * r.containerRow;
    	else if(next >= vEnd)
    		c.scrollTop = (next - r.containerCount + 1) * r.containerRow;
    }

    // update the contents of the search box
    if(updateSearchBox){
    	os_updateSearchQuery(r,newText);
    }
}

function os_HighlightClass() {
	var match = navigator.userAgent.match(/AppleWebKit\/(\d+)/);
	if (match) {
		var webKitVersion = parseInt(match[1]);
		if (webKitVersion < 523) {
			// CSS system highlight colors broken on old Safari
			// https://bugs.webkit.org/show_bug.cgi?id=6129
			// Safari 3.0.4, 3.1 known ok
			return "os-suggest-result-hl-webkit";
		}
	}
	return "os-suggest-result-hl";
}

function os_updateSearchQuery(r,newText) {
	 _proxy_jslib_assign('',  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.searchbox), 'value', '=', ( newText));
    r.query = newText;
}

/** Find event target */
function os_getTarget(e) {
	if (!e) e = window.event;
	if (e.target) return e.target;
	else if (e.srcElement) return e.srcElement;
	else return null;
}



/********************
 *  Keyboard events
 ********************/

/** Event handler that will fetch results on keyup */
function os_eventKeyup(e) {
	var targ = os_getTarget(e);
	var r =  _proxy_jslib_handle(os_map, (targ.id), 0, 0);
	if(r == null)
		return; // not our event

	// some browsers won't generate keypressed for arrow keys, catch it
	if(os_keypressed_count == 0){
		os_processKey(r,os_cur_keypressed,targ);
	}
	var query =  _proxy_jslib_handle(targ, 'value', '', 0, 0);
	os_fetchResults(r,query,os_search_timeout);
}

/** catch arrows up/down and escape to hide the suggestions */
function os_processKey(r,keypressed,targ) {
	if (keypressed == 40){ // Arrow Down
    	if (r.visible) {
      		os_changeHighlight(r, r.selected, r.selected+1, true);
    	} else if(os_timer == null){
    		// user wants to get suggestions now
    		r.query = "";
			os_fetchResults(r, _proxy_jslib_handle(targ, 'value', '', 0, 0),0);
    	}
  	} else if (keypressed == 38){ // Arrow Up
  		if (r.visible){
  			os_changeHighlight(r, r.selected, r.selected-1, true);
  		}
  	} else if(keypressed == 27){ // Escape
  		 _proxy_jslib_assign('',  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.searchbox), 'value', '=', ( r.original));
  		r.query = r.original;
  		os_hideResults(r);
  	} else if(r.query !=  _proxy_jslib_handle( _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.searchbox), 'value', '', 0, 0)){
  		// os_hideResults(r); // don't show old suggestions
  	}
}

/** When keys is held down use a timer to output regular events */
function os_eventKeypress(e) {
	var targ = os_getTarget(e);
	var r =  _proxy_jslib_handle(os_map, (targ.id), 0, 0);
	if(r == null)
		return; // not our event

	var keypressed = os_cur_keypressed;
	if(keypressed == 38 || keypressed == 40){
		var d = new (Date)()
		var now = d.getTime();
		if(now - os_last_keypress < 120){
			os_last_keypress = now;
			return;
		}
	}

	os_keypressed_count++;
	os_processKey(r,keypressed,targ);
}

/** Catch the key code (Firefox bug)  */
function os_eventKeydown(e) {
	if (!e) e = window.event;
	var targ = os_getTarget(e);
	var r =  _proxy_jslib_handle(os_map, (targ.id), 0, 0);
	if(r == null)
		return; // not our event

	os_mouse_moved = false;

	os_cur_keypressed = (e.keyCode == undefined) ? e.which : e.keyCode;
	os_last_keypress = 0;
	os_keypressed_count = 0;
}

/** Event: loss of focus of input box */
function os_eventBlur(e) {
	var targ = os_getTarget(e);
	var r =  _proxy_jslib_handle(os_map, (targ.id), 0, 0);
	if(r == null)
		return; // not our event
	if(!os_mouse_pressed)
		os_hideResults(r);
}

/** Event: focus (catch only when stopped) */
function os_eventFocus(e) {
	// nothing happens here?
}



/********************
 *  Mouse events
 ********************/

/** Mouse over the container */
function os_eventMouseover(srcId, e) {
	var targ = os_getTarget(e);
	var r =  _proxy_jslib_handle(os_map, (srcId), 0, 0);
	if(r == null || !os_mouse_moved)
		return; // not our event
	var num = os_getNumberSuffix(targ.id);
	if(num >= 0)
		os_changeHighlight(r,r.selected,num,false);

}

/* Get row where the event occured (from its id) */
function os_getNumberSuffix(id) {
	var num = id.substring(id.length-2);
	if( ! (num.charAt(0) >= '0' && num.charAt(0) <= '9') )
		num = num.substring(1);
	if(os_isNumber(num))
		return parseInt(num);
	else
		return -1;
}

/** Save mouse move as last action */
function os_eventMousemove(srcId, e) {
	os_mouse_moved = true;
}

/** Mouse button held down, register possible click  */
function os_eventMousedown(srcId, e) {
	var targ = os_getTarget(e);
	var r =  _proxy_jslib_handle(os_map, (srcId), 0, 0);
	if(r == null)
		return; // not our event
	var num = os_getNumberSuffix(targ.id);

	os_mouse_pressed = true;
	if(num >= 0){
		os_mouse_num = num;
		// os_updateSearchQuery(r,r.results[num]);
	}
	// keep the focus on the search field
	 _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.searchbox).focus();

	return false; // prevents selection
}

/** Mouse button released, check for click on some row */
function os_eventMouseup(srcId, e) {
	var targ = os_getTarget(e);
	var r =  _proxy_jslib_handle(os_map, (srcId), 0, 0);
	if(r == null)
		return; // not our event
	var num = os_getNumberSuffix(targ.id);

	if(num >= 0 && os_mouse_num == num){
		os_updateSearchQuery(r, _proxy_jslib_handle(r.results, (num), 0, 0));
		os_hideResults(r);
		 _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.searchform).submit();
	}
	os_mouse_pressed = false;
	// keep the focus on the search field
	 _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.searchbox).focus();
}

/** Check if x is a valid integer */
function os_isNumber(x) {
	if(x == "" || isNaN(x))
		return false;
	for(var i=0;i<x.length;i++){
		var c = x.charAt(i);
		if( ! (c >= '0' && c <= '9') )
			return false;
	}
	return true;
}


/** When the form is submitted hide everything, cancel updates... */
function os_eventOnsubmit(e) {
	var targ = os_getTarget(e);

	os_is_stopped = true;
	// kill timed requests
	if(os_timer != null && os_timer.id != null){
		clearTimeout(os_timer.id);
		os_timer = null;
	}
	// Hide all suggestions
	for(i=0;i<os_autoload_inputs.length;i++){
		var r =  _proxy_jslib_handle(os_map, ( _proxy_jslib_handle(os_autoload_inputs, (i), 0, 0)), 0, 0);
		if(r != null){
			var b =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.searchform);
			if(b != null && b == targ){
				// set query value so the handler won't try to fetch additional results
				r.query =  _proxy_jslib_handle( _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.searchbox), 'value', '', 0, 0);
			}
			os_hideResults(r);
		}
	}
	return true;
}

function os_hookEvent(element, hookName, hookFunct) {
	if (element.addEventListener) {
		element.addEventListener(hookName, hookFunct, false);
	} else if (window.attachEvent) {
		element.attachEvent("on" + hookName, hookFunct);
	}
}

/** Init Result objects and event handlers */
function os_initHandlers(name, formname, element) {
	var r = new (os_Results)(name, formname);
	// event handler
	os_hookEvent(element, "keyup", function(event) { os_eventKeyup(event); });
	os_hookEvent(element, "keydown", function(event) { os_eventKeydown(event); });
	os_hookEvent(element, "keypress", function(event) { os_eventKeypress(event); });
	os_hookEvent(element, "blur", function(event) { os_eventBlur(event); });
	os_hookEvent(element, "focus", function(event) { os_eventFocus(event); });
	 _proxy_jslib_handle(element, 'setAttribute', '', 1, 0)("autocomplete","off");
	// stopping handler
	os_hookEvent( _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(formname), "submit", function(event) { return os_eventOnsubmit(event); });
	 _proxy_jslib_assign('', os_map, (name), '=', ( r));
	// toggle link
	if( _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.toggle) == null){
		// TODO: disable this while we figure out a way for this to work in all browsers
		/* if(name=='searchInput'){
			// special case: place above the main search box
			var t = os_createToggle(r,"os-suggest-toggle");
			var searchBody = document.getElementById('searchBody');
			var first = searchBody.parentNode.firstChild.nextSibling.appendChild(t);
		} else{
			// default: place below search box to the right
			var t = os_createToggle(r,"os-suggest-toggle-def");
			var top = element.offsetTop + element.offsetHeight;
			var left = element.offsetLeft + element.offsetWidth;
			t.style.position = "absolute";
			t.style.top = top + "px";
			t.style.left = left + "px";
			element.parentNode.appendChild(t);
			// only now width gets calculated, shift right
			left -= t.offsetWidth;
			t.style.left = left + "px";
			t.style.visibility = "visible";
		} */
	}

}

/** Return the span element that contains the toggle link */
function os_createToggle(r,className) {
	var t = document.createElement("span");
	t.className = className;
	 _proxy_jslib_handle(t, 'setAttribute', '', 1, 0)("id", r.toggle);
	var link = document.createElement("a");
	 _proxy_jslib_handle(link, 'setAttribute', '', 1, 0)("href","javascript:void(0);");
	link.onclick = function() { os_toggle(r.searchbox,r.searchform) };
	var msg = document.createTextNode(wgMWSuggestMessages[0]);
	link.appendChild(msg);
	t.appendChild(link);
	return t;
}

/** Call when user clicks on some of the toggle links */
function os_toggle(inputId,formName) {
	r =  _proxy_jslib_handle(os_map, (inputId), 0, 0);
	var msg = '';
	if(r == null){
		os_enableSuggestionsOn(inputId,formName);
		r =  _proxy_jslib_handle(os_map, (inputId), 0, 0);
		msg = wgMWSuggestMessages[0];
	} else{
		os_disableSuggestionsOn(inputId,formName);
		msg = wgMWSuggestMessages[1];
	}
	// change message
	var link =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(r.toggle).firstChild;
	link.replaceChild(document.createTextNode(msg),link.firstChild);
}

/** Call this to enable suggestions on input (id=inputId), on a form (name=formName) */
function os_enableSuggestionsOn(inputId, formName) {
	os_initHandlers( inputId, formName,  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(inputId) );
}

/** Call this to disable suggestios on input box (id=inputId) */
function os_disableSuggestionsOn(inputId) {
	r =  _proxy_jslib_handle(os_map, (inputId), 0, 0);
	if(r != null){
		// cancel/hide results
		os_timer = null;
		os_hideResults(r);
		// turn autocomplete on !
		 _proxy_jslib_handle( _proxy_jslib_handle(document, 'getElementById', '', 1, 0)(inputId), 'setAttribute', '', 1, 0)("autocomplete","on");
		// remove descriptor
		 _proxy_jslib_assign('', os_map, (inputId), '=', ( null));
	}
}

/** Initialization, call upon page onload */
function os_MWSuggestInit() {
	for(i=0;i<os_autoload_inputs.length;i++){
		var id =  _proxy_jslib_handle(os_autoload_inputs, (i), 0, 0);
		var form =  _proxy_jslib_handle(os_autoload_forms, (i), 0, 0);
		element =  _proxy_jslib_handle(document, 'getElementById', '', 1, 0)( id );
		if(element != null)
			os_initHandlers(id,form,element);
	}
}

hookEvent("load", os_MWSuggestInit);
 ;
_proxy_jslib_flush_write_buffers() ;