var nCombos=-1
var Combos=[]
var keyCode=''
var ev
var TAB   =9
var ENTER =13
var CTimeout=null

String.prototype.trim = function() {return this.replace(/(^\s*)|(\s*$)/g, "")}  //needed in case AJAX.js isn't loaded

function ComboOpen(){
  for(var i=0;i<=nCombos;i++) if(Combos[i] && Combos[i].div.style.display=='block') return true
  return false
}

function ComboGarbageCollection() {
  try{
    for(var i=0;i<nCombos;i++) {
      if(Combos[i] && !Combos[i].id.parentNode) {
        Combos[i].div.removeNode(true)
        for(var z in Combos[i]) Combos[i][z]=null
        Combos[i]=null
      }
    }
  }catch(ee){}
} //ComboGarbageCollection

function Combo(obj,arr,func,atend) {
  ComboGarbageCollection()
  nCombos++
  Combos[nCombos]={}
  var c=Combos[nCombos]
  c.id=obj
  c.holdvalue=obj.value
  obj.nCombo=nCombos

  obj.onkeyup  =ComboKU
  obj.onkeydown=ComboKD
  obj.onfocus  =ComboFocus
  obj.onblur   =ComboBlur

  obj.onclick=function(){this.select()}

  c.div=document.body.appendChild(document.createElement('DIV'))
  c.div.style.cssText='border:1px solid gray;display:none;position:absolute;font-size:8pt;background:lightyellow;cursor:pointer;z-Index:1000'

  c.div.obj=obj
  c.div.onclick=function(){var rec=Combos[this.obj.nCombo]; ComboUpdate(rec); ComboWrapUp(rec)}

  c.div.onmouseover=ComboMOver
  c.div.mouseover=null
  c.div.onmouseout=ComboMOut
  c.y=0

  c.N=arr
  c.ndNames=0
  c.dNames=[]
  c.ind=[]
  c.func=func
  c.match=true
  c.endfunc=null
  c.atend=atend
  obj.combo=c
  return c
} //Combo

function ComboFocus(ev){
  if(CTimeout) clearTimeout(CTimeout)
  else {
    var rec=Combos[this.nCombo];
    rec.match=false;
    rec.orgvalue=rec.id.value;
  }
} //ComboFocus

function ComboBlur(ev){
  curcombo=this.nCombo
  CTimeout=setTimeout(function(){
                        var rec=Combos[curcombo]
                        if(rec.div.style.display=='block') {ComboUpdate(rec,1); ComboWrapUp(rec)}
                        else if(!rec.match && rec.orgvalue!=rec.id.value) rec.id.value=''
                      }
                      ,500
                     )
} //ComboBlur

function ComboMOver(ev) {
  ev=ev || window.event;  var e=ev.srcElement?ev.srcElement:ev.target
  var he=e
  var rec=Combos[this.obj.nCombo]

  while(e.className!='CCC' && e.parentNode) e=e.parentNode
  if(e.className!='CCC') return

  rec.y=rec.start+e.offsetTop/e.offsetHeight-1

  this.holdstyle=he.style.backgroundColor
  he.style.backgroundColor='lightblue'
  if(rec.div.mouseover) rec.div.mouseover(rec.ind[rec.y])
} //ComboMOver

function ComboMOut(ev) {
  ev=ev || window.event; var e=ev.srcElement?ev.srcElement:ev.target
  var he=e

  while(e.className!='CCC' && e.parentNode) e=e.parentNode
  if(e.className!='CCC') return
  he.style.background=this.holdstyle
} //ComboMout

function ComboWrapUp(rec) {
  rec.div.style.display='none'
  rec.holdvalue=''
  if(!rec.match) rec.id.value=''
  if(rec.id.value=='') return
  if(rec.orgvalue==rec.id.value) return

  rec.y=(rec.y).toFixed(0)

  if(rec.ind.length!=0) {
    if(rec.N instanceof Array) rec.id.value=rec.N[rec.ind[rec.y]+1]
    else                       rec.id.value=rec.N.a[rec.ind[rec.y]+1]
  }

//  if(rec.func && rec.atend && rec.ind[rec.y]>=0) rec.func(rec.ind[rec.y])
  if(rec.func && rec.atend) rec.func(rec.ind[rec.y])
  if(rec.endfunc           && rec.ind[rec.y]>=0) rec.endfunc(rec.ind[rec.y])
  rec.ndNames=rec.start=rec.y=0
  rec.match=false
  rec.orgvalue=rec.id.value

  var p=rec.id.value.indexOf('<span'); if(p>-1) rec.id.value=rec.id.value.substr(0,p)
} //ComboWrapUp

function ComboUpdate(rec,f) {
  try {
    if(!f) rec.id.focus()
    if(rec.func && !rec.atend && rec.ind[rec.y]>=0) rec.func(rec.ind[rec.y])
  } catch(ee) {rec.id.value=''}
}

function CloseCombosExcept(n) {
  for(var i=0;i<=nCombos;i++) if(i!=n) try{Combos[i].div.style.display='none'}catch(ee){}
}

function ScrollTop(obj) {
  if(window.Node) return 0 //doesn't work in FireFox
  else return obj.scrollTop
}

function ComboKD(e) {
  if(!e) ev=window.event
  else ev=e
  if(ev.keyCode)    keyCode=ev.keyCode
  else if(ev.which) keyCode=ev.which
  else keyCode=e
  scroll(this.nCombo)
} //ComboKD

function Cposition(id) {
  var offsetLeft= 0
  var offsetTop= 0
  while(id) {
    offsetLeft+= id.offsetLeft+id.clientLeft
    offsetTop+= (id.offsetTop+id.clientTop)-(id.offsetParent?ScrollTop(id):0)
    id= id.offsetParent
  }
  return {left:offsetLeft,top:offsetTop}
} //Cposition

function ComboKU() {
  if(keyCode==ENTER || keyCode==TAB) return
  var n=this.nCombo
  ShowCombo(n)
} //ComboKU

function ShowCombo(n){
  if(typeof n=='string') {
    Combos[$(n).nCombo].match=false
    Combos[$(n).nCombo].orgvalue=rndtime()
    Combos[$(n).nCombo].holdvalue=rndtime()
    $(n).value=' '
    n=$(n).nCombo
    Combos[n].match=false
    keyCode=32
  }

  CloseCombosExcept(n)

  var rec=Combos[n]

  if(rec.id.value=='') ComboWrapUp(rec)

  if(rec.holdvalue==rec.id.value) return
  rec.holdvalue=rec.id.value

  rec.div.style.width=(rec.id.clientWidth*1+1)+'px'
  rec.div.style.left=(Cposition(rec.id).left-3)+'px'
  rec.div.style.top=(Cposition(rec.id).top+rec.id.offsetHeight-3)+'px'

  rec.div.style.display='block'

  var ip=' '+rec.id.value.trim()
  var len=ip.length
  rec.ndNames=0
  var p

  ip=ip.replace(/\\/g,'\\\\').replace(/\[/g,'\\[').replace(/\]/g,'\\]').replace(/\(/g,'\\(').replace(/\)/g,'\\)').replace(/\./g,'\\.')
  var t=new RegExp(ip)
  t.compile(ip,'i')

  rec.match=false
  if(rec.N instanceof Array) {
    for(var i=0;i<rec.N.length;i++) if(t.test(' '+rec.N[i])) {
      rec.match=true
      rec.ind[rec.ndNames]=i-1
      rec.dNames[rec.ndNames++]=rec.N[i]
    }
  }
  else {
    for(var i=0;i<rec.N.a.length;i++) if(t.test(' '+rec.N.a[i])) {
      rec.match=true
      rec.ind[rec.ndNames]=i-1
      rec.dNames[rec.ndNames++]=rec.N.a[i]
    }
  }

  if(!rec.match) rec.div.style.display='none'
  else if(rec.ndNames==1 && rec.id.value.trim()==rec.dNames[0]) ComboWrapUp(rec)
  else scroll(n,0)

  if(rec.func && !rec.atend && rec.ind[rec.y]>=0) rec.func(rec.ind[rec.y])
} //ShowCombo

function PageDown(n) {
  var rec=Combos[n]
  if(rec.y<rec.ndNames-1) {
    var sd=rec.y-rec.start
    rec.y+=10; if(rec.y>rec.ndNames-1) rec.y=rec.ndNames-1
    if(rec.y>rec.start+9) rec.start=rec.y-sd
    ComboUpdate(rec)
  }
} //PageDown

function PageUp(n) {
  var rec=Combos[n]
  if(rec.y>0) {
    var sd=rec.y-rec.start
    rec.y-=10; if(rec.y<0) rec.y=0
    if(rec.y<rec.start) rec.start=rec.y-sd; if(rec.start<0) rec.start=0
    ComboUpdate(rec)
  }
} //PageUp

function scroll(n,st) {
  var UP    =38
  var PGUP  =33
  var DOWN  =40
  var PGDN  =34
  var HOME  =36
  var END   =35
  var rec   =Combos[n]
  var kc    =keyCode
  if(rec.div.style.display=='block') {
    switch(kc) {
      case HOME :if(ev.ctrlKey) {
                   rec.start=rec.y=0
                   ComboUpdate(rec)
                 }
                 break
      case END  :if(ev.ctrlKey) {
                   rec.y=rec.ndNames-1
                   rec.start=rec.y-9; if(rec.start<0) rec.start=0
                   ComboUpdate(rec)
                 }
                 break
      case DOWN :if(rec.y<rec.ndNames-1) {
                   rec.y++
                   if(rec.y>rec.start+9) rec.start++
                   ComboUpdate(rec)
                 }
                 break
      case PGDN :PageDown(n)
                 break
      case UP   :if(rec.y>0) {
                   rec.y--
                   if(rec.y<rec.start) rec.start--
                   ComboUpdate(rec)
                 }
                 break
      case PGUP :PageUp(n)
                 break

    }
    doscroll(n,st)
  }

  switch(kc) {
    case ENTER:
    case TAB  :if(rec.match) {ComboUpdate(rec); ComboWrapUp(rec)}
               else if(rec.orgvalue!=rec.id.value) rec.id.value=''
  }
} //scroll

function doscroll(n,st) {
  var rec=Combos[n]
  if(st==0) {rec.start=rec.y=rec.hy=0; rec.hold=rec.dNames[0]}
  rec.dNames[rec.hy]=rec.hold
  rec.hold=rec.dNames[rec.y]; rec.hy=rec.y
  rec.dNames[rec.y]='<div style="background:navy;color:lightyellow">'+rec.dNames[rec.y]+'</div>'
  var sbg=rec.start==0?'color:lightyellow':'background:#dddddd;'
  var ebg=rec.start+10>=rec.ndNames?'color:lightyellow':'background:#dddddd;'
  s ='<pre style="text-align:center;font-family:verdana;color:green;margin:0;'+sbg+'" onmousedown="event.cancelBubble=true; PageUp('+n+');   doscroll('+n+'); Combos['+n+'].id.focus(); return false">«</pre>'
  s+='<pre class="CCC">'+rec.dNames.slice(rec.start,Math.min(rec.start+10,rec.ndNames)).join('</pre><pre class="CCC">')+'</pre>'
  s+='<pre style="text-align:center;font-family:verdana;color:green;margin:0;'+ebg+'" onmousedown="event.cancelBubble=true; PageDown('+n+'); doscroll('+n+'); Combos['+n+'].id.focus(); return false">»</pre>'
  s=s.replace(/&amp;/g,'&')
  rec.div.innerHTML=s
  rec.id.focus()
} //doscroll
