function CndSuggest(input) {
	this.input=input;
	this.lastValue='';
	this.lastTime=null;
	this.lastSelected=null;

	//Parameter fuer die AJAX-Requests
	this.url=input.form.action;
	this.method=input.form.method.toUpperCase();
	this.params={OUTPUTFORMAT:'JSON'};
	if(CndSuggest.useDojo){
		dojo.query('input[type=hidden]', input.form).forEach(function(e){
			if (e.name!=='cssmarker') {
				this.params[e.name]=e.value;
			}
		},this);
	} else if(CndSuggest.usePrototype){
		$(input.form).select('input[type=hidden]').each(function(e){
			if (e.name!=='cssmarker') {
				this.params[e.name]=e.value;
			}
		},this);
	}
	
	//Select-Element fuer die Darstellung der Ergebnisse
	this.select=null;
	
	/*
	 * Ereignishandler fuer: Taste losgelassen
	 * Es wird die Pruefubng der Tipppausen initiert.
	 */
	this.handleKeypressed=function(event){
		event=(event)?event:window.event;
		if(event.keyCode!==13&&this.input.value!==this.lastValue&&this.input.value!==''){
			this.lastValue=this.input.value;
			var date=new Date();
			this.lastTime=date.getTime();
			var suggest=this;
			setTimeout(function(){suggest.handleSuggest();}, CndSuggest.timeout+30);
		}
	};
	
	/*
	 * Es werden die Tipppausen geprueft - sind diese lang genug,
	 * wird die eigentliche Suggest-Funktionalitaet aufgerufen
	 */
	this.handleSuggest=function() {
		var date=new Date();
		var timeout=date.getTime()-this.lastTime;
		if(timeout>CndSuggest.timeout){
			this.loadSuggest();
		}
	};

	/*
	 * Fuehrt die AJAX-Anfrage aus und verwendet hierfuer die Parameter vom
	 * Parent-Formulares des Input-Elementes
	 */
	this.loadSuggest=function(){
		var suggest=this;
		var params=this.params.valueOf();
		params[this.input.name]=this.lastValue;
		if(CndSuggest.useDojo) {
			dojo.xhr(this.method, {
				url:this.url,
				handleAs:'json',
				content:params,
				load: function(data, args){
					suggest.performAddSuggest(data);
				}
			},this.method=='POST');
		}else if(CndSuggest.usePrototype){
			var request=new Ajax.Request(this.url, {
				parameters: params,
				onSuccess: function(transport){
					suggest.performAddSuggest(transport.responseJSON);
				}
			});
		}
	};
	/*
	 * Liefert das Select-Element zur Darstellung der Ergebisse
	 */
	this.getSelectElement=function(){
		if(!this.select){
			this.select=document.createElement('ul');
			this.select.className='condero[suggest] hidden';
			
			this.select.style.visibility='hidden';
			this.select.style.position='absolute';
			this.select.style.left='0px';
			this.select.style.top=this.input.offsetHeight+'px';
			
			this.input.form.appendChild(this.select);

			var suggest=this;
			var mouseSelection=function(event){suggest.mouseSelection.call(suggest,event);};
			this.select.onmouseover=mouseSelection;
		}
		return this.select;
	};

	/*
	 * Zeigt das Select-Element mit den Ergebnissen an
	 */
	this.showResults=function(){
		if (this.select) {
			this.select.style.visibility='visible';
			this.select.className='condero[suggest] visible';
		}
	};

	/*
	 * Blendet das Select-Element mit den Ergebnissen aus
	 */
	this.hideResults=function(){
		if (this.select) {
			this.select.style.visibility='hidden';
			this.select.className='condero[suggest] hidden';
		}
	};

	/*
	 * EventHandler zur Ergebnisselektion per Tastatur
	 */
	this.keySelection=function(event){
		if (this.select){
			var elems=this.select.getElementsByTagName('li');
			if (elems.length>0){
				event=(event)?event:window.event;
				var code=event.keyCode;
				var sel=null;
				
				if(code==38){/*up*/
					sel=elems[elems.length-1];
					if(this.lastSelected) {
						this.lastSelected.className='';
						if (this.lastSelected.previousSibling) {
							sel=this.lastSelected.previousSibling;
						}
					}
					this.lastSelected = sel;
					this.lastSelected.className=this.checkedClass;

					//ggf. zum Eintrag scrollen
					if(this.lastSelected.offsetTop>=this.select.scrollTop+this.select.clientHeight){
						this.select.scrollTop=this.lastSelected.offsetHeight+this.lastSelected.offsetTop-this.select.clientHeight;
					}else if(this.lastSelected.offsetTop<this.select.scrollTop){
						this.select.scrollTop=this.lastSelected.offsetTop;
					}

					this.handleSelection(this.lastSelected.innerHTML, this.lastSelected.getAttribute('value'));
				}else if(code==40){/*down*/
					sel=elems[0];
					if(this.lastSelected) {
						this.lastSelected.className='';
						if (this.lastSelected.nextSibling) {
							sel=this.lastSelected.nextSibling;
						}
					}
					this.lastSelected = sel;
					this.lastSelected.className=this.checkedClass;

					//ggf. zum Eintrag scrollen
					if(this.lastSelected.offsetTop>=this.select.scrollTop+this.select.clientHeight){
						this.select.scrollTop=this.lastSelected.offsetHeight+this.lastSelected.offsetTop-this.select.clientHeight;
					}else if(this.lastSelected.offsetTop<this.select.scrollTop){
						this.select.scrollTop=this.lastSelected.offsetTop;
					}

					this.handleSelection(this.lastSelected.innerHTML, this.lastSelected.getAttribute('value'));
				}else if(code==13){/*RETURN*/
					this.fire();
					return true;
				}else if(code==27){/*ESCAPE*/
					this.hideResults();
				}
			}
		}
	};

	/*
	 * EventHandler zur Ergebnisselektion per Maus
	 */
	this.mouseSelection = function(event) {
		var src=(event)?event.target:window.event.srcElement;
		if(src!==this.lastSelected){
			if (this.lastSelected){
				this.lastSelected.className='';
			}
			src.className=this.checkedClass;
			this.lastSelected=src;
		}
		this.handleSelection(src.innerHTML, src.getAttribute('value'));
	};

	/*
	 * EventHandler zur Ergebnisaktivierung per Maus
	 */
	this.fire = function(event) {
		this.hideResults();
		this.input.focus();
		if(this.lastSelected){
			this.handleFire(this.lastSelected.innerHTML, this.lastSelected.getAttribute('value'));
		}
	};
}

CndSuggest.prototype.checkedClass='selected';
/*
 * Methode wird aufgerufen, wenn sich die Auswahl der Suggest-Values geaendert hat
 * (per Tastatur od. Maus)
 */
CndSuggest.prototype.handleSelection = function(label, value){};

/*
 * Methode wird aufgerufen, wenn ein Suggest-Value ausgewählt wurde
 * (per RETURN od. Maus-Klick)
 */
CndSuggest.prototype.handleFire = function(label, value){
	this.input.value=label;
};


CndSuggest.prototype.performAddSuggest=function(jsonResponse){
	//Ergebnisse abrufen;
	var values=null;
	try{
		values = CndSuggest.reader.getRecords(jsonResponse);
	}catch(ex){}
	
	if (values instanceof Array&&values.length>0) {
		//Alte Ergebisse aus der Darestellung entfernen
		var select=this.getSelectElement();
		for(var i=select.childNodes.length-1; i>=0; i--) {
			select.removeChild(select.childNodes[i]);
		}
		//ggf. Scrolling ganz nach oben
		select.scrollTop=0;
		
		this.lastSelected=null;
	
		//Funktionsreferenzen fuer Mouse-Events
		var suggest=this;
		var mouseFire=function(event){suggest.fire.call(suggest,event);};
		
		var count=0;
		for(i=0;i<values.length;i++){
		//Ergebnisdetails abrufen und auf Gueltigkeit pruefen
		var label=CndSuggest.reader.getLabel(values[i]);
		var value=CndSuggest.reader.getValue(values[i]);
		if(label===''||value===''){continue;}
		
		var elem=document.createElement('li');
		elem.innerHTML=label;
		elem.setAttribute('value', value);
		
		//Event-Handler fuer die Selektion per Maus
		elem.onclick=mouseFire;
		select.appendChild(elem);
		
		count++;
		}
		
		if(count>0){
			this.showResults();
		}
	}else{
		this.hideResults();
	}
};

/*
 * Initialisiert das Suggest-System mit allen Input-Elementen,
 * welche die CSS-Klasse condero[suggest] deklariert haben
 */
CndSuggest.init=function(reader,timeout){
	CndSuggest.reader=reader;
	CndSuggest.timeout=(timeout)?timeout:380;
	//auf verfuegbare JS-Bibliotheken pruefen
	CndSuggest.useDojo=false;
	CndSuggest.usePrototype=false;
	CndSuggest.useJQuery=false;
	var flag=false;
	if(dojo) {
		CndSuggest.useDojo=true;
		flag=dojo.isWebKit || dojo.isIE;
	} else if(Prototype){
		CndSuggest.usePrototype=true;
		flag=Prototype.Browser.WebKit || Prototype.Browser.IE;
	}else{
		alert('Keine Unterstuetzte JS Bibliothek gefunden (Prototype');
		return;
	}
	//Input-Elemente heraussuchen, Event-Handler registrieren
	if(CndSuggest.useDojo){
		dojo.query('form input[class*="condero[suggest]"]').forEach(function(e){
			dojo.attr(e, 'autocomplete', 'off');

			var suggest=new CndSuggest(e);
			dojo.connect(e, 'onkeyup', function(event){
				suggest.handleKeypressed.call(suggest, event);
			});
			dojo.connect(e,(flag?'keydown':'keypress'),function(event){
				if(suggest.keySelection.call(suggest, event)){
					event.preventDefault();
				}
			});
			dojo.connect(e,'click',function(event){
				suggest.hideResults();
			});
			dojo.connect(e,'blur',function(event){
				setTimeout(function(){suggest.hideResults();}, 1000);
			});
		});
	} else	if(CndSuggest.usePrototype){
		$$('form input[class~="condero[suggest]"]').inputs.each(function(e){
			e.setAttribute('autocomplete', 'off');

			var suggest=new CndSuggest(e);
			Event.observe(e,'keyup',function(event){
				suggest.handleKeypressed.call(suggest, event);
			});
			Event.observe(e,(flag?'keydown':'keypress'),function(event){
				if(suggest.keySelection.call(suggest, event)){
					if(CndSuggest.usePrototype) {
						event.stop();
					}
				}
			});
			Event.observe(e,'click',function(event){
				suggest.hideResults();
			});
			Event.observe(e,'blur',function(event){
				setTimeout(function(){suggest.hideResults();}, 1000);
			});
		});
	}
};


