var _LT = function(inputField, outpuField, options) {
  var self = this; // self-hack

  self.element = _getById(inputField);
  self.element.setAttribute("autocomplete", "off");
  self.update  = _getById(outpuField);
  self.formElement = _getFormElement();
  self.options = {
    host: window.location.href.match(/.*:\/\/.*?\//),
    url: "/search",
    param: "s"
  }
  for(option in options) {
    self.options[option] = options[option];
  }
  self.cache = {};
  self.index = -1;
  
  _addEvents();
  
  function _getFormElement() {
    var parent = self.element.parentNode;
    while(parent.tagName.toLowerCase() != 'form') {
      parent = parent.parentNode
    }
    return parent;
  }

  function _search() {
    var value = _trim(self.element.value);
    if (value.length == 0) {
      _hide();
      return false;
    }
    if (self.cache[value]) { self._results(self.cache[value]); return false; }
    if (value.length == 0) return false;
    var url = _url() + value;
    if (self.scriptTag) self.scriptTag.parentNode.removeChild(self.scriptTag);
    
    self.scriptTag = _newElement('script', { src: url, type: 'text/javascript' }, '');
    document.getElementsByTagName('head')[0].appendChild(self.scriptTag);      
    
  }
  
  self._results = function(result) {
    if (!self.cache[result.query]) self.cache[result.query] = result;
    if (result.suggests && result.suggests.length > 0) {
      self.update.innerHTML = '';
      var listElements = '';
      for (var i=0; i < result.suggests.length; i++) {
    	  listElements += _newElementString('li', { "deeplink": result.suggests[i].deeplink, "onmouseout": '_LT._deselect(this)', "onmouseover": '_LT._select(this)', "title": result.suggests[i].meta }, result.suggests[i].meta.replace(new RegExp("(" + self.originalValue.split(" ").join("|") + ")", 'ig'), "<b>$1</b>"));
    	};
      var html = _newElementString('ul', { id: 'autocomplete_results'}, listElements);
      //var html = _newElement('ul', { id: 'autocomplete_results'}, '')
    	/*for (var i=0; i < result.suggests.length; i++) {
    	  html.appendChild(_newElement('li', { "onmouseout": '_LT._deselect(this)', "onmouseover": '_LT._select(this)', "title": result.suggests[i].meta }, result.suggests[i].meta));
    	};*/
    	//.replace(new RegExp("(" + self.originalValue + ")", 'i'), "<b>$1</b>"))
    	self.update.innerHTML = html;
    	self.resultElements = self.update.firstChild.childNodes;
    	
    	_show();
  	}
  	else if (typeof(result.suggests) === 'undefined') {}
  	else _hide();
  }
  
  function _url() {
    return(self.options.host + self.options.url + "?" + self.options.param + "=");
  }
  
  function _newElement(tag, options, content) {
    var element = document.createElement(tag);
    for (option in options) {
      element.setAttribute(option, options[option]);
    }
    if (tag != 'script' && content) {
      var text = document.createTextNode(content);
      element.appendChild(text);
    }
    return element;
  }
  
  function _newElementString(tag, options, content) {
    var html = "<" + tag;
    for (option in options) {
      html += " " + option + "='" + options[option] + "'";
    }
    html += ">" + content + "</" + tag + ">";
    return html;
  }
  
  function _trim(text) {
    text = text.replace( /^\s+/g, "" );
    return text.replace( /\s+$/g, "" );
  }
  
  function _addEvent(evnt, elem, func) {
    elem = _getById(elem);
    if (elem.addEventListener)
      elem.addEventListener(evnt, func, false);
    else if (elem.attachEvent) {
      var r = elem.attachEvent("on" + evnt, func);
  	  return r;
    }
  }
  
  function _stopEvent(e) {
    if (e && e.stopPropogation) e.stopPropogation();
    else if (window.event && window.event.cancelBubble)
      window.event.cancelBubble = true;
    if (e &&e.preventDefault) e.preventDefault();
    else if (window.event && window.event.returnValue)
      window.event.returnValue = false;
  }
  
  function _eventElement(e) {
    var targ;
    if (!e) e = window.event;
    if (e.target) targ = e.target;
    else if (e.srcElement) targ = e.srcElement;
    if (targ.nodeType == 3) targ = targ.parentNode;
    return targ;
  }
  
  function _show() {
    self.update.style.display = 'block';
  }
  function _hide() {
    self.update.style.display = 'none';
  }
  
  function _stripTags(string) {
    return string.replace(/(<([^>]+)>)/ig,"").replace(/\(.*\)/ig, '');
  }
  
  function _addEvents() {
    // event deledation
    _addEvent('blur', self.element, function(event) {
      self.element.setAttribute("hasFocus", "false");
    });
    _addEvent('focus', self.element, function(event) {
      self.element.setAttribute("hasFocus", "true");
    });
    _addEvent('click', document.body, function(event) {
      if (self.update.style.display == 'block') {
        _hide();
      }
    });
    _addEvent('click', self.update, function(event) {
      var element = _eventElement(event);
      if (element == self.element) {
        _show();
      }
      else {
        if (element.tagName.toLowerCase() == 'b') element = element.parentNode;
        if (element.tagName.toLowerCase() == 'li' && element.className == 'lt_selected') {
          var url = element.getAttribute("deeplink");
          var value = _stripTags(element.innerHTML);
	  //  self.element.value = value;
          _submit(url);
        }
      }
    });
  }
  
  function _submit(url) {
    if (!url && self.index < 0) return false;
    if (!url) {
      url = self.resultElements[self.index].getAttribute("deeplink");
    }
    window.location.href = url;
  }  
  
  function _deselectElements(elements) {
    for (var i = elements.length - 1; i >= 0; i--){
      elements[i].className = '';
    };
  }
  
  function _onkeyup(event) {   
    if (self.element.getAttribute("hasFocus") === "true") {
      switch(event.keyCode) {
        case 27: // ESC
          _hide();
          _stopEvent(event);
          ltIndex = -1;
          break;
        case 39: // cursor right
          _hide();
          _stopEvent(event);
          break;
        case 38: // cursor up
          _stopEvent(event);
          _markPrevious();
          break;
        case 40: // cursor down
          _stopEvent(event);
          _markNext();
          break;
        case 13: // Return key
	_stopEvent(event);
          _submit();
          break;
        default:
          self.originalValue = self.element.value;
          _search();
          break;
      }
    }
    else {
      _search();
      if (self.element.getAttribute("hasFocus") === "true" && self.update.innerHTML.length == 0) {
        _show();
        _stopEvent(event);
      }
    }
  }
  
  function _onkeydown(event) {
    if (self.element.getAttribute("hasFocus") === "true") {
      switch(event.keyCode) {
        case 38:
          _stopEvent(event);
          break;
        case 40:
          _stopEvent(event);
          break;
      }
    }
  }
  
  function _markNext() {
    self.index = (self.index == self.resultElements.length -1) ? -1 : self.index + 1;
  	_deselectElements(self.resultElements);
  	if (self.index > -1) {
  		_LT._select(self.resultElements[self.index]);
  		_show();
  		//self.element.value = _stripTags(self.resultElements[self.index].innerHTML);
  	}
  	else {
	    //  	  self.element.value = self.originalValue;
  		_hide();
  	}
  }
  
  function _markPrevious() {
  	self.index = (self.index == -1) ? self.resultElements.length -1  : self.index - 1;
  	_deselectElements(self.resultElements);
  	if (self.index > -1) {
  		_LT._select(self.resultElements[self.index]);
  		_show();
		//  		self.element.value = _stripTags(self.resultElements[self.index].innerHTML);
  	}
  	else {
	    //  	  self.element.value = self.originalValue;
  		_hide();
  	}
  	return false;
  };
  
  
  document.onkeyup = function keyPress(event) {
    if (typeof(event) == "undefined") event = window.event;
    _onkeyup(event);
  }
  document.onkeydown = function keyPressDown(event) {
    if (typeof(event) == "undefined") event = window.event;
    _onkeydown(event);
  }
  
}


_LT._select = function(element) {
	_getById(element).className = 'lt_selected';
};
_LT._deselect = function(element) {
	_getById(element).className = _getById(element).className.replace("lt_selected", "");
};

function _getById(element) {
  if (typeof(element) == 'string')
    return document.getElementById(element);
  else
    return element;
}

