var AutoSuggest = new Class({
	Implements: [Options],
	options: {
		callback : $empty,
		minchars:1,
		meth:"post",
		varname:"input",
		className:"autosuggest",
		timeout:2500,
		delay:500,
		offsety:0,
		shownoresults: true,
		noresults: "No results!",
		maxheight: 250,
		cache: true,
		maxentries: 25,
		autodropdown: false,
		pressEnter:"",
		preLoader:""
	},
	
	initialize: function(element, options){
		this.setOptions(options);
		this.sInp 	= "";
		this.nInpC 	= 0;
		this.cashedValues 	= []; // talalatok
		this.filteredValues = [];
		this.iHigh 	= 0;
		this.fld	= $(element);
		this.preLoader = $(this.options.preLoader);
		
		this.fld.set({
			'events':{
				'keypress': function(ev){ return this.onKeyPress(ev); }.bind(this),
				'keyup' 	: function(ev){ return this.onKeyUp(ev); }.bind(this),
				'click'   : function(ev){ this.getSuggestions(this.fld.get('value')); }.bind(this)
				//'blur'		: function(ev){ return this.clearSuggestions(); }.bind(this) // utolag lett beszurva, ha az input boxrol elkattintunk, akkor csukja be egybol a listat
			},
			'autocomplete': 'off'
		});
	},
	
	onKeyPress : function(event){
		var key = event.key;
		var bubble = 1;
		
		switch(key){
			case 'enter':
				this.setHighlightedValue();
				bubble = 0;
			break;
			case 'esc':
				this.clearSuggestions();
			break;
		}
		return bubble;	
	},
	onKeyUp : function(event){
		var key = event.key;
		var bubble = 1;
	
		switch(key){
			case 'up':
				this.changeHighlight(key);
				bubble = 0;
			break;
			case 'down':
				this.changeHighlight(key);
				bubble = 0;
			break;
			case 'enter': break;
			case 'esc': break;
			default:
				this.getSuggestions(this.fld.get('value'));
		}
		return bubble;
	},

	clearSuggestions : function(){
		$clear(this.toID);
		if($(this.idAs)){
			$(this.idAs).tween('opacity', [1, 0]);
			$(this.idAs).dispose();
		};
	},
	
	getSuggestions : function(value){
		// ellenorzi hogy beirta e mar a minimum karaktert
		if (value.length < this.options.minchars){
			this.filteredValues  = [];
			this.nInpC = value.length;
			return 0;
		}
		
		var oldLength = this.nInpC; // old length
		this.nInpC = value.length ? value.length : 0;
	
		// az eltarolt szavak kozul kikeresi a mar berit szavakat
		this.filteredValues = this.cashedValues.filter(function(item, index){
			return (item.input == value);
		});
		
		var l = this.filteredValues.length;
		this.sInp = value;
		// megnezi, hogy a szo szerepel e a hashben
		if (l && l<this.options.maxentries && this.options.cache){
			var arr = [];
			for (var i=0;i<l;i++){
				if (this.filteredValues[i].value.substr(0,value.length).toLowerCase() == value.toLowerCase()){
					arr.push( this.filteredValues[i] );
				}
			}
			this.createList(arr);
			return false;
		// ha nem szerepel kerdezze le
		}else{
		// do new request
			// elozo lekerdezes viszavonasa
			$clear(this.ajID);
			// uj lekerdezes elinditasa
			this.ajID = ( function() { this.makeRequest(value); }.bind(this)).delay( this.options.delay );
		}
		return false;
	},
	
	makeRequest : function (value){
		
		new Request({'method':this.options.meth,
					 'url':this.options.url,
					 'onRequest' :function(){ this.preLoader.setStyle('visibility','visible'); }.bind(this),
					 'onComplete':function(){ this.preLoader.setStyle('visibility','hidden'); }.bind(this),
					 'onSuccess' :function(responseText, responseXML){
							this.setSuggestions({'responseText':responseText, 'responseXML':responseXML}, value);
					 }.bind(this),
					 'onError'   : function(){ alert('Hiba történet a szavak keresése közben!'); }
				}).send('input='+value);
	},
	
	setSuggestions : function (req, input){
		// if field input no longer matches what was passed to the request
		// don't show the suggestions
		if (input != this.fld.value){
			return false;
		}
		
		this.filteredValues = [];
		
		if (this.options.json){
			var jsondata = eval('(' + req.responseText + ')');
			
			for (var i=0;i<jsondata.results.length;i++){
				this.cashedValues.push({ 'input': input, 'id':jsondata.results[i].id, 'value':jsondata.results[i].value, 'info':jsondata.results[i].info   });
				this.filteredValues.push({ 'input': input, 'id':jsondata.results[i].id, 'value':jsondata.results[i].value, 'info':jsondata.results[i].info   });
				
			}
		}else{
			var xml = req.responseXML;
			// traverse xml
			var results = xml.getElementsByTagName('results')[0].childNodes;
			
			for (var i=0;i<results.length;i++){
				if (results[i].hasChildNodes()){
					this.cashedValues.push({ 'input': input, 'id':results[i].getAttribute('id'), 'value':results[i].childNodes[0].nodeValue, 'info':results[i].getAttribute('info') });
					this.filteredValues.push({ 'input': input, 'id':results[i].getAttribute('id'), 'value':results[i].childNodes[0].nodeValue, 'info':results[i].getAttribute('info') });
				}
			}
		}

		this.idAs = "as_"+this.fld.id;
		this.createList(this.filteredValues);
	
	},
	createList : function(arr){
		// get rid of old list
		// and clear the list removal timeout
		if($(this.idAs)) {$(this.idAs).dispose();}
		$clear(this.toID);
		
		// if no results, and shownoresults is false, do nothing
		if (arr.length === 0 && !this.options.shownoresults){
			return false;
		}
		
		// create holding div
		var div = new Element("div", {'id':this.idAs, 'class':this.options.className}).adopt(
			new Element("div", {'class' :"as_header"}).adopt(
				new Element("div", {'class':"as_corner"}),
				new Element("div", {'class':"as_bar"})
			)
		);
		
		// create and populate ul
		var ul = new Element("ul", {id:"as_ul"});
		
		// loop throught arr of suggestions
		// creating an LI element for each suggestion
		
		for (var i=0;i<arr.length;i++){
			// format output with the input enclosed in a EM element
			// (as HTML, not DOM)
			var val = arr[i].value;
			var st = val.toLowerCase().indexOf( this.sInp.toLowerCase() );
			var output = val.substring(0,st) + "<em>" + val.substring(st, st+this.sInp.length) + "</em>" + val.substring(st+this.sInp.length);
			
			var span = new Element("span", {'html':output});
			if (arr[i].info !== ""){
				span.adopt(
					new Element("br", {}),
					new Element("small", {'html': arr[i].info})
				);
			}
			
			var pointer = this;
			var a 	= new Element("a", { 'href':"#" , 'name': i+1,
								 'events':{
									'click': function (event) { event.stop();this.setHighlightedValue(); }.bind(this),
									'mouseover' : function () { pointer.setHighlight(this.name); }
								}
						}).adopt(											
							new Element("span", {'class':"tl", 'html': ' '}),
							span,
							new Element("span", {'class':"tr", 'html': ' '})
						);

			var li = new Element(  "li", {});
			a.inject(li);
			
			ul.adopt( li );
		}

		// no results
		if (arr.length === 0 && this.options.shownoresults){
			li = new Element(  "li", {'class':"as_warning", 'html':this.options.noresults  });
			ul.adopt( li );
		}
		
		
		div.adopt( ul );
	
		div.adopt(
			new Element("div", {'class':"as_corner"}).adopt(
				new Element("div", {'class':"as_bar"}),
				new Element("div", {'class':"as_footer"})
			)
		);
		
		// get position of target textfield
		// position holding div below it
		// set width of holding div to width of field
		var pos = this.fld.getPosition();
		
		div.set({
			'styles': { 
				'left': pos.x + "px",
				'top': ( pos.y + this.fld.offsetHeight + this.options.offsety ) + "px",
				'width': this.fld.offsetWidth + "px"
			},
			'events': {
				'mouseover': function(){ $clear(this.toID); }.bind(this),
				'mouseout': function(){ this.resetTimeout(); }.bind(this)
			}
		});

		$$("body")[0].adopt(div);
		
		// currently no item is highlighted
		this.iHigh = 0;
		// remove list after an interval
		this.toID = (function () { this.clearSuggestions(); }.bind(this)).delay(this.options.timeout);
	},
	
	resetTimeout : function(){
		$clear(this.toID);
		this.toID = (function () { this.clearSuggestions(); }.bind(this)).delay(1000);
	},
	changeHighlight : function(key){
		var list = $("as_ul");
		if (!list){
			return false;
		}

		if (key == 'down'){
			var n = (this.iHigh + 1) > list.childNodes.length ? list.childNodes.length : this.iHigh + 1;
		}else if (key == 'up'){
			var n = (this.iHigh - 1) < 1 ? 1 : this.iHigh - 1;
		}
		
		this.setHighlight(n);
	},
	setHighlight : function(n){
			
		var list = $("as_ul");
		if (!list){
			return false;
		}
		if (this.iHigh > 0){
			this.clearHighlight();
		}
		this.iHigh = Number(n);
		list.childNodes[this.iHigh-1].className = "as_highlight";
	
		$clear(this.toID);
	},
	clearHighlight : function(){
		var list = $("as_ul");
		if (!list){
			return false;
		}
		if (this.iHigh > 0){
			list.childNodes[this.iHigh-1].className = "";
			this.iHigh = 0;
		}
	},
	setHighlightedValue : function (){
		if (this.iHigh){
			this.sInp = this.fld.value = this.filteredValues[ this.iHigh-1 ].value;
			
			// 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 ($type(this.options.callback) == "function"){
				this.options.callback( this.filteredValues[this.iHigh-1] );
			}
		}
	},
	// talalatok kiuritese, pl nyelvfelcserelesnel
	removeSuggestions : function(){
		this.cashedValues 	= $empty; // talalatok
		this.cashedValues	= [];
		this.filteredValues = $empty;
		this.filteredValues = [];
		this.clearSuggestions();
	},
	setNewOptions : function(options){
		this.setOptions(options);
		this.removeSuggestions();
	}
});
