// Creates autocompletion handler.
// -----------------------------------------------------------------------------
// url        - url of the servlet responder.
// lookup     - <Bean name>.<method name> used to provide response.
// lookupsize - maximum size of the lookup list.
// actlength  - minimum length of the input box text to activate lookup.
// cliendId   - id of the whole client div element.
// zIndex     - z-index of the whole client div element.
// handlerName- name of the handler.
// -----------------------------------------------------------------------------
function newAutocompletionHandler(url, lookup, lookupsize, actlength, clientId, zIndex, handlerName) {
  // prepare vars
  var inputTextId        = clientId + "_input";
  var lookupDivId        = clientId + "_input_lookup";
  var lookupElementDivId = clientId + "_input_lookup_element_";

  // create handler object
  var handler = new Object();

  // mouse over the lookup indicator; indicates if a mouse is currenlty over the lookup component
  handler.mouseOver = false;

  // stored length of the lookup list
  handler.lookuplength = 0;

  // stored preselected by key item on the lookup list
  handler.preselected  = -1;

  // stored information about pressed ESC
  handler.escpressed   = false;

  // original text typed into the input box
  handler.orgtext = "";

  // text to update
  handler.newtext = "";

  // request to restore orgtext
  handler.updatetextrequest = false;

  // Creates instance of AJAX communication object.
  // ---------------------------------------------------------------------------
  handler.GetXMLHttpRequest = function() {
    var object = null;
    
    if (window.XMLHttpRequest) {
        object = new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        try {
            object = new ActiveXObject("Msxml2.XMLHTTP");
        } catch(e) {}
        
        if (object == null) {
            try {
                object = new ActiveXObject("Microsoft.XMLHTTP");
            } catch(e) {}
        }
    }
    
    if (object == null) {
        alert("Your browser does not support AJAX");
    }
    
    return object;
  };

  // Sends autocomplete request.
  // ---------------------------------------------------------------------------
  // url        - url of the servlet responder.
  // keystrokes - characters typed into the input box.
  // lookup     - <Bean name>.<method name> used to provide response.
  // ---------------------------------------------------------------------------
  handler.send = function(url, keystrokes, lookup) {
    var requestObject = this.GetXMLHttpRequest();

    requestObject.onreadystatechange = function() {
      if (requestObject.readyState == 4) {
          if (requestObject.status == 200) {
              var items  = new Object();
              if (requestObject.responseText) {
                items = requestObject.responseText.split("\r\n");
                for (i = 0; i<items.length && i<lookupsize; i++) {
                  items[i] = items[i].replace(/^\s+|\s+$/g,"");
                }
                while (items.length > lookupsize) {
                  items.pop();
                }
              }

              var clientDiv = document.getElementById(clientId);
              var lookupDiv = document.getElementById(lookupDivId);
              var inputText = document.getElementById(inputTextId);

              while (lookupDiv.firstChild) {
                lookupDiv.removeChild(lookupDiv.firstChild);
              }

              for (i = 0; i < items.length; i++) {
                var div = document.createElement('div');
                div.innerHTML = 
                  "<a id=\"" +(lookupElementDivId+i)+ "\" class=\"autocompletionPopupItem\" href=\"#\" onclick=\"" +handlerName+ ".onListClick('" +items[i]+ "')\">" +items[i]+ "</a>";
                lookupDiv.appendChild(div);
              }

              var winW, winH;
              if (self.innerHeight) {
                // all except Explorer
                winW = self.innerWidth;
                winH = self.innerHeight;
              }
              else if (document.documentElement && document.documentElement.clientHeight) {
                // Explorer 6 Strict Mode
                winW = document.documentElement.clientWidth;
                winH = document.documentElement.clientHeight;
              }
              else if (document.body) {
                // other Explorers
                winW = document.body.clientWidth;
                winH = document.body.clientHeight;
              }

              if (items.length>0) {
                clientDiv.style.zIndex = zIndex+1;
                if (handler.totalTopOffset(inputText) + inputText.offsetHeight + lookupDiv.offsetHeight <= winH) {
                  lookupDiv.style.top = (handler.totalTopOffset(inputText) + inputText.offsetHeight) + "px";
                } else {
                  lookupDiv.style.top = (handler.totalTopOffset(inputText) - lookupDiv.offsetHeight) + "px";
                }
                lookupDiv.style.left = (handler.totalLeftOffset(inputText) + inputText.offsetLeft) + "px";
                lookupDiv.style.visibility = "visible";
                handler.lookuplength = items.length;
              } else {
                handler.hideLookup();
              }
          } 
          else {
              // An error has occurred.
              //alert("Error: "+requestObject.status);
              if(window.status){
                 window.status("Could not list publishers "+ requestObject.status);
              }
          }
      }  
    }

    var gurl = location.protocol+"//"+location.host + url;

    requestObject.open("GET", gurl + "?keystrokes="+keystrokes+"&lookup="+lookup+"&lookupsize="+lookupsize, true);
    requestObject.setRequestHeader( "Content-Type" , "application/x-www-form-urlencoded; charset=UTF-8" );
    requestObject.send(null);
  };

  // Executes autocompletion request.
  // ---------------------------------------------------------------------------
  handler.execute = function() {
    var inputText = document.getElementById(inputTextId);
      
    if (this.updatetextrequest==true) {
      inputText.value = this.newtext;
      this.updatetextrequest = false;
    }

    if (this.escpressed==false && this.preselected<0) {
      var value = inputText.value.replace(/^[ \t]+|[ \t]+$/g,"");
      if (value.length >= actlength)  {
        this.send(url, value, lookup);
      } else {
        this.hideLookup();
      }
    }
    this.escpressed = false;
  };

  // Hides lookup component.
  // ---------------------------------------------------------------------------
  handler.hideLookup = function() {
    var clientDiv = document.getElementById(clientId);
    var lookupDiv = document.getElementById(lookupDivId);

    clientDiv.style.zIndex = zIndex;
    while (lookupDiv.firstChild) {
      lookupDiv.removeChild(lookupDiv.firstChild);
    }

    //lookupDiv.style.visibility = "hidden";
    this.lookuplength = 0;
    this.preselected = -1;
  };

  // Indicates that element has been blured.
  // ---------------------------------------------------------------------------
  handler.onBlur = function() {
    if (this.mouseOver==false) {
      this.hideLookup();
    }
  };

  // Indicates that mouse is over the lookup list.
  // ---------------------------------------------------------------------------
  handler.onMouseOver = function() {
    this.mouseOver = true;
  };

  // Indicates that mouse is out of the lookup list.
  // ---------------------------------------------------------------------------
  handler.onMouseOut = function() {
    this.mouseOver = false;
  };

  // Indicates that mouse move over the lookup list.
  // ---------------------------------------------------------------------------
  handler.onMouseMove = function() {
    if (this.preselected>=0) {
      for (i=0; i<this.lookuplength; i++) {
        var e = document.getElementById(lookupElementDivId+i);
        e.className = "autocompletionPopupItem";
      }
      this.preselected = -1;
    }
  };

  // Function invoked everytime an item is selected from the autocomlpete list.
  // ---------------------------------------------------------------------------
  // text  - text selected from autocomplete list.
  // ---------------------------------------------------------------------------
  handler.onListClick = function(text) {
    var inputText = document.getElementById(inputTextId);
    inputText.value = text;
    this.hideLookup();
  };

  // Calculates total (absolute) offset top of the node.
  // ---------------------------------------------------------------------------
  // node - node to have total offset calculated
  // ---------------------------------------------------------------------------
  handler.totalTopOffset = function(node) {
    var offset = node.offsetTop;
    while (node.offsetParent!=null) {
      node = node.offsetParent;
      offset = offset + node.offsetTop;
    }
    return offset;
  };

  // Calculates total (absolute) offset left of the node.
  // ---------------------------------------------------------------------------
  // node - node to have total offset calculated
  // ---------------------------------------------------------------------------
  handler.totalLeftOffset = function(node) {
    var offset = node.offsetLeft;
    while (node.offsetParent!=null) {
      node = node.offsetParent;
      offset = offset + node.offsetLeft;
    }
    return offset;
  };

  // Handles keyboard events.
  // ---------------------------------------------------------------------------
  // event - keyboard event
  // ---------------------------------------------------------------------------
  handler.onKeyDown = function(event) {
    if (this.lookuplength > 0) {
      var lookupDiv = document.getElementById(lookupDivId);
      var inputText = document.getElementById(inputTextId);

      var keynum;

      if(window.event) { // IE
        keynum = event.keyCode;
      }
      else if(event.which) { // Netscape/Firefox/Opera
        keynum = event.which;
      } 

      if (keynum==38) {
        // up
        if (this.preselected>0) {
          this.preselected--;
          var element = document.getElementById(lookupElementDivId+this.preselected);
          element.className = "autocompletionPopupItemSelected";
          this.newtext = element.innerHTML;
          this.updatetextrequest = true;

          for (i=0; i<this.lookuplength; i++) {
            var e = document.getElementById(lookupElementDivId+i);
            if (i==this.preselected) {
              e.className = "autocompletionPopupItemSelected";
            } else {
              e.className = "autocompletionPopupItemNotSelected";
            }
          }  
        } else if (this.preselected==0) {
          for (i=0; i<this.lookuplength; i++) {
            var e = document.getElementById(lookupElementDivId+i);
            e.className = "autocompletionPopupItem";
          }
          this.preselected = -1;
          this.newtext = this.orgtext;
          this.updatetextrequest = true;
          for (i=0; i<this.lookuplength; i++) {
            var e = document.getElementById(lookupElementDivId+i);
            e.className = "autocompletionPopupItem";
          }
        } else if (this.preselected==-1) {
          this.orgtext = inputText.value;
          this.preselected = this.lookuplength-1;

          var element = document.getElementById(lookupElementDivId+this.preselected);
          this.newtext = element.innerHTML;
          this.updatetextrequest = true;

          for (i=0; i<this.lookuplength; i++) {
            var e = document.getElementById(lookupElementDivId+i);
            if (i==this.preselected) {
              e.className = "autocompletionPopupItemSelected";
            } else {
              e.className = "autocompletionPopupItemNotSelected";
            }
          }
        }
      } else if (keynum==40) {
        // down
        if (this.preselected+1<this.lookuplength) {
          if (this.preselected==-1) {
            this.orgtext = inputText.value;
          }

          this.preselected++;
          var element = document.getElementById(lookupElementDivId+this.preselected);
          this.newtext = element.innerHTML;
          this.updatetextrequest = true;

          for (i=0; i<this.lookuplength; i++) {
            var e = document.getElementById(lookupElementDivId+i);
            if (i==this.preselected) {
              e.className = "autocompletionPopupItemSelected";
            } else {
              e.className = "autocompletionPopupItemNotSelected";
            }
          }
        }
      } else if (keynum==39) {
        // right
        this.hideLookup();
        this.escpressed = true;
      } else if (keynum==27) {
        // escape
        this.hideLookup();
        this.escpressed = true;
      } else {
        this.preselected = -1;
      }
    }
  };

  return handler;
}
