// $Id: autosuggest.js,v1.0.9 - 2011/08/25 16:00:00 JCockayne $
function Autosuggest(oParms){
 this.textBox=oParms.textBox;
 if(oParms.oDDLParentNode)
  this.ddlParentNode=oParms.oDDLParentNode;
 this.minLength=oParms.minLength>-1?oParms.minLength:2;
 this.multiWord=oParms.multiWord;
 this.inLine=oParms.inLine==null?true:oParms.inLine;
 this.hideResults=oParms.hideResults==null?true:oParms.hideResults;
 this.useImages=oParms.useImages;
 this.imageMargin=oParms.imageMargin==null?true:oParms.imageMargin;
 this.alwaysRequest=oParms.alwaysRequest==true;
 this.timeout=oParms.timeout>0?oParms.timeout:900;
 this.ddlHeight=oParms.ddlHeight>0?oParms.ddlHeight:100;
 this.ddlWidth=oParms.ddlWidth;
 
 this.lastTextBoxValue="";
 this.hTimeout=0;
 this.init();
}
Autosuggest.prototype.asyncReceive=function(sSrc,oResponse){
 var l,l2;
 if(this.onasyncreceive)
  this.onasyncreceive(oResponse);
 if(!sSrc.length)return;
 var textBox=this.textBox;
 var textBoxValue=textBox.value;
 if(!oResponse.document)return;
 if(this.iframe.readyState){
  if(this.iframe.readyState!="complete")
	 return;
 }
 try{
  oResponse=oResponse.document.body.firstChild.nodeValue;
 }catch(l){return;}
 //Kludge to prevent unnecessary reload of same data
 if(oResponse==this.oldResponse)return;
 this.oldResponse=oResponse;
 //
 if(!oResponse){
  this.showDDL(false);
  return;
 }
 oResponse=oResponse.split("~");
 if(this.multiWord){	
	l=textBoxValue.length;
  l2=(textBoxValue.lastIndexOf(" ")+1);	
	if(textBoxValue.substring(l2,l)!=unescape(getQueryStrVal(sSrc,"query")))return;
	this.showDDL(true,oResponse);
	this.selectDDLItem();
 }else{
  if(textBoxValue!=unescape(getQueryStrVal(sSrc,"query")))return;
	this.showDDL(true,oResponse);
	this.selectDDLItem();
 }
};
Autosuggest.prototype.asyncRequest=function(bGetAll){
 clearTimeout(this.hTimeout);
 var sSrc;
 if(!bGetAll&&!this.textBox.value.length)return;
 var sQuery=bGetAll?"":this.textBox.value;
 if(this.multiWord){
  var l=(sQuery.lastIndexOf(" ")+1);
	var sQueryLeft=sQuery.substring(0,l);
  sQuery=sQuery.substring(l);
 }
 sSrc="?async=autosug&query="+escape(sQuery);
 if(this.multiWord)
	sSrc+="&left="+escape(sQueryLeft);
 if(this.onasyncrequest){
  var s=this.onasyncrequest(sSrc);
  if(s)sSrc=s;
 }
 var oThis=this;
 oThis.hTimeout=setTimeout(function(){oThis.iframe.src=sSrc;},(bGetAll?1:oThis.timeout));
};
Autosuggest.prototype.blur=function(bForce){
 if(!this.textBox.gotFocus||bForce){
   this.showDDL(false);
	 if(this.onblur)
	  this.onblur();
	}
};
Autosuggest.prototype.focus=function(){
 this.textBox.focus();
 this.textBox.gotFocus=true;
};
Autosuggest.prototype.getItemPageHeight=function(){
 var ddlHeight=this.ddlHeight;
 var trs=this.ddl.getElementsByTagName("tr");
 var firstItemY=this.ddl.scrollTop;
 var itemPageHeight=0;
 var offsetTop=0;
 for(var i=0;i<trs.length;i++){
  offsetTop=trs[i].offsetTop;
	if(offsetTop>=firstItemY){
   if(offsetTop-firstItemY<ddlHeight)
    itemPageHeight++;
   else
	  break;
  }
 }
 return itemPageHeight;
};
Autosuggest.prototype._getOffset=function(e,o,p){
 if(!e)return;
 if(p)
  if(e==p)return;
 o["x"]+=e.offsetLeft;
 o["y"]+=e.offsetTop;
 o=this._getOffset(e.offsetParent,o,p);
};
Autosuggest.prototype.getOffset=function(e,p){
 var o=new Array();
 o["x"]=0;
 o["y"]=0;
 this._getOffset(e,o,p);
 return o;
};
Autosuggest.prototype.handleKeyUp=function(oEvent){
 var k=oEvent.keyCode;
 var t=this.textBox.value.length;
 if(k<32||(k>=33&&k<=46)||(k>=112&&k<=123)) {
  if(k==8||k==46){
	 this.lastTextBoxValue=this.textBox.value;
	 if(t==0||t<this.minLength){
	  clearTimeout(this.hTimeout);
		this.asyncReceive("");
	  this.showDDL(false,"");
	 }else{
    if(this.inLine){
		 this.showDDL(false);
		}else{
     if(!this.selectDDLItem())this.showDDL(false);
     if(this.alwaysRequest)this.asyncRequest();
    }
   }
	}else
  if(k==9){
	 if(this.inLine)
    this.selectRange(t,t);
	 else
	  this.selectDDLItem(this.ddl.selRowId);
   this.showDDL(false);
   oEvent.cancelBubble=true;
   return false;
  }else
  if(k==33||k==34||k==38||k==40){
   if(this.ddl.style.display!="none"){
		if(k==38){
     this.selAdvance(-1);
		}else
	  if(k==40){
		 this.selAdvance(1);
		}else
	  if(k==33){
		 this.selAdvance(-this.getItemPageHeight());
		}else
	  if(k==34){
		 this.selAdvance(this.getItemPageHeight());
		}
    this.showDDL(true);
	  this.selectDDLItem(this.ddl.selRowId);
   }else{
	  if(k==40){
		 if(!t&&!this.minLength)
		  this.asyncRequest(true);
     else
      this.showDDL(true);
		}
   }
  }else
  if(k==13||k==27){
	 clearTimeout(this.hTimeout);
	 this.showDDL(false);
  }
 }else{
  this.lastTextBoxValue=this.textBox.value;
  if(t>=this.minLength){
//   if(this.selectDDLItem()&&!this.alwaysRequest)
	 var x=this.selectDDLItem();
	 if(x)
	  this.showDDL(true);
   if(!x||this.alwaysRequest)
    this.asyncRequest();
	}else{
	 this.showDDL(false,"");
	}
 }
};
Autosuggest.prototype.lostFocus=function(){
 this.textBox.gotFocus=false;
 var oThis=this;
 oThis.hTimeout=setTimeout(function(){oThis.blur();},350);
};
Autosuggest.prototype.selAdvance=function(iRows){
 var ddl=this.ddl;
 var trs=ddl.getElementsByTagName("tr");
 var iRow=ddl.selRowId;
 var iMax=trs.length-1;

 if(isNaN(iRow))iRow=-1;
 if(iRow+iRows>iMax){
  if(this.hideResults){
	 iRow=iMax+1;
	 iRows=-1;
	}else{
   iRows=iMax-iRow;
  }
 }else
 if(iRow+iRows<0){
  if(iRows=-1&&iRow<1){
   this.textBox.value=this.lastTextBoxValue;
	 ddl.selRowId=-1;
	 return;
  }else{
   if(this.hideResults){
    iRow=-1;
	  iRows=1;
	 }else{
	  iRows=-iRow;
	 }
  }
 }
 iRow=iRow+iRows;
  
 try{
	while(trs[iRow].style.display=="none"&&iRows!=0){
	 if(iRow+iRows>iMax)return;
	 if(iRow+iRows<0){
	  this.textBox.value=this.lastTextBoxValue;
		iRow=-1
		break;
   }
   iRow=iRow+iRows;
	}
 }catch(e){return;};

 ddl.selRowId=iRow;
};
Autosuggest.prototype.selectDDLItem=function(iRow,bChoose){
 var ddl=this.ddl;
 if(!ddl)return;
 var ddlHeight=this.ddlHeight;
 var ddlTextWidth=ddl.textWidth;
 var bFound=false;
 var hideResults=this.hideResults;
 var inLine=this.inLine;
 var textBox=this.textBox;
 var textBoxValue=textBox.value;
 var tva;
 var trs=ddl.getElementsByTagName("tr");
 var trsLength=trs.length;
 var qb;
 var qn=0;
 var qv="";
 var textBoxValueLength=(iRow)?0:textBoxValue.length;
 var useImages=this.useImages;

 if(isNaN(iRow)){
  ddl.selRowId=-1;
 }else{
  ddl.selRowId=iRow;
 }

 if(!inLine)
  tva=textBoxValue.replace(/\s{2,}/g," ").replace(/^\s+|\s+$/g,"").split(" ");

 for(var i=0;i<trsLength;i++){
  trs[i].className="DDListItem";

  qe=trs[i].childNodes[useImages?1:0];
  if(!qe){
	 this.showDDL(false,"");
	 return;
	}

	qe.className="DDListItem";
  qv=trs[i].text;

  if(inLine){
	 qb=qv.search(new RegExp(textBoxValue,"i"))==0;
   
	 qe.innerHTML=qv.replace(/\^/g,"");

	 if(!bFound)bFound=qb;
	 if(qb){
		trs[i].style.display="";
   }else{
		if(hideResults&&isNaN(iRow)){
		 trs[i].style.display="none";
		 qn++;
		}
   }
  }else{
   if(isNaN(iRow)){	 
    for(var i2=0;i2<tva.length;i2++){
     qb=qv.match(new RegExp(tva[i2],"gi"));
     if(qb){
		  bFound=true;
			for(var i3=0;i3<qb.length;i3++){
			 if(!(qb[i3].length==1&&qb[i3].match(new RegExp("(<|/|>)","g"))))
        qv=qv.replace(new RegExp("(?!&)"+qb[i3]+"(?!>)",""),qb[i3].bold());
      }
     }
    }

    qe.innerHTML=qv.replace(/\^/g,"");

	  if(qb){
		 trs[i].style.display="";
		}else{
		 if(hideResults){
		  trs[i].style.display="none";
		  qn++;
		 }
		}
		if(qn&&qn==trsLength)
		 bFound=false;
	 }
  }
	if(ddl.selRowId==-1||!isNaN(iRow)){
   if((!isNaN(iRow)&&iRow==i)||(isNaN(iRow)&&bFound&&inLine)){
    ddl.selRowId=i;
	  trs[i].className="DDListItem Selected";
		qe.className="DDListItem Selected";
    ddl.scrollTop=trs[i].offsetTop-((ddl.offsetHeight-trs[i].offsetHeight)/2);
    if(inLine||!isNaN(iRow)){
		 qv=trs[i].text;
		 i2=qv.indexOf("^");
		 if(i2==-1)i2=qv.length;
		 textBox.value=qv.substring(0,i2);//.entityDecode();
		 if(inLine)
		  this.selectRange(textBoxValueLength,qv.length);
		}
	 }
  }
 }

 if(hideResults&&isNaN(iRow)){
  ddl.style.display=qn==trsLength?"none":"";
  ddl.style.height="";
  ddl.style.height=(ddl.offsetHeight<ddlHeight)?"":ddlHeight+"px";
 }

 if(this.onselectddlitem)
  this.onselectddlitem(textBox,bChoose);
 return bFound;
};
Autosuggest.prototype.selectRange=function(iStart,iEnd){
 var textBox=this.textBox;
 try{
  if(textBox.createTextRange){
   var r=textBox.createTextRange();
	 r.moveStart("character",iStart);
	 r.moveEnd("character",iEnd-textBox.value.length);
	 r.select();
  }else if(textBox.setSelectionRange){
   textBox.setSelectionRange(iStart,iEnd); 
  }
 }catch(x){};
};
Autosuggest.prototype.showDDL=function(s,h){
 var ddl=this.ddl;
 var trs;
 var textBox=this.textBox;
 var inLine=this.inLine;
 var textBoxValue=this.textBox.value
 var useImages=this.useImages;
 var op;
 var ot=0;
 var t;
 if(this.ddlParentNode)
  op=this.ddlParentNode;
 if(useImages&&this.imageMargin&&!this.imageSize){
  var e=document.createElement("div");
  e.className="DDListImg";
	e.style.overflow="scroll";
	e.style.display="";
	e.style.visibility="visible";
  e=document.body.appendChild(e);
  this.imageSize=e.offsetWidth;
  e.parentNode.removeChild(e);
 }

 if(!s){
	ddl.style.display="none";
	if(h==""){
	 ddl.innerHTML="";
	 this.oldResponse="";
	 return;
	}
	trs=ddl.getElementsByTagName("tr");
	for(var i=0;i<trs.length;i++){
	 if(i!=ddl.selRowId)
    trs[i].className="DDListItem";
	}
	return;
 }else{
  trs=ddl.getElementsByTagName("tr")
  if(!h){
	 if(trs.length)
	  ddl.style.display="";
	 return;
	}

	var lh=(useImages&&this.imageMargin)?(" style=\"height:"+this.imageSize+"px\""):"";
	var l="";
	var l1="";
  var p1;
  t=(this.multiWord)?textBoxValue.substring(0,textBoxValue.lastIndexOf(" ")+1):"";
	ddl.selRowId=0;
  if(h.length==1&&h[0].length==0){
	 ddl.style.display="none";
	 return;
	}
	for(var i=0;i<h.length;i++){
	 p1=h[i].indexOf("|");
	 if(p1>-1){
	  l1=h[i].substring(0,p1);
		h[i]=h[i].substring(p1+1);
    if(useImages)
		 l1="<td><img src=\""+l1+"\" class=\"DDListImg\" \/><\/td>";
		else
		 l1="";
	 }
	 l+="<tr"+lh+" class=\"DDListItem\">"+l1+"<td>";
   if(inLine)l+=t+h[i];
   l+="<\/td><\/tr>";
	}
  if(!this.ddlParentNode){
	 var o=this.getOffset(textBox);
  }else{
	 var o=this.getOffset(textBox,op);
  }
  //Yet another bizarre workaround for MSIE...
	try{ot=getParent(textBox,"A").offsetLeft-op.getElementsByTagName("a")[0].offsetLeft;}catch(i){};
	//
	if(isNaN(ot))ot=0;
	if(useImages&&this.imageMargin)ot+=this.imageSize;
  ddl.style.left=(o["x"]-ot)+"px";
  ddl.style.top=o["y"]+textBox.offsetHeight+"px";
	ddl.style.height="";

  ddl.innerHTML="<table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\">"+l+"<\/table>";
	var oThis=this;
  trs=ddl.getElementsByTagName("tr");
  for(i=0;i<trs.length;i++){
	 trs[i].text=t+h[i];
   //mouseovers as JS instead of CSS for...you guessed it, MSIE(6)...
   trs[i].onmouseover=function(){
    this.className="Selected DDListItem";
    this.childNodes[oThis.useImages?1:0].className="Selected DDListItem";
   };
   trs[i].onmouseout=function(){
    this.className="DDListItem";
    this.childNodes[oThis.useImages?1:0].className="DDListItem";
   };
	 //
	 trs[i].i=i;
   trs[i].onmousedown=function(){
    oThis.selectDDLItem(this.i,true);
		oThis.blur(true);
	 };
	}
	
	//And another workaround for MSIE...
  t=ddl.style.overflow;
  ddl.style.overflow="scroll";
  ddl.style.width="";
	ddl.style.visibility="hidden";
	ddl.style.display="";
  ot=ddl.offsetWidth>ddl.clientWidth?ddl.offsetWidth-ddl.clientWidth+3:32;
  ddl.style.overflow=t;
  //

	ddl.style.display=h.length?"":"none";
	ddl.style.visibility="visible";
	
	ddl.style.height=(ddl.offsetHeight<this.ddlHeight&&ddl.offsetHeight>0)?"":this.ddlHeight+"px";
	if(this.ddlWidth!=undefined){
	 ddl.style.width=this.ddlWidth+(parseFloat(this.ddlWidth)>0&&this.ddlWidth.toString().indexOf("%")==-1?"px":"");
	 if(ddl.style.width=="")
	  ddl.style.width=ddl.offsetWidth+ot+"px";
   if(this.ddlParentNode){
    ot=op.offsetWidth>op.clientWidth?op.offsetWidth-op.clientWidth+3:32;
	  ot=ddl.offsetLeft+ddl.offsetWidth+ot-op.offsetWidth;
	 }
	 if(ot>0)ddl.style.width=ddl.offsetWidth-ot+"px";
	}else{
	 ddl.style.width=textBox.offsetWidth-3+(useImages&&this.imageMargin?this.imageSize:0)+"px";
	}

  ddl.textWidth=(ddl.offsetWidth-(ddl.offsetWidth-ddl.clientWidth+3)-(useImages?this.imageSize:0));

	if(this.onshowddl)
   this.onshowddl(ddl);
 }
};
Autosuggest.prototype.init=function(){
 var oThis=this;
 var textBoxId=oThis.textBox.id;
 //Another atrocious IE workaround...
 var oEl=document.getElementById("spnifrAsync_"+textBoxId);
 if(!oEl){
  oEl=document.createElement("span");
  oEl.setAttribute("id","spnifrAsync_"+textBoxId);
	oEl.style.display="none";
  oEl.innerHTML="<iframe name=\"ifrAsync_"+textBoxId+"\" id=\"ifrAsync_"+textBoxId+"\" onload=\"\" \/>";
  oEl=document.body.appendChild(oEl);
 }
 oThis.iframe=document.getElementById("ifrAsync_"+textBoxId);
 addEvent(oThis.iframe,"load",function(){
	oThis.asyncReceive(oThis.iframe.src,window.frames["ifrAsync_"+textBoxId]);
 });
 addEvent(oThis.textBox,"blur",function(){
  oThis.lostFocus();
 });
 addEvent(oThis.textBox,"focus",function(){
  oThis.focus();
 });
 //Necessary kludge for Tab key & forbidden keys
 addEvent(oThis.textBox,"keydown",function(oEvent){
  if(!oEvent)
   oEvent=window.event;
	if(oEvent.keyCode==9){
   oThis.handleKeyUp(oEvent);
  }else
  if(oEvent.keyCode==192||oEvent.keyCode==220){
   if(oEvent.preventDefault)
	  oEvent.preventDefault();
   oEvent.returnValue=false;
	 return false;
  }
 });
 addEvent(oThis.textBox,"keyup",function(oEvent){
  if(!oEvent)
   oEvent=window.event;
  oThis.handleKeyUp(oEvent);
 });
 oEl=document.createElement("div");
 oEl.setAttribute("id","div"+textBoxId+"DDL");
 oEl.className="DDListDiv";
 oEl.style.display="none";
 if(oThis.ddlParentNode)
	e=oThis.ddlParentNode.appendChild(oEl);
 else
	oEl=oThis.textBox.parentNode.appendChild(oEl);
 oThis.ddl=oEl;
 addEvent(oThis.ddl,"keyup",function(oEvent){
  if(!oEvent)
   oEvent=window.event;
  oThis.handleKeyUp(oEvent);
 });
 oThis.ddl.onselectstart=function(){return false;};
 oThis.ddl.onfocus=function(){oThis.textBox.gotFocus=true;};
 oThis.ddl.onblur=function(){oThis.lostFocus();};
 //oThis.focus();
};
String.prototype.entityDecode=function(){
 if(!this.length)return this;
 var t=document.createElement("div");
 t.innerHTML=this;
 return t.firstChild.nodeValue;
}
function addEvent(obj,eType,fn,useCapture){
 if(obj.addEventListener){
  obj.addEventListener(eType,fn,useCapture);
  return true;
 }else if (obj.attachEvent){
  return obj.attachEvent("on"+eType,fn);
 }
}
function getParent(e,n){
 var d=e.parentNode;
 if(!d)return false;
 try{
 while(d.nodeName!=n){
  d=d.parentNode;
	if(!d)return false;
 }
 return d;
 }catch(e){}
}
function getQueryStrVal(q,v){
 var p=q.indexOf(v+"=");
 if(p==-1)return false;
 p+=v.length+1;
 var t=q.substring(p);
 p=t.indexOf("&");
 if(p==-1)p=t.indexOf("#");
 if(p==-1)p=t.length;
 return t.substring(0,p); 
}
