var Suggestions = {
  _searchElem: null,
  _suggestBox: null,
  _suggestUrl: undefined,
  _selectFunc: undefined,
  _absolute: false,
  _currentSel: null,
  _prefix: '',
  _oldPrefix: '',
  _timerId: undefined,
  
  init: function(searchElemId, maxSuggestions, suggestUrl, selectFunc, absolute) {
     this._searchElem = document.getElementById(searchElemId);
     if (this._searchElem == null) return;
     if (arguments.length > 4)
        this._absolute = absolute;
     this._getBox(searchElemId, maxSuggestions);
     this._suggestUrl = suggestUrl;
     this._selectFunc = selectFunc;
  },
  
  _getBox: function(searchElemId, maxSuggestions) {
     var boxId = searchElemId + "_box";
     var box = document.getElementById(boxId);
     if (box == null) {
        box = document.createElement("div");
        box.id = boxId;
     }
     box.className = "suggestions";
     box.style.display = 'none';
     box.style.zIndex = 200;
     if (this._absolute) {
        box.style.position = "absolute";
        document.body.appendChild(box);
     }
     else {
        var parent = this._searchElem.parentNode;
        parent.insertBefore(box, this._searchElem.nextSibling);
        box.style.position = "relative";
     }
     
     this._suggestBox = box;
     this._initEvents();
  },

  _positionBox: function() {
     var buddy = this._searchElem;
     var box = this._suggestBox;
     if (this._absolute) {
        box.style.left = rol.leftOffset(buddy) + 'px';
        box.style.top = rol.topOffset(buddy) + buddy.offsetHeight + 'px';
     }
     else {
        box.style.left = 0;
        box.style.top = "-1px";
     }
     box.style.width = buddy.clientWidth + 'px';
     box.style.height = "auto";
  },
  
  _initEvents: function() {
     this._suggestBox.onmouseover = rol.createDelegate(this, this.onSuggestionHighlighted);
     this._suggestBox.onmousedown = rol.createDelegate(this, this.onSuggestionClicked);
     var buddy = this._searchElem;
     var _this = this;
     buddy.onkeydown = this._filterKeys;
     rol.addEventHandler(buddy, 'keyup', rol.createDelegate(this, this._getSuggestions), false);
     rol.addEventHandler(buddy, 'blur',
       function() {
         _this._suggestBox.style.display = 'none';
       }, false
     );
  },
  
  _filterKeys: function(evt) {
    var e = rol.getEvent(evt);
    var k = e.keyCode;
    return !(k == 13 || k == 27);
  },

  _getSuggestions: function getNames(evt)
  {
    this._cancelGet();
    var e = rol.getEvent(evt);
    var k = e.keyCode;
    if (k == 38)
       this.moveUp();
    else if (k == 40)
       this.moveDown();
    else if (k == 13) // Enter
       this._selectSuggestion();
    else if (k == 27) { // Esc
        this._searchElem.value = this._prefix;
        this._suggestBox.style.display = 'none';
    }
    else {
       this._prefix = this._searchElem.value;
       if (this._prefix.length > 0) {
          this._delayedGet();
       }
       else {
          this._suggestBox.style.display = 'none';
          this._reset();
       }
    }
  },
  
  onSuggestionsLoaded: function(json, headers, divId)
  {
    this._timerId = undefined;
    var target = document.getElementById(divId);
    if (target != null) {
       this._reset();
       if (json.length > 0) {
          var results = eval(json);
          for (var i=0; i < results.length; ++i) {
             var p = document.createElement("p");
             p.innerHTML = results[i];
             target.appendChild(p);
          }
          this._positionBox();
          target.style.display = 'block';
       }
       else
          target.style.display = 'none';
    }
  },
  
  onSuggestionHighlighted: function(evt) {
    var e = rol.getEvent(evt);
    var reltg = e.target || e.srcElement;
    if (reltg == null || reltg.tagName != "P") return;

    this.move(function() { return reltg; });
  },
  
  onSuggestionClicked: function(evt) {
    this._selectSuggestion();
  },

  _selectSuggestion: function() {
       this._suggestBox.style.display = 'none';
       if (this._selectFunc != undefined)
          this._selectFunc(this._searchElem.value);
  },
  
  moveUp: function() {
    this.move(rol.createDelegate(this,
        function() {
          if (this._currentSel == null) return this._suggestBox.lastChild;
          if (this._currentSel.previousSibling == null) {
             this._searchElem.value = this._prefix;
             return this._currentSel = null;
          }
          return this._currentSel.previousSibling;
        }
    ));
  },

  moveDown: function() {
    this.move(rol.createDelegate(this,
        function() {
          if (this._currentSel == null) return this._suggestBox.firstChild;
          if (this._currentSel.nextSibling == null) {
             this._searchElem.value = this._prefix;
             return this._currentSel = null;
          }
          return this._currentSel.nextSibling;
        }
    ));
  },
  
  move: function(traverser) {
    var box = this._suggestBox;
    if (box.childNodes.length == 0)
       return;

    if (this._suggestBox.style.display == 'none') {
       this._suggestBox.style.display = 'block';
       return;
    }
    
    if (this._currentSel != null)
       this._currentSel.className = "notactive";

    if ( (this._currentSel = traverser()) != null) {
       this._currentSel.className = "active";
       this._searchElem.value = this._currentSel.innerHTML;
    }
    else {
       this._searchElem.value = this._prefix;
    }
    this._suggestBox.style.display = 'block';
  },

  _reset: function() {
    rol.removeAllChildren(this._suggestBox);
    this._oldPrefix = '';
    this._currentSel = null;
  },
  
  _delayedGet: function() {
     var _this = this;
     this._timerId = window.setTimeout(
       function() {
         var prefix = _this._searchElem.value;
         if (_this._oldPrefix != prefix) {
            _this._oldPrefix = prefix;
               ajaxCaller.get(_this._suggestUrl, {prefix: encodeURIComponent(prefix)},
                      rol.createDelegate(_this, _this.onSuggestionsLoaded), false, _this._suggestBox.id, false);
         }
       }, 300);
  },
  
  _cancelGet: function() {
     if (this._timerId != undefined) {
        window.clearTimeout(this._timerId);
        this._timerId = undefined;
   }
  }
}

