/*
	Klasse: 	AutoComplete
	Autor:	    Lars Kreimeyer
	E-Mail: 	lkreimeyer@iscope.de
	Version:	1.0
	Erstellt:	10.01.2009
	Geaendert:  16.01.2009 - Mouse-Wheel Unterstuetzung eingebaut.
	Geandert:   21.10.2010 - Div ausblenden, wenn die Maus sich nicht mehr darüber befindet.

	Copyright (c) 2009,2010 Lars Kreimeyer
*/
function AutoComplete(id,debug,filename,imagePath,itemHeight,naviHeight,maxItemLength,maxItems) {
	// Membervariablen definieren
	// Das zu ueberwachende Inpu-Feld.
	this.id 	 = null;

	// Alphawert der Komponente
	this.opacity = 0;

	// Debug-div, wenn debug auf true
	this.debug;

	// Das Ergebnis-div
	this.resultDiv;

	// Variable, die sich den Timer zum Aufruf der keyDown-Methode merkt.
	this.destructTimer;
	
	// Variable, die sich den Timer zu Zerstoerung merkt
	this.destroyTimer;

	// Internes debug-flag
	this.debugFlag = debug;

	// Die Datei, die per AJAX aufgerufen werden soll.
	this.filename=filename;

	// Das Ergebnis-JSON
	this.resultJSON=null;

	// Der Index des aktuell ausgewaehlten Elements.
	this.index = -1;

	if (maxItems < 1) maxItems = 1;
	else if (undefined == maxItems) maxItems = 5;
	this.maxItems = maxItems;

    this.iframe;

    // Hoehe der Items in px
    this.itemHeight = itemHeight;

    this.naviHeight = naviHeight;

    this.naviScrollTime = 150;

    this.keyStrokeTime = 300;

    this.fadeEffectTime = 40;

    this.naviUpTimer;

    this.naviDownTimer;

    this.lastItem;

    this.firstItem;

    // Nach dieser Anzahl Zeichen fangen die Requests an
    this.maxLength = 3;

    // Maximale Zeichenlaenge
    if (maxItemLength<1) {
        maxItemLength = 1;
    }
    this.maxItemLength = maxItemLength;

    this.imageExt = 'gif';

    this.markType = 'u';

    this.browser;

    this.htmled = false;

    if (imagePath.charAt(imagePath.length-1) != '/') imagePath += '/';
    this.imagePath = imagePath;


	// http://www.lipfert-malik.de/webdesign/tutorial/bsp/browser_js_test.html
	 /*  Autor, Entwicklung 8/2002 Kristof Lipfert Duesseldorf    */
     /*  Version 2005-12-09                                  */
     /*  Modifiziert von lkreimeyer: Versionsbezeichnung entfernt. */
    // -->
        if(document.ids)x='nc4';
        else if( document.all && !document.getElementById )x='ie';
        else if( window.opera && !document.createElement )x='op';
        else if( window.opera && window.getComputedStyle )  {
                  if(document.createRange)x='op';
                    else if(window.navigate)x='op';
                                     else x='op';                   }
        else if( window.opera && document.compatMode )x='op';
        else if( window.opera && document.releaseEvents )x='op';
        else if( document.contains && !window.opera )x='kq';
        else if(window.pkcs11&&window.XML)x='ff';
        else if( window.getSelection && window.atob )x='nn';
        else if( window.getSelection && !document.compatMode )x='nn';
        else if( window.clipboardData && document.compatMode )
          x=window.XMLHttpRequest? 'ie' : 'ie';
        else if( window.clipboardData ){x='ie';}
             //if( !document.createDocumentFragment ) x+='.5';
             //if( document.doctype && !window.print ) x+='m';}
        else if( document.getElementById && !document.all ) x='op';
        else if( document.images && !document.all ) x='nn';
        else if(document.clientWidth&&!window.RegExp)x='kq';
        else x='???';
     // <--
    this.browser = x;



	// Debug-div erstellen -->
		if (debug) {
			this.debug = document.createElement('div');
			this.debug.className = 'iscopeAutoCompleteDebugWindow';
			document.body.appendChild(this.debug);
		}
	// <--
	if (debug) {
		this.debug.innerHTML = ('<p><b>AutoComplete (Constructor):</b> Image path set to "<span>'+this.imagePath+'</span>".</p>') + this.debug.innerHTML;
	}

	// Element finden
	this.id = document.getElementById(id);
	if (debug) {
		if (this.id) {
			this.debug.innerHTML = ('<p><b>AutoComplete (Constructor):</b> Found <span>'+this.id.type+'</span> with id <span>'+this.id.id+'</span>.</p>') + this.debug.innerHTML;
		}
		else {
			this.debug.innerHTML = ('<p class="error"><b>AutoComplete (Constructor):</b> Cannot find element with id <span>'+id+'</span>.</p>') + this.debug.innerHTML;
		}
	}


	// Ergebnis div erzeugen
	if (debug) {
		this.debug.innerHTML = ('<p><b>AutoComplete (Constructor):</b> Creating <span>result div</span>.</p>') + this.debug.innerHTML;
	}
	this.iframe = document.createElement('iframe');
	var wrapper = document.createElement('div');
	wrapper.style.zIndex   = 99999;
	wrapper.style.position = 'absolute';


	this.resultDiv = document.createElement('div');


	// CSS-Klasse fuer den Wrapper einbinden
	this.resultDiv.className	= 'iscopeAutoCompleteDivBox';
	this.resultDiv.id			= 'iscopeAutoCompleteDivBox';

	var className = this.id.className;
	var width;

	// Wenn das Element Breitenangaben verwendet, diese benutzen -->
		if ((width=this.id.getAttribute('width'))) {
			this.resultDiv.style.width = width;
			if (debug) {
				this.debug.innerHTML = ('<p ><b>AutoComplete (Constructor):</b> Found with attribute. Using width <span>'+width+'</span>.</p>') + this.debug.innerHTML;
			}
		}
		else if ((width=this.id.style.width)) {
			this.resultDiv.style.width = width;
			if (debug) {
				this.debug.innerHTML = ('<p ><b>AutoComplete (Constructor):</b> Found with attribute. Using width <span>'+width+'</span>.</p>') + this.debug.innerHTML;
			}
		}
		else {
			width ='200px'
			this.resultDiv.style.width = width;
			if (debug) {
				this.debug.innerHTML = ('<p ><b>AutoComplete (Constructor):</b> Using default width of <span>'+width+'</span>.</p>') + this.debug.innerHTML;
			}
		}
	// <--

	wrapper.style.width = width;
	this.iframe.style.width    = width;
	this.iframe.style.position = 'absolute';
	this.iframe.style.zIndex   = 100;
	this.iframe.style.display  = 'none';
	this.iframe.style.filter = 'alpha(opacity=0)';
	this.iframe.setAttribute('src','javascript:\'\';',0);
	this.iframe.setAttribute('marginwidth',0,0);
	this.iframe.setAttribute('marginheight',0,0);
	this.iframe.setAttribute('scrolling','no',0);
	this.iframe.setAttribute('frameborder',0,0);
	// IE gefunden, hier muss der div verschoben werden
	if ('ie'==this.browser) {
		wrapper.style.marginLeft = '-'+width;
		this.iframe.style.marginLeft = '-'+width;
		wrapper.style.marginTop = this.id.style.height;
		this.iframe.style.marginTop = this.id.style.height;
	}


	// Das Ergebnis-div verstecken
	this.resultDiv.style.position = 'absolute';
	this.resultDiv.style.display = 'none';

	// div nach dem zu ueberwachenden Element anhaengen
	var parent     = this.id.parentNode;
	var nextItem   = this.id.nextSibling;

	wrapper.appendChild(this.resultDiv);

	// IE-hack um Selectboxen ueberlagern zu koennen.
	if ('ie'==this.browser) {
	   parent.insertBefore(this.iframe,nextItem);
	}
	parent.insertBefore(wrapper,nextItem);

	var self = this;
	this.setHtmlEntityDecode = function(on) {
	   if (on) {
	       this.htmled = true;
	   }
	   else {
	       this.htmled = false;
	   }
	}

	this.isChild = function(targ,cobj) {
		if (targ.id == cobj.id) return false;
		var retval=false;
		var curobj;
		curobj=targ.parentNode;
		var i=0;
		while(curobj!=undefined && curobj!=document.body) {i++;
		   if (curobj.parentNode==document.body) break;
		   if (curobj.id == cobj.id) {
		   		retval = true;
		   		break;
		   }
		   curobj=curobj.parentNode;
		}

		return retval;
	}

	// http://adomas.org/javascript-mouse-wheel/
	this.mousewheel = function(e) {
        var delta = 0;
        if (!e) var e=window.event;
        if (e.wheelDelta) { // IE
            delta = e.wheelDelta/120;
            if (window.opera)
                delta = -delta;
        }
        else if (e.detail) { // FF
            delta = -e.detail/3;
        }
        /* delta <0 bei Scrolldown */
        if (delta<0)
            self.naviDownMethod(true);
        else if (delta>0)
            self.naviUpMethod(true);

        if (e.preventDefault)
                e.preventDefault();
	    e.returnValue = false;
    }

    this.resetDestroyAutoComplete = function(e) {
  	window.clearTimeout(self.destroyTimer);
    }

    this.destroyAutoComplete = function(e) {
      window.clearTimeout(self.destroyTimer);
      self.destroyTimer = window.setTimeout(function () {self.fadeOut();}, 100);
    }

	this.naviDown = function(e) {
	    self.naviDownMethod();
	}

	this.naviDownOut = function(e) {
	    window.clearTimeout(self.naviDownTimer);
	}

	this.naviUp = function(e) {
	    self.naviUpMethod();
	}

	this.naviUpOut = function(e) {
	    window.clearTimeout(self.naviUpTimer);
	}

	this.setMaxLength = function(maxLength) {
	   if (maxLength < 1) {
	       maxLength = 1;
	   }
	   this.maxLength = maxLength;
	}

	this.setNaviScrollTime = function(maxTime) {
	   if (maxTime < 0) {
	       maxTime = 0;
	   }
	   this.naviScrollTime = maxTime;
	}

	this.setKeyStrokeTime = function(maxTime) {
	   if (maxTime < 0) {
	       maxTime = 0;
	   }
	   this.keyStrokeTime = maxTime;
	}

	this.setFadeEffectTime = function(maxTime) {
	   if (maxTime < 0) {
	       maxTime = 0;
	   }
	   this.fadeEffectTime = maxTime;
	}

	this.setImageExt = function(ext) {
	   this.imageExt = ext;
	}

	this.setMarkType = function(type) {
	   if ('italic'==type) {
	       this.markType = 'i';
	   }
	   else if('bold'==type) {
	       this.markType = 'b';
	   }
	   else {
	       this.markType = 'u'
	   }
	}

	this.isVisible = function() {
	   if ('block'==this.resultDiv.style.display) return true;
	   return false;
	}

	this.mouseover = function(e) {
		// http://www.quirksmode.org/js/events_properties.html -->
		if (!e) var e = window.event;
		if (e.target) targ = e.target;
		else if (e.srcElement) targ = e.srcElement;
		if (targ.nodeType == 3) // defeat Safari bug
		targ = targ.parentNode;
		// <--

		if ('b'==targ.tagName.toLowerCase() || 'u'==targ.tagName.toLowerCase()) {
		  targ = targ.parentNode;
		}
		targ.className = 'selected';

		var pos = targ.getAttribute('pos');
		if (-1<self.index) {
            if (pos!=self.index) {
    		    pNodes = self.resultDiv.getElementsByTagName('p');
    		    // Durch das schnelle hinzufuegen und loeschen von Knoten, kann es sein, dass der Wert zu gross ist.
    		    self.index = self.index%pNodes.length;
    			if (0==self.index%2) {
    				pNodes[self.index].className = 'peven';
    			}
    			else {
    				pNodes[self.index].className = 'podd';
    			}
    		}
		}


		self.index = parseInt(pos);
	}

	this.mouseout = function(e) {
		// http://www.quirksmode.org/js/events_properties.html -->
		if (!e) var e = window.event;
		if (e.target) targ = e.target;
		else if (e.srcElement) targ = e.srcElement;
		if (targ.nodeType == 3) // defeat Safari bug


		targ = targ.parentNode;
		// <--
		if ('b'==targ.tagName.toLowerCase() || 'u'==targ.tagName.toLowerCase() || 'i'==targ.tagName.toLowerCase()) {
		  targ = targ.parentNode;
		}
		if (-1<self.index) {
		    pNodes = self.resultDiv.getElementsByTagName('p');
		    // Durch das schnelle hinzufuegen und loeschen von Knoten, kann es sein, dass der Wert zu gross ist.
		    self.index = self.index%pNodes.length;
			if (0==self.index%2) {
				targ.className = 'peven';
			}
			else {
				targ.className = 'podd';
			}
		}
	}

	this.click = function(e) {
		// http://www.quirksmode.org/js/events_properties.html -->
		if (!e) var e = window.event;
		if (e.target) targ = e.target;
		else if (e.srcElement) targ = e.srcElement;
		if (targ.nodeType == 3) // defeat Safari bug



		targ = targ.parentNode;
		// <--
		if ('b'==targ.tagName.toLowerCase() || 'u'==targ.tagName.toLowerCase() || 'i'==targ.tagName.toLowerCase()) {
		  targ = targ.parentNode;
		}
		// Den gewaehlten Wert ermitteln ...
		var value = targ.getAttribute('value');

		// ... und einfuegen.
		if (value) {
			self.id.value = value;
		}
		self.id.focus();
		self.fadeOut();
	}

	this.keyStroke = function(e) {
	    if (!e) var e = window.event;
		// Fall schnell hintereinander Tasten gedrueckt werden, wird hier der Timer immer wieder geloescht.
		window.clearTimeout(self.destructTimer);
		keyCode = e.keyCode;
		// Umstaendliche Key-Abfrage
		// Bei Enter keinen Request
		// 13 = Enter
		// 16 = Shift
		// 17 = Strg
		// 18 = Alt
		// 19 = Pause
		// 27 = Escape
		// 34 = Bild-Runter
		// 35 = Ende
		// 36 = Pos1
		// 33 = Bild-Hoch
		// 38 = Pfeil-Rauf
		// 40 = Pfeil-Runter
		// 45 = Eunfuegen
		// 145 = Rollen

		window.clearTimeout(self.destroyTimer); // Timer kaputt machen
		
		if (13!=keyCode && 40!=keyCode && 38 != keyCode && 27 != keyCode && keyCode != 16 && keyCode != 17 && keyCode != 18 &&
			33 != keyCode && 34!=keyCode && 45!=keyCode && 35!=keyCode && 36!=keyCode && 19!=keyCode && 145!=keyCode) {
    	      self.destructTimer = window.setTimeout(function () {self.callAutoComplete(keyCode);}, self.keyStrokeTime);
		}
		else {
			// Sonderfaelle
			switch(keyCode) {
				case 27: // Escape
						 self.fadeOut();
						 break;
				case 34: // Bild-Runter
				case 40: // Pfeil-Runter
						 if ('block' == self.resultDiv.style.display) {
						 	pNodes = self.resultDiv.getElementsByTagName('p');
						 	if (pNodes) {
						 	    if ((self.index+1) < pNodes.length) {
    						 		if (-1<self.index) {
    						 		   // Durch das schnelle hinzufuegen und loeschen von Knoten, kann es sein, dass der Wert zu gross ist.
    						 		   self.index = self.index%pNodes.length;
    							 		if (0==self.index%2) {
    										pNodes[self.index].className = 'peven';
    									}
    									else {
    										pNodes[self.index].className = 'podd';
    									}
    								}
    							 	self.index++;

    							 	pNodes[self.index].className = 'selected';

    							 	var naviUp = document.getElementById('iscopeAutoCompleteNaviUp');
                            	    var imgUp = null;
                            	    if (naviUp) {
                                	    imgUp = naviUp.getElementsByTagName('img')[0];
                                	}
                                	var naviDown = document.getElementById('iscopeAutoCompleteNaviDown');
                            	    var imgDown = null;
                            	    if (naviDown) {
                                	    imgDown = naviDown.getElementsByTagName('img')[0];
                                	}
    							 	if ('none'==pNodes[self.index].style.display) {
       							 	    var firstElem = self.index-self.maxItems;
    							 	    pNodes[firstElem].style.display = 'none';
        						 	    pNodes[self.index].style.display = 'block';

        						 	    this.lastItem++;
                                   		this.firstItem++;
                            	 	    if (null!=imgDown) {
                            	 	         if (this.lastItem<(pNodes.length-1)) {
                                	           imgDown.src = this.imagePath+'down_active.'+this.imageExt;
                                	         }
                                	         else {
                                	           imgDown.src = this.imagePath+'down_inactive.'+this.imageExt;
                                	         }
                                	    }

                                	    if (null!=imgUp) {
                            	 	         if (this.firstItem>0) {
                                	           imgUp.src = this.imagePath+'up_active.'+this.imageExt;
                                	         }
                                	         else {
                                	           imgUp.src = this.imagePath+'up_inactive.'+this.imageExt;
                                	         }
                                	    }
        						 	}
           						 }
							}
						 }
						 break;
				case 33: // Bild-Hoch
				case 38: // Pfeil-Hoch
						 if ('block' == self.resultDiv.style.display) {
						 	pNodes = self.resultDiv.getElementsByTagName('p');
						 	if (pNodes) {
						 	    if ((self.index-1) >= 0) {
    						 		if (-1<self.index) {
    						 		   // Durch das schnelle hinzufuegen und loeschen von Knoten, kann es sein, dass der Wert zu gross ist.
    						 		   self.index = self.index%pNodes.length;
    							 		if (0==self.index%2) {
    										pNodes[self.index].className = 'peven';
    									}
    									else {
    										pNodes[self.index].className = 'podd';
    									}
    								}
    							 	self.index--;

    							 	pNodes[self.index].className = 'selected';

    							 	var naviUp = document.getElementById('iscopeAutoCompleteNaviUp');
                            	    var imgUp = null;
                            	    if (naviUp) {
                                	    imgUp = naviUp.getElementsByTagName('img')[0];
                                	}
                                	var naviDown = document.getElementById('iscopeAutoCompleteNaviDown');
                            	    var imgDown = null;
                            	    if (naviDown) {
                                	    imgDown = naviDown.getElementsByTagName('img')[0];
                                	}
    							 	if ('none'==pNodes[self.index].style.display) {
       							 	    var lastElem = self.index+self.maxItems;

    							 	    pNodes[lastElem].style.display = 'none';
        						 	    pNodes[self.index].style.display = 'block';

        						 	    this.lastItem--;
                                   		this.firstItem--;
                            	 	    if (null!=imgDown) {
                            	 	         if (this.lastItem<(pNodes.length-1)) {
                                	           imgDown.src = this.imagePath+'down_active.'+this.imageExt;
                                	         }
                                	         else {
                                	           imgDown.src = this.imagePath+'down_inactive.'+this.imageExt;
                                	         }
                                	    }

                                	    if (null!=imgUp) {
                            	 	         if (this.firstItem>0) {
                                	           imgUp.src = this.imagePath+'up_active.'+this.imageExt;
                                	         }
                                	         else {
                                	           imgUp.src = this.imagePath+'up_inactive.'+this.imageExt;
                                	         }
                                	    }
        						 	}
       							 }
							}
						 }
						 break;
				case 13: // Enter
						if ('block' == self.resultDiv.style.display) {
							pNodes = self.resultDiv.getElementsByTagName('p');
							if (pNodes) {
								if (-1==self.index) {
									self.fadeOut();
								}
								else {
					       			if (self.htmled) {
				                        self.id.value = self.html_entity_decode(pNodes[self.index].getAttribute('value'));
				                    }
                                    else {
									   self.id.value = pNodes[self.index].getAttribute('value');
									}
								}
							}
					   }
					   self.fadeOut();
			}
		}

	}

	this.callAutoComplete = function(keyCode){
	   // Nachdem der Timer abgelaufen ist, sollte das value in der inputbox angekommen sein.
	   if (0==self.id.value.length || self.id.value.length < self.maxLength) {
            self.fadeOut();
        }
        else {
   	       self.makeRequest(self.id.value);
    	}
	}





	// Listener -->
	    if (this.id.addEventListener) {
		  this.id.addEventListener('keydown',this.keyStroke,false);
          this.id.addEventListener('DOMMouseScroll', this.mousewheel, false);
          this.resultDiv.addEventListener('DOMMouseScroll', this.mousewheel, false);
	  this.resultDiv.addEventListener('mouseout', this.destroyAutoComplete, false);
          this.resultDiv.addEventListener('mouseover', this.resetDestroyAutoComplete, false);
		}
		else {
		  this.id.attachEvent("onkeydown", this.keyStroke);
		  this.id.attachEvent("onmousewheel",this.mousewheel);
		  this.resultDiv.attachEvent("onmousewheel",this.mousewheel);
		  this.resultDiv.attachEvent("mouseout",this.destroyAutoComplete);
		  this.resultDiv.attachEvent("mouseover",this.resetDestroyAutoComplete);
		}
	// <--
}





// fadeIn/fadeOut-Funktion fuer den AutoComplete
// Adaptiert aus swfupload.queue.js der SWF Upload Komponente
// http://www.swfupload.org/
AutoComplete.prototype.fadeIn = function(){
	var increaseOpacityBy = 15;
	var rate = this.fadeEffectTime;	// 15 fps


	if (this.opacity < 100) {
		this.opacity += increaseOpacityBy;
		if (this.opacity > 100) {
			this.opacity = 100;
		}

		if (this.resultDiv.filters) {
			try {
				this.resultDiv.filters.item("DXImageTransform.Microsoft.Alpha").opacity = this.opacity;
			} catch (e) {
				// If it is not set initially, the browser will throw an error.  This will set it if it is not set yet.
				this.resultDiv.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=" + this.opacity + ")";
			}
		} else {
			this.resultDiv.style.opacity = this.opacity / 100;
		}
	}

	if (this.opacity < 100) {
		var self = this;
		window.setTimeout(function () {
			self.fadeIn();
		}, rate);
	}

	if (this.debugFlag) {
		this.debug.innerHTML = ('<p><b>AutoComplete (fadeIn):</b> Opacity increased to <span>'+this.opacity+'</span>.</p>')  + this.debug.innerHTML;;
	}
}


AutoComplete.prototype.fadeOut = function(){
	var reduceOpacityBy = 15;
    var rate = this.fadeEffectTime;	// 15 fps

	if (this.opacity > 0) {
		this.opacity -= reduceOpacityBy;
		if (this.opacity < 0) {
			this.opacity = 0;
		}

		if (this.resultDiv.filters) {
			try {
				this.resultDiv.filters.item("DXImageTransform.Microsoft.Alpha").opacity = this.opacity;
			} catch (e) {
				// If it is not set initially, the browser will throw an error.  This will set it if it is not set yet.
				this.resultDiv.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=" + this.opacity + ")";
			}
		} else {
			this.resultDiv.style.opacity = this.opacity / 100;
		}
	}

	if (this.opacity > 0) {
		var self = this;
		window.setTimeout(function () {
			self.fadeOut();
		}, rate);
	}
	else {
		this.resultDiv.style.display = 'none';
		this.iframe.style.display    = 'none';
	}

	if (this.debugFlag) {
		this.debug.innerHTML = ('<p><b>AutoComplete (fadeOut):</b> Opacity reduced to <span>'+this.opacity+'</span>.</p>') + this.debug.innerHTML;
	}
    this.resultJSON=null;
    this.index = -1;
}

AutoComplete.prototype.makeRequest = function(value) {
       if (this.debugFlag) {
            this.debug.innerHTML = ('<p><b>AutoComplete (makeRequest):</b> Making request @<span>'+new Date().toLocaleString()+'</span>.</p>') + this.debug.innerHTML;
	   }

	// HTTP-Request Objekt erzeugen -->
		var request;
		try {
			request = new XMLHttpRequest();
		}
		catch (ms) {
			try {
				request = new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch (nonms) {
				try {
					request = new ActiveXObject("Microsoft.XMLHTTP");
				}
				catch (failed) {
					request = null;
				}
			}
		}
	// <--
	if (null!=request) {
		request.open("POST", this.filename, true);
		// Spezialbehandlung für einige ältere Mozilla-Versionen
        if (request.overrideMimeType) {
            request.overrideMimeType('text/xml; charset=utf-8');
        }
		request.setRequestHeader("Content-type", 'application/x-www-form-urlencoded; charset=utf-8');
		request.setRequestHeader("Content-Transfer-Encoding", "8bit");
		request.setRequestHeader("Content-length", value.length);
		//request.setRequestHeader("Connection", "close");
		request.send("value="+value+"&id="+this.id.id);

		var self=this;
		request.onreadystatechange = function() {
			switch(request.readyState) {
				case 4:
					if(request.status==200) {
						resultJSON = eval( "(" + request.responseText + ")");
						if (resultJSON) {
							self.resultJSON = resultJSON;
							self.keydown();
						}
						else {
							self.resultJSON = null;
						}
					}
					break;
				default:
					self.resultJSON= null;
					break;
			}
		};
	}
	else {
		if (this.debugFlag) {
			this.debug.innerHTML = ('<p class="error"><b>AutoComplete (makeRequest):</b> <span>Could not</span> create request object.</p>') + this.debug.innerHTML;
		}
	}
}

AutoComplete.prototype.naviUpMethod = function(noTimer) {
        var naviDiv = document.getElementById('iscopeAutoCompleteNaviUp');
	    var img = null;
	    if (naviDiv) {
    	    img = naviDiv.getElementsByTagName('img')[0];
    	}

		pNodes = this.resultDiv.getElementsByTagName('p');
		var nextItem=null;
		var firstElem;
		var p=this.firstItem-1;
		var naviDiv2 = document.getElementById('iscopeAutoCompleteNaviDown');
		if (naviDiv2) {
		  var img2 = naviDiv2.getElementsByTagName('img')[0];
		}

   		if (p >= 0) {
		  if ('none'==pNodes[p].style.display) {
		      nextItem=p;
		      firstElem = p+this.maxItems;
		  }
		}

		if (null!=nextItem) {
			pNodes[firstElem].style.display = 'none';
	 	    pNodes[nextItem].style.display = 'block';
	 	    if (null!=img) {
	 	         if (p-1>=0) {
    	           img.src = this.imagePath+'up_active.'+this.imageExt;
    	         }
    	         else {
    	           img.src = this.imagePath+'up_inactive.'+this.imageExt;
    	         }
    	    }


    	    if (img2) {
   		       img2.src = this.imagePath+'down_active.'+this.imageExt;
       		}
       		this.firstItem = p;
       		this.lastItem--;
       		var self=this;
       		if (this.firstItem-1>=0) {
       		   if (undefined==noTimer) {
       		       noTimer = false;
       		   }
       		   if (!noTimer) {
       		       this.naviUpTimer = window.setTimeout(function () {self.naviUpMethod(noTimer);}, self.naviScrollTime);
       		   }
       	    }
	 	}
	 	else {
	 	   if (img)
  	         img.src = this.imagePath+'up_inactive.'+this.imageExt;
 	 	}
}

AutoComplete.prototype.naviDownMethod = function(noTimer) {
        var naviDiv = document.getElementById('iscopeAutoCompleteNaviDown');
	    var img = null;
	    if (naviDiv) {
    	    img = naviDiv.getElementsByTagName('img')[0];
    	}

		pNodes = this.resultDiv.getElementsByTagName('p');
		var nextItem=null;
		var firstElem;
		var p=this.lastItem+1;
		var naviDiv2 = document.getElementById('iscopeAutoCompleteNaviUp');
		if (naviDiv2) {
		  var img2 = naviDiv2.getElementsByTagName('img')[0];
		}

   		if (p < pNodes.length) {
		  if ('none'==pNodes[p].style.display) {
		      nextItem=p;
		      firstElem = p-this.maxItems;
		  }
		}

		if (null!=nextItem) {
			pNodes[firstElem].style.display = 'none';
	 	    pNodes[nextItem].style.display = 'block';
	 	    if (null!=img) {
	 	         if (p+1<pNodes.length) {
    	           img.src = this.imagePath+'down_active.'+this.imageExt;
    	         }
    	         else {
    	           img.src = this.imagePath+'down_inactive.'+this.imageExt;
    	         }
    	    }


    	    if (img2) {
       		    img2.src = this.imagePath+'up_active.'+this.imageExt;
       		}
       		this.lastItem = p;
       		this.firstItem++;
       		var self=this;
       		if (this.lastItem+1<pNodes.length) {
       		   if (undefined==noTimer) {
       		       noTimer = false;
       		   }
       		   if (!noTimer) {
       		       this.naviDownTimer =window.setTimeout(function () {self.naviDownMethod(noTimer);}, self.naviScrollTime);
       		   }
       		}

	 	}
	 	else {
	 	 if (img)
  	         img.src = this.imagePath+'down_inactive.'+this.imageExt;
   	 	}
}

AutoComplete.prototype.get_html_translation_table = function(table, quote_style) {
    // Returns the translation table used by htmlspecialchars() and htmlentities()
    //
    // +    discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_get_html_translation_table/
    // +       version: 901.714
    // +   original by: Philip Peterson
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: noname
    // %          note: It has been decided that we're not going to add global
    // %          note: dependencies to php.js. Meaning the constants are not
    // %          note: real constants, but strings instead. integers are also supported if someone
    // %          note: chooses to create the constants themselves.
    // %          note: Table from http://www.the-art-of-web.com/html/character-codes/
    // *     example 1: get_html_translation_table('HTML_SPECIALCHARS');
    // *     returns 1: {'"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;'}

    var entities = {}, histogram = {}, decimal = 0, symbol = '';
    var constMappingTable = {}, constMappingQuoteStyle = {};
    var useTable = {}, useQuoteStyle = {};

    useTable      = (table ? table.toUpperCase() : 'HTML_SPECIALCHARS');
    useQuoteStyle = (quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT');

    // Translate arguments
    constMappingTable[0]      = 'HTML_SPECIALCHARS';
    constMappingTable[1]      = 'HTML_ENTITIES';
    constMappingQuoteStyle[0] = 'ENT_NOQUOTES';
    constMappingQuoteStyle[2] = 'ENT_COMPAT';
    constMappingQuoteStyle[3] = 'ENT_QUOTES';

    // Map numbers to strings for compatibilty with PHP constants
    if (!isNaN(useTable)) {
        useTable = constMappingTable[useTable];
    }
    if (!isNaN(useQuoteStyle)) {
        useQuoteStyle = constMappingQuoteStyle[useQuoteStyle];
    }

    if (useQuoteStyle != 'ENT_NOQUOTES') {
        entities['34'] = '&quot;';
    }

    if (useQuoteStyle == 'ENT_QUOTES') {
        entities['39'] = '&#039;';
    }

    if (useTable == 'HTML_SPECIALCHARS') {
        // ascii decimals for better compatibility
        entities['38'] = '&amp;';
        entities['60'] = '&lt;';
        entities['62'] = '&gt;';
    } else if (useTable == 'HTML_ENTITIES') {
        // ascii decimals for better compatibility
	    entities['38']  = '&amp;';
	    entities['60']  = '&lt;';
	    entities['62']  = '&gt;';
	    entities['160'] = '&nbsp;';
	    entities['161'] = '&iexcl;';
	    entities['162'] = '&cent;';
	    entities['163'] = '&pound;';
	    entities['164'] = '&curren;';
	    entities['165'] = '&yen;';
	    entities['166'] = '&brvbar;';
	    entities['167'] = '&sect;';
	    entities['168'] = '&uml;';
	    entities['169'] = '&copy;';
	    entities['170'] = '&ordf;';
	    entities['171'] = '&laquo;';
	    entities['172'] = '&not;';
	    entities['173'] = '&shy;';
	    entities['174'] = '&reg;';
	    entities['175'] = '&macr;';
	    entities['176'] = '&deg;';
	    entities['177'] = '&plusmn;';
	    entities['178'] = '&sup2;';
	    entities['179'] = '&sup3;';
	    entities['180'] = '&acute;';
	    entities['181'] = '&micro;';
	    entities['182'] = '&para;';
	    entities['183'] = '&middot;';
	    entities['184'] = '&cedil;';
	    entities['185'] = '&sup1;';
	    entities['186'] = '&ordm;';
	    entities['187'] = '&raquo;';
	    entities['188'] = '&frac14;';
	    entities['189'] = '&frac12;';
	    entities['190'] = '&frac34;';
	    entities['191'] = '&iquest;';
	    entities['192'] = '&Agrave;';
	    entities['193'] = '&Aacute;';
	    entities['194'] = '&Acirc;';
	    entities['195'] = '&Atilde;';
	    entities['196'] = '&Auml;';
	    entities['197'] = '&Aring;';
	    entities['198'] = '&AElig;';
	    entities['199'] = '&Ccedil;';
	    entities['200'] = '&Egrave;';
	    entities['201'] = '&Eacute;';
	    entities['202'] = '&Ecirc;';
	    entities['203'] = '&Euml;';
	    entities['204'] = '&Igrave;';
	    entities['205'] = '&Iacute;';
	    entities['206'] = '&Icirc;';
	    entities['207'] = '&Iuml;';
	    entities['208'] = '&ETH;';
	    entities['209'] = '&Ntilde;';
	    entities['210'] = '&Ograve;';
	    entities['211'] = '&Oacute;';
	    entities['212'] = '&Ocirc;';
	    entities['213'] = '&Otilde;';
	    entities['214'] = '&Ouml;';
	    entities['215'] = '&times;';
	    entities['216'] = '&Oslash;';
	    entities['217'] = '&Ugrave;';
	    entities['218'] = '&Uacute;';
	    entities['219'] = '&Ucirc;';
	    entities['220'] = '&Uuml;';
	    entities['221'] = '&Yacute;';
	    entities['222'] = '&THORN;';
	    entities['223'] = '&szlig;';
	    entities['224'] = '&agrave;';
	    entities['225'] = '&aacute;';
	    entities['226'] = '&acirc;';
	    entities['227'] = '&atilde;';
	    entities['228'] = '&auml;';
	    entities['229'] = '&aring;';
	    entities['230'] = '&aelig;';
	    entities['231'] = '&ccedil;';
	    entities['232'] = '&egrave;';
	    entities['233'] = '&eacute;';
	    entities['234'] = '&ecirc;';
	    entities['235'] = '&euml;';
	    entities['236'] = '&igrave;';
	    entities['237'] = '&iacute;';
	    entities['238'] = '&icirc;';
	    entities['239'] = '&iuml;';
	    entities['240'] = '&eth;';
	    entities['241'] = '&ntilde;';
	    entities['242'] = '&ograve;';
	    entities['243'] = '&oacute;';
	    entities['244'] = '&ocirc;';
	    entities['245'] = '&otilde;';
	    entities['246'] = '&ouml;';
	    entities['247'] = '&divide;';
	    entities['248'] = '&oslash;';
	    entities['249'] = '&ugrave;';
	    entities['250'] = '&uacute;';
	    entities['251'] = '&ucirc;';
	    entities['252'] = '&uuml;';
	    entities['253'] = '&yacute;';
	    entities['254'] = '&thorn;';
	    entities['255'] = '&yuml;';
    } else {
        throw Error("Table: "+useTable+' not supported');
        return false;
    }

    // ascii decimals to real symbols
    for (decimal in entities) {
        symbol = String.fromCharCode(decimal)
        histogram[symbol] = entities[decimal];
    }

    return histogram;
}

AutoComplete.prototype.html_entity_decode = function( string, quote_style ) {
    // http://kevin.vanzonneveld.net
    // +   original by: john (http://www.jd-tech.net)
    // +      input by: ger
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   bugfixed by: Onno Marsman
    // +   improved by: marc andreu
    // +    revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // -    depends on: get_html_translation_table
    // *     example 1: html_entity_decode('Kevin &amp; van Zonneveld');
    // *     returns 1: 'Kevin & van Zonneveld'
    // *     example 2: html_entity_decode('&amp;lt;');
    // *     returns 2: '&lt;'

    var histogram = {}, symbol = '', tmp_str = '', entity = '';
    tmp_str = string.toString();

    if (false === (histogram = this.get_html_translation_table('HTML_ENTITIES', quote_style))) {
        return false;
    }

    // &amp; must be the last character when decoding!
    delete(histogram['&']);
    histogram['&'] = '&amp;';

    for (symbol in histogram) {
        entity = histogram[symbol];
        tmp_str = tmp_str.split(entity).join(symbol);
    }

    return tmp_str;
}


// keydown-Funktion -->
AutoComplete.prototype.keydown = function() {
	if (this.debugFlag) {
		this.debug.innerHTML = ('<p><b>AutoComplete (keydown):</b> Value is <span>'+this.id.value+'</span>. Called @<span>'+new Date().toLocaleString()+'</span>.</p>') + this.debug.innerHTML;
	}

	var numItems = 0;
	if (null!=this.resultJSON) {
		var res = this.resultJSON;
		itemsResultDiv = this.resultDiv.getElementsByTagName('p');

		var totalHeight=0;
		if (res.result) {
			numItems 	= res.result.length;
			numInDiv 	= itemsResultDiv.length;
			numRemove	= numInDiv-numItems;

			for (var i=0; i<(numRemove); i++) {
				this.resultDiv.removeChild(itemsResultDiv[0]);
			}

			var i;
			var styleobj;



			this.lastItem=0;
			this.firstItem=0;
			for (i=0; i<numItems; i++) {
				pItem = document.createElement('p');
				var classHeight;
				if (0==i%2) {
					pItem.className = 'peven';
					classHeight = 'peven';
				}
				else {
					pItem.className = 'podd';
					classHeight = 'podd';
				}




				pItem.setAttribute('value',res.result[i].itemValue,0);
				pItem.setAttribute('pos',i,0);

				if (this.htmled) {
			   		res.result[i].value = this.html_entity_decode(res.result[i].value);
				}

				var start = res.result[i].value.toLowerCase().indexOf(this.id.value.toLowerCase());
				var end   = start+this.id.value.length;

				// String zu lang.
				if (res.result[i].value.length>this.maxItemLength) {
				    var offset = Math.floor(this.id.value.length/2)+start;
				    var lengthPlus = Math.floor(this.maxItemLength/2);
				    var lengthMin  = Math.ceil(this.maxItemLength/2);

				    start = offset-lengthMin;
				    var remainder;
				    if (start<0 && offset+lengthPlus>res.result[i].value.length) {
				        lengthPlus -= res.result[i].value.length;
				        start  = 0;
				    }
				    else if (start<0) {
				        remainder = -1*start;
				        lengthPlus +=remainder;
				        lengthMin  -=remainder;
				        start = 0;
				    }
				    else if(offset+lengthPlus>res.result[i].value.length) {
				        remainder = offset+lengthPlus-res.result[i].value.length;
				        lengthMin  += remainder;
				        start      -= remainder;
				        lengthPlus -= remainder;
				    }
				    res.result[i].value = res.result[i].value.substr(start,lengthMin)+res.result[i].value.substr(offset,lengthPlus);
                }

                var start = res.result[i].value.toLowerCase().indexOf(this.id.value.toLowerCase());
				var end   = start+this.id.value.length;

				// Sollte eigentlich nicht passieren, da wir ja nach dem value gesucht haben, aber wer weiß?!
				if (-1==start) {
				    text = '<'+this.markType+'>'+res.result[i].value+'</'+this.markType+'>';
				}
				else {
            		text = res.result[i].value.substring(0,start)+'<'+this.markType+'>'+res.result[i].value.substring(start,end)+'</'+this.markType+'>'+res.result[i].value.substring(end,res.result[i].value.length);
            	}


				if (pItem.addEventListener) {
		            pItem.addEventListener('click',this.click,false);
				    pItem.addEventListener('mouseover',this.mouseover,false);
				    pItem.addEventListener('mouseout',this.mouseout,false);
				    
		        }
		        else {
		            pItem.attachEvent('onclick',this.click);
				    pItem.attachEvent('onmouseover',this.mouseover);
				    pItem.attachEvent('onmouseout',this.mouseout);
		        }


			    pItem.style.height = this.itemHeight;

				pItem.innerHTML = text;

				if (i<itemsResultDiv.length) {
					this.resultDiv.replaceChild(pItem,itemsResultDiv[i]);
				}
				else {
					this.resultDiv.appendChild(pItem);
				}

				if (i>=this.maxItems) {
				    if (0==this.lastItem) {
				        this.lastItem = i-1;
				    }
				    pItem.style.display = 'none';
				}
				else  {
				    totalHeight += this.itemHeight;
				}
			}


		}

		if (res.numResults) {
			numResultDiv = document.getElementById('iscopeAutoCompleteNumResults');
			if (numResultDiv) {
				this.resultDiv.removeChild(numResultDiv);
			}

			numResultDiv = document.createElement('div');
			numResultDiv.setAttribute('id','iscopeAutoCompleteNumResults',0);
			numResultDiv.style.textAlign = 'center';
			numResultDiv.style.paddingTop = '6px';
			numResultDiv.className = 'numResults';
			numResultDiv.style.height = this.itemHeight;
			numResultDiv.innerHTML = res.numResults;
			
      
		    totalHeight += this.itemHeight;
			this.resultDiv.appendChild(numResultDiv);

		    totalHeight += this.itemHeight;
			this.resultDiv.appendChild(numResultDiv);
		}

		if (i>this.maxItems) {
    		var naviDiv = document.getElementById('iscopeAutoCompleteNaviUp');
    		if (!naviDiv) {
    			naviDiv = document.createElement('div');
    			var img = document.createElement('img');
    			img.src = this.imagePath+'up_inactive.'+this.imageExt;
    			if (img.addEventListener) {
    		          img.addEventListener('mouseover',this.naviUp,false);
    		          img.addEventListener('mouseout',this.naviUpOut,false);
    		     }
    		     else {
    		          img.attachEvent("onmouseover", this.naviUp);
    		          img.attachEvent('onmouseout',this.naviUpOut);
    		      }

    			naviDiv.style.textAlign = 'center';
    			naviDiv.className = 'navi';
    			naviDiv.setAttribute('id','iscopeAutoCompleteNaviUp',0);
    			naviDiv.appendChild(img);
    			pItem0 = this.resultDiv.getElementsByTagName('p');
    			if (pItem0) pItem0 = pItem0[0];
    			if (pItem0) {
    			     this.resultDiv.insertBefore(naviDiv,pItem0);
    			     totalHeight += this.naviHeight;
    			}
    		}
    		else {
    		    if (this.index-this.maxItems>0) {
    		         naviDiv.getElementsByTagName('img')[0].src = this.imagePath+'up_active.'+this.imageExt;
    		    }
    		    else {
    		         naviDiv.getElementsByTagName('img')[0].src = this.imagePath+'up_inactive.'+this.imageExt;
    		    }
    		    naviDiv.style.display = 'block';
    		    totalHeight += this.naviHeight;
    		}


    		naviDiv = document.getElementById('iscopeAutoCompleteNaviDown');
    		if (!naviDiv) {
    			naviDiv = document.createElement('div');
    			img = document.createElement('img');

    			if (i>=this.maxItems) {
    			     img.src = this.imagePath+'down_active.'+this.imageExt;
    			}
    			else {
    			     img.src = this.imagePath+'down_inactive.'+this.imageExt;
    			}
    			if (img.addEventListener) {
        	         img.addEventListener('mouseover',this.naviDown,false);
        	         img.addEventListener('mouseout',this.naviDownOut,false);
        	    }
        	    else {
        	         img.attachEvent("onmouseover", this.naviDown);
        	         img.attachEvent('onmouseout',this.naviDownOut);
        	    }

    			naviDiv.style.textAlign = 'center';
    			naviDiv.className = 'navi';
    			naviDiv.setAttribute('id','iscopeAutoCompleteNaviDown',0);



    			naviDiv.appendChild(img);
    			this.resultDiv.insertBefore(naviDiv,numResultDiv);
    			totalHeight += this.naviHeight;
    		}
    		else {
    		    var img = naviDiv.getElementsByTagName('img')[0];
    		    if (i>=this.maxItems) {
        	         img.src = this.imagePath+'down_active.'+this.imageExt;

    		    }
    		    else {
    		         img.src = this.imagePath+'down_inactive.'+this.imageExt;

    		    }
    		    //this.resultDiv.removeChild(naviDiv);
    		    this.resultDiv.insertBefore(naviDiv,numResultDiv);
    		    naviDiv.style.display = 'block';
    		    totalHeight += this.naviHeight;
    		}
    	}
    	else {
    	   var naviDiv = document.getElementById('iscopeAutoCompleteNaviUp');
    	   if (naviDiv) {
    	       naviDiv.style.display = 'none';
    	   }
    	   naviDiv = document.getElementById('iscopeAutoCompleteNaviDown');
    	   if (naviDiv) {
    	       naviDiv.style.display = 'none';
    	   }
    	}

		if (0<numItems) {
			if ('none'==this.resultDiv.style.display) {
				this.fadeIn();
				this.resultDiv.style.display = 'block';
			}
		}
		else {
			if ('block'==this.resultDiv.style.display) {
				this.fadeOut();
			}
		}
		this.iframe.style.height    = totalHeight+'px';
	    this.iframe.style.display   = 'block';
	    if (this.id.attachListener) {
		  this.resultDiv.style.height = totalHeight+'px';
		  this.resultDiv.parentNode.style.height = totalHeight+'px';
	   }
	   
	   self=this;
	   this.destroyTimer = window.setTimeout(function () {self.fadeOut();}, 4000); // Selbstzerstoerung einleiten
	}
}
