function Suggest(el, url, target)
{
  if (!el.hasSuggest)
  {
    el.hasSuggest = true;
    this.el = el;
    this.url = url;
    this.target = target;
    this.init();
  }
}
Suggest.prototype =
{
  init: function()
  {
    Spif.DOMEvents.attach(this.el,     "keyup",   this.onKeyUp,        this);
    Spif.DOMEvents.attach(this.el,     "keydown", this.onKeyDown,      this);
    Spif.DOMEvents.attach(this.el,     "blur",    this.closeSg,        this);
    Spif.DOMEvents.attach(this.target, "click",   this.onClickSuggest, this);
  },
  xhr: function()
  {
    return window.XMLHttpRequest? new XMLHttpRequest : new ActiveXObject("Microsoft.XmlHttp");
  },
  onKeyUp: function(evt)
  {
    var keyCode = evt.keyCode;
    if (keyCode == 32 || keyCode == 8 || (keyCode >= 48 && keyCode <= 92))
      return this.getSuggestions();
  },
  onKeyDown: function(evt)
  {
    var cancel = false;

    switch (evt.keyCode)
    {
      case 13: if (this.chooseSg()) break;
      case 27: return this.closeSg();
      case 38: this.prevSg(); break;
      case 40: this.nextSg(); break;
      default: 
        if (!cancel)
          return;
    }
    evt.cancel();
  },
  onClickSuggest: function(evt)
  {
    var sugIdx = parseInt(evt.subject.getAttribute("idx"));
    if (!isNaN(sugIdx))
    {
      this.selectSg(sugIdx);
      this.chooseSg();
    }
  },

  sgs : [],
  getSuggestions: function()
  {
    var v = this.el.value.replace(/[^\w-+ ]/gi, "");
    var curTag = v.replace(/^(\w+ )*(\w+)$/gi, "$2");
    if (curTag.length > 0)
    {
      var xhr = this.xhr();
      var curSg = this.curSg(true);
      curSg = (curSg == -1)? "" : "cur=" + curSg + "&";
      xhr.open("GET", this.url + curTag + "?" + curSg + new Date(), true);
      var me = this;
      xhr.onreadystatechange = function()
      {
        if (xhr.readyState == 4)
          me.suggest(xhr.responseText);
      }
      return xhr.send(null);
    }
    this.closeSg();    
  },
  suggest: function(xhtml)
  {
    if (xhtml.search("suggest") > -1)
    {
      this.target.innerHTML = "";
      var el = document.createElement("div");
      el.innerHTML = xhtml;
      while (el.firstChild)
        this.target.appendChild(el.firstChild);
      this.sgs = this.target.firstChild.getElementsByTagName("div");
    }
  },
  curSg: function(asText)
  {
    for (var i=0,l=this.sgs.length; i<l;i++)
      if (this.sgs[i].className.search("selected") > -1)
        return asText? this.sgs[i].id.substr(3) : i;
    return -1;
  },
  prevSg: function()
  {
    var i = this.curSg() - 1;
    if (i < 0)
      i = this.sgs.length - 1;
    this.selectSg(i);
  },  
  nextSg: function()
  {
    var i = (this.curSg() + 1) % this.sgs.length;
    this.selectSg(i);
  },
  selectSg: function(j)
  {
    for (var i=0,l=this.sgs.length; i<l;i++)
      this.sgs[i].className = "sug" + ((i==j)? " sug-selected" : "");
  },
  chooseSg: function()
  {
    var curSg = this.curSg(true);
    if (curSg != -1)
      this.el.value = this.el.value.replace(/^((\w+ )*)(\w+)$/gi, "$1" + curSg);
    
    this.closeSg();
    return (curSg != -1);
  },
  closeSg: function()
  {
    var me = this;
    setTimeout(function()
    {
      me.target.innerHTML = "";
      me.sgs = [];
    }, 100);
  }  
};
