
/**
 * author: Antonio Ramirez http://webeaters.blogspot.com
 *
 * class: AutoComplete for Prototype 
 *
 * version: 1.2.0 - 2007-11-11 
 * 		(based on AutoSuggest 2.1.3 - 2007-07-19)
 *
 *
 * REFERENCES AND THANKS 
 * this class is based on the work in AutoSuggest.js of
 * Timothy Groves - http://www.brandspankingnew.net
 * and adapted for use with prototype 1.5.1
 *
 */

var AutoComplete = Class.create();

AutoComplete.prototype = {
	Version: '1.0.0_beta',
	REQUIRED_PROTOTYPE: '1.5.1', // minimum

	initialize: function (id, param)
	{
		// check whether we have the appropiate javascript libraries
		this.PROTOTYPE_CHECK();

		// get field
		this.fld = $(id);
		if (!this.fld)
		{
			throw("AutoComplete requires a field id to initialize");
		}

		// init variables
		this.sInp 	= ""; 	// input value 
		this.nInpC 	= 0;	// input value length
		this.aSug 	= []; 	// suggestions array 
		this.iHigh 	= 0;	// level of list selection 

		// parameters object
		this.options = param ? param : {};

		// defaults	
		var k, def = {minchars:1, meth:"get", varname:"input", className:"autocomplete", timeout:2500, delay:300, offsety:-5, shownoresults: false, noresults: "-", maxheight: 250, cache: false, maxentries: 25, onAjaxError:null, setWidth: false, minWidth: 100, maxWidth: 200, useNotifier: false, language: 'cz'};
		for (k in def)
		{
			if (typeof(this.options[k]) != typeof(def[k]))
			this.options[k] = def[k];
		}

		if (this.options.useNotifier) this.fld.addClassName('ac_field');
		// set keyup handler for field
		// and prevent AutoComplete from client

		var p = this;
		// NOTE: not using addEventListener because UpArrow fired twice in Safari
		this.fld.onkeypress 	= function(ev){ return p.onKeyPress(ev); };
		this.fld.onkeyup 		= function(ev){ return p.onKeyUp(ev); };
		// this.fld.onblur			= function(ev){ p.resetTimeout(); return true; }; // to implement? i did not think so but... up to you

		this.fld.setAttribute("autocomplete","off");

		},
		convertVersionString: function (versionString){
				var r = versionString.split('.');
				return parseInt(r[0])*100000 + parseInt(r[1])*1000 + parseInt(r[2]);
		},
		PROTOTYPE_CHECK: function() { 
			if((typeof Prototype=='undefined') || 
				 (typeof Element == 'undefined') || 
				 (typeof Element.Methods=='undefined') ||
				 (this.convertVersionString(Prototype.Version) < 
					this.convertVersionString(this.REQUIRED_PROTOTYPE)))
				 throw("AutoComplete requires the Prototype JavaScript framework >= " +
					this.REQUIRED_PROTOTYPE);
		},
		onKeyPress: function (e)
		{
			if (!e) e = window.event;

			var key	= e.keyCode || e.wich;


		// set responses to keypress events in the field
		// this allows the user to use the arrow keys to scroll through the results
		// ESCAPE clears the list
		// RETURN sets the current highlighted value
		// TAB moves to next item in the list

		switch(key)
		{
			case Event.KEY_RETURN:
				this.setHighlightedValue();
				//Event.stop(e);
				break;
			case Event.KEY_TAB: // if we wish to use this, we need to use it here, keyup fails
				this.changeHighlight(key);
				Event.stop(e);
				break;
			case Event.KEY_ESC:
				this.clearSuggestions();
				break;
		}
		return true;
		},
		onKeyUp: function (e)
		{
			if (!e) e = window.event;
			var key = e.keyCode || e.wich;
			if (key == Event.KEY_UP || key == Event.KEY_DOWN) 
			{
				this.changeHighlight(key);
				Event.stop(e);
			}
			else this.getSuggestions(this.fld.value);
		return true;
		},
	getSuggestions: function(val)
	{
		// input the same? do nothing
		if(val==this.sInp) return false;

		// kill the old list
		if($(this.acID)) $(this.acID).remove();

		this.sInp = val;

		// input length is less than the min required to trigger a request
		// do nothing
		if (val.length < this.options.minchars)
		{
			this.aSug 	= [];
			this.nInpC	= val.length; 
			return false;
		}

		// here we will detect if there is a comma and the splitted value has a value to check
		// comma stars a new search and val is converted to the new value after the comma
		var ol	= this.nInpC; // old length

		this.nInpC	= val.length ? val.length : 0;

		// if caching enabled, and user is typing (ie. length of input is increasing)
		// filter results out of suggestions from last request
		var l = this.aSug.length;

		if (this.nInpC > ol && l && l < this.options.maxentries && this.options.cache)
		{
			var arr = [];
			for (var i=0;i<l;i++)
			{
				if(this.aSug[i].value.substr(0,val.length).toLowerCase() == val.toLowerCase())
					arr.push(this.aSug[i]);
			}
			this.aSug = arr;

			// recreate the list
			this.createList(this.aSug);
		}
		else
		{
			// do new request
			var p = this;
			//var input	= this.sInp; // send the converted new value (comma)
			clearTimeout(this.ajID); // ajax id timer
			this.ajID = setTimeout( function () {p.doAjaxRequest(p.sInp)}, this.options.delay);
		}

		return false;
	},
	doAjaxRequest: function (input)
	{
		// we have to check here if there is a new splitted value (, or ;)
		// always check against the last part of the comma and then check
		// saved input is still the value of the field
		if (input != this.fld.value) 
			return false;

		// create ajax request
		// do we need to call a function to recreate the url?
		if (typeof this.options.script == 'function')
			var url = this.options.script(encodeURIComponent(this.sInp));
		else
			var url = this.options.script+this.options.varname+'='+encodeURIComponent(this.sInp);

		if(!url) return false;

		var p = this;
		var m = this.options.meth;	// get or post?
		if (this.options.useNotifier){this.fld.setStyle({backgroundImage:'url(images/AutoComplete/AutoComplete_spinner.gif)'});} 

		var options = {
			method: m,
			onSuccess: function (req) 
			{
					if (p.options.useNotifier){p.fld.setStyle({backgroundImage:'url(images/AutoComplete/AutoComplete_leftcap.gif)'});} 
					p.setSuggestions(req,input);
			},
			onFailure: (typeof p.options.onAjaxError == 'function')? function (status) {if (p.options.useNotifier){p.fld.setStyle({backgroundImage:'url(images/AutoComplete/AutoComplete_leftcap.gif)'});} p.options.onAjaxError(status)} : function (status) {if (p.options.useNotifier){p.fld.setStyle({backgroundImage:'url(images/AutoComplete/AutoComplete_leftcap.gif)'});} alert("AJAX error: "+status); }
		}
		// make new ajax request
		new Ajax.Request(url, options);
	},
	setSuggestions: function (req, input)
	{
		// if field input no longer matches what was passed to the request
		// don't show the suggestions
		// here we need to check against the splitted values if any (, or ;)
	if (input != this.fld.value)
		return false;
	this.aSug = [];
	if(this.options.json) // response in json format?
	{
		var jsondata = eval('(' + req.responseText + ')');

		for (var i=0; i<jsondata.results.length;i++)
		{
			this.aSug.push({'query':jsondata.results[i].query, 'hits':jsondata.results[i].hits, 'encodedQuery':jsondata.results[i].encodedQuery});
		}
	}
	else	// response in xml format?
	{
		var results = req.responseXML.getElementsByTagName('results')[0].childNodes;
		for(var i=0;i<results.length;i++)
		{
			if(results[i].hasChildNodes())
				this.aSug.push(	{ 'id':results[i].getAttribute('query'), 'hits':results[i].childNodes[0].nodeValue, 'encoded_query':results[i].getAttribute('encodedQuery') }	);
		}
	}
	this.acID = 'ac_'+this.fld.id;

	this.createList(this.aSug);
	},
	createDOMElement: function ( type, attr, cont, html )
	{
	var ne = document.createElement( type );

	if (!ne)
		return 0;

	for (var a in attr)
		ne[a] = attr[a];

	var t = typeof(cont);

	if (t == "string" && !html)
		ne.appendChild( document.createTextNode(cont) );
	else if (t == "string" && html)
		ne.innerHTML = cont;
	else if (t == "object")
		ne.appendChild( cont );

	return ne;
	},
	createList: function(arr)
	{
	// get rid of the old list if any	
		if($(this.acID)) $(this.acID).remove();

		// clear list removal timeout
		this.killTimeout();

		// if no results, and shownoresults is false, do nothing
		if (arr.length == 0 && !this.options.shownoresults) return false;

		// create holding div
		var div	= this.createDOMElement('div', {id:this.acID, className:this.options.className});

		// create div header

	// create and populate ul
	var ul	= this.createDOMElement('ul', {id:'ac_ul'});
	var p 	= this; // pointer that we will need later on
	// no results?
	if (arr.length == 0 && this.options.shownoresults)
	{
		var li = this.createDOMElement('li', {className: 'ac_warning'}, this.options.noresults );
		ul.appendChild(li);
	}
	else
	{
		// loop through arr of suggestions creating an LI element for each of them
		for (var i=0,l = arr.length; i<l; i++)
		{
			// format output with the input enclosed in a EM elementFromPoint
			// (as HTML not DOM)
			var site_spec = 'O2_' + this.options['site_spec'] + '_' +  this.options['language'];
			var val = arr[i].query;
			var st = val.toLowerCase().indexOf(this.sInp.toLowerCase()); // HERE WE CHECK AGAINST THE SPLITTED VALUE IF ANY***
			var output = '<span>' + val.substring(0,st) + '<em>' + val.substring(st,st+this.sInp.length) + '</em>' + val.substring(st+this.sInp.length) + '</span> <small>' + arr[i].hits + '</small><br class="reset" />';

			var targetURL = '/osobni/en/search/index$122686.html';
			targetURL += '?q=' + arr[i].encodedQuery;
			targetURL += '&filter=p';
			targetURL += '&output=xml_no_dtd';
			targetURL += '&client=' + site_spec;
			targetURL += '&proxystylesheet=' + site_spec;
			targetURL += '&site=' + site_spec;
			targetURL += '&getfields=description';

			var a = this.createDOMElement('a',{href:targetURL});
			a.innerHTML = output;

			a.name = i+1;

			a.onclick = function () { p.setHighlightedValue(); };
			a.onmouseover = function () { p.setHighlight(this.name); }; 

			var li = this.createDOMElement('li',{}, a); // add the link element to a li element

			// finally add the newly created li element to the ul element 
			ul.appendChild(li);
		}
	}

	div.appendChild(ul); // add the newly created list to the div element

	// add DIV to document
	$('searchFooter').insertBefore(div, $('searchFooterLinks'));

	// highlight first item
	//this.iHigh = 1;
	//this.setHighlight(1);

	// remove list after interval
	//this.toID = setTimeout(function () {p.clearSuggestions() },this.options.timeout);

	},
	changeHighlight: function(key)
	{
		var list = $("ac_ul");
	if (!list)
		return false;

	var n;

	n = (key == Event.KEY_DOWN || key == Event.KEY_TAB)? this.iHigh + 1 : this.iHigh - 1; // false assumed to be Event.KEY_UP

	n = (n > list.childNodes.length)? list.childNodes.length : ((n < 1)? 1 : n);	

	this.setHighlight(n);
	},
	setHighlight: 	function(n)
	{
		var list = $('ac_ul');

		if (!list) return false;

		if (this.iHigh > 0) this.clearHighlight();

		this.iHigh = Number(n);

		list.childNodes[this.iHigh-1].className = 'ac_highlight';

		this.killTimeout();
	},
	clearHighlight: function()
	{
		var list = $('ac_ul');

		if(!list) return false;

		if(this.iHigh > 0)
		{
			list.childNodes[this.iHigh-1].className = '';
			this.iHigh = 0;
		}

	},
	setHighlightedValue: function()
	{
		if (this.iHigh)
		{
			// HERE WE NEED TO IMPLEMENT THE GMAIL LIKE SPLITTED VALUE
			if (!this.aSug[this.iHigh - 1]) return;
			this.sInp = this.fld.value = this.aSug[ this.iHigh -1 ].query;

			// move cursor to end of input (safari)
			this.fld.focus();
			if(this.fld.selectionStart)
				this.fld.setSelectionRange(this.sInp.length, this.sInp.length);

			this.clearSuggestions();

			// pass selected object to callback function, if exists
			if (typeof this.options.callback == 'function')
				this.options.callback(this.aSug[this.iHigh-1]); // the object has the properties we want, it will depend of
		}
	},
	killTimeout: function()
	{
		clearTimeout(this.toID);
	},
	resetTimeout: function()
	{
		this.killTimeout();
		var p = this;
		this.toID = setTimeout(function () { p.clearSuggestions();});
	},
	clearSuggestions: function ()
	{

	this.killTimeout();

	//if ($(this.acID)){this.fadeOut(300,function () {$(this.acID).remove();});}
	if ($(this.acID)){ $(this.acID).remove();}
	},
	fadeOut: function (milliseconds, callback)
	{
		this._fadeFrom 	= 1;
		this._fadeTo	= 0;
		this._afterUpdateInternal = callback;

		this._fadeDuration	= milliseconds;
		this._fadeInterval = 50;
		this._fadeTime = 0;
		var p = this;
		this._fadeIntervalID = setInterval(function() {p._changeOpacity()},this._fadeInterval);

	},
	_changeOpacity: function() {

	if (!$(this.acID)){
			this._fadeIntervalID=clearInterval(this._fadeIntervalID);
			return;
		} 
		this._fadeTime += this._fadeInterval;

		var ieop = Math.round( (this._fadeFrom + ((this._fadeTo - this._fadeFrom) * (this._fadeTime/this._fadeDuration))) * 100)
		var op = ieop / 100;


		var el = $(this.acID);
		if (el.filters) // internet explorer
	{
		try
		{
			el.filters.item("DXImageTransform.Microsoft.Alpha").opacity = ieop;
		} catch (e) { 
			// If it is not set initially, the browser will throw an error.	This will set it if it is not set yet.
			el.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity='+ieop+')';
		}
	}
	else // other browsers
	{
		el.style.opacity = op;
	}

	if (this._fadeTime >= this._fadeDuration)
	{
		clearInterval( this._fadeIntervalID );
		if (typeof this._afterUpdateInternal == 'function')
			this._afterUpdateInternal();
	}

	}

}

/* by Bumbo z duvodu zamceneho js_function */
function enableTextarea() {
	if (typeof elm == "undefined") {
		var elm = $("categorySelect");
	}
	if (typeof textareaElm == "undefined") {
		var textareaElm = $("tAR");
	}
	if (elm.selectedIndex > 0) {
		textareaElm.enable();
		textareaElm.clear();
		textareaElm.focus();
	} else {
		textareaElm.disable();
	}
}


