var Registry = [];
var _registryIndex = 0;
var _lastKeyCode = -1;
var _names;
var _ids;
var _images;
var _networks;

var TypeAhead = function(rootEl, formEl, textBoxEl, idEl, defaultOptions, instructions, useFilter, onSuccessHandler, onInputChangeHandler, onUpHandler, onDownHandler, onListElMouseDownHandler, placeholderText, showNoMatches, override_resize)
{
  this.resize=!override_resize;
  this.getMatchSingleTerm = function(term, document)
  {
    var str = "";
    var len = term.length;
    if (!document) return '';
    var curDocument = document;

    // first check at beginning of string.
    var index = 0;
    index = curDocument.toUpperCase().indexOf(term.toUpperCase());
    if(index == -1)
    {
      return str;
    }
  
    var match = curDocument.substring(0, len);
    str += '<span class="suggest">' + match + '</span>';

    var moreMatches = 0;
    curDocument = curDocument.substring(index+len);
    while((index = curDocument.toUpperCase().indexOf(term.toUpperCase())) != -1)
    {
      var pre = curDocument.substring(0, index);
      if(pre)
      {
        str += pre;
      }
      var match = curDocument.substring(index, index+len);        
      if(match)
      {
        str += '<span class="suggest">' + match + '</span>';
      }
      curDocument = curDocument.substring(index+len);
      moreMatches = 1;
    }
    if(moreMatches)
    {
      str += curDocument;
    }
  }

  this.getMatchMultipleTerms = function(terms, document)
  {
    if (!document) return '';
    var termsArr = terms.split(/\s+/);
    var docArr = document.split(/\s+/);

    var str = "";
    for(var docIdx in docArr)
    {
      var matchFound = 0;
      var doc = docArr[docIdx];
      for(var termIdx in termsArr)
      {
        var term = termsArr[termIdx];

        // if we found a match
        if(doc.toUpperCase().indexOf(term.toUpperCase()) == 0)
        {
          matchFound = 1;
          break;
        }
      }

      if(docIdx > 0)
      {
        str += ' ';
      }

      if(matchFound)
      {
        var len = term.length;
        var pre = doc.substring(0, len);
        var suf = doc.substring(len);
        str += '<span class="suggest">' + pre + '</span>' + suf;
      }
      else
      {
        str += doc;
      }
    }

    return str;
  }

	this.onListChange = function()
	{
		this.selectedIndex = -1;
    if(!this.pEvent)
    {
      this.idEl.value = -1;
    }
		var dropDownEl = this.dropDownEl;
		if(dropDownEl && dropDownEl.childNodes)
		{
			this.dropDownCount = dropDownEl.childNodes.length;
		}

		this.lastTypedValue = this.currentInputValue;
		if(this.currentInputValue == "" || this.dropDownCount == 0 || this.pEvent)
		{
			this.dropDownEl.hide();
//    this.defaultDropDownEl.hide();
		}
		else
		{
			this.dropDownEl.show();
      this.defaultDropDownEl.show();
		}
			
		var matchFound = false;
		if(this.currentInputValue.length > 0)
		{
			for(var i = 0; i < this.dropDownCount; i++)
			{
          if(!matchFound)
          {
					  matchFound = true;
					  this.selectedIndex = i;
				    this.selectedEl = this.dropDownEl.childNodes[i];
          }

          // try matching the name
          var str = this.getMatchSingleTerm(this.currentInputValue, this.dropDownEl.childNodes[i]._value);
          if(!str)
          {
            str = this.getMatchMultipleTerms(this.currentInputValue, this.dropDownEl.childNodes[i]._value);
          }
          this.dropDownEl.childNodes[i].setName(str);

          // try matching the location
          str = this.getMatchSingleTerm(this.currentInputValue, this.dropDownEl.childNodes[i]._loc);
          if(!str)
          {
            str = this.getMatchMultipleTerms(this.currentInputValue, this.dropDownEl.childNodes[i]._loc);
          }
          this.dropDownEl.childNodes[i].setLoc(str);
			}				

      if(!matchFound)
      {
        for(var i = 0; i < this.defaultDropDownCount; i++)
        {
				  if(this.defaultDropDownEl.childNodes[i]._value.toUpperCase().indexOf(this.currentInputValue.toUpperCase()) == 0)
				  {
				  	matchFound = true;
				  	this.selectedIndex = i;
					  this.selectedEl = this.defaultDropDownEl.childNodes[i];
					  break;
          }
        }
      }
		}
			
		var value = this.currentInputValue;
			
		var keyIgnore = false;
		switch(this.lastKeyCode)
		{
			case 8:
			case 33:
			case 34:
			case 35:
			case 35:
			case 36:
			case 37:
			case 39:
			case 45:
			case 46:
				keyIgnore = true;
				break;
      case 27:
        keyIgnore = true;
        break;
			default:
				break;
		}
			
		if(!keyIgnore && matchFound && !this.pEvent /* IE focus bug */)
		{
			this.selectedEl.select();	
		}
		else
		{
		}

    this._noMatches = false;
    if(this.dropDownCount == 0)
    {
      if(this.textBoxEl.value != "" && this.textBoxEl.value != this.textBoxEl.ph)
      {
        this._noMatches = true;
        if(this.showNoMatches)
        {
          this.defaultTextEl.setText("No Matches Found");
        }
      }
      else
      {
        this.defaultTextEl.setDefault();
      }

      this.defaultDropDownEl.show();

      if(this.showNoMatches)
      {
        this.defaultTextEl.show();
      }
    }
    else
    {
      this.defaultTextEl.hide();
    }

    if(this.dropDownCount >= 1 && this.selectedEl && this.getUnselectedLength() == this.selectedEl._value.length)
    {
		  this.idEl.value = this.selectedEl._id;
      if (this.dropDownCount == 1) {
        this.onTypeAheadSuccess();
      } else {
        this.textBoxEl.style.background = "#e1e9f6";
      }
    }
    else
    {
      this.onTypeAheadFailure();
    }
    if(this.lastKeyCode == 27)
    {
      this.textBoxEl.blur();
    }
  
    this.setFrame();
    this.pEvent = 0;
	}

  this.setFrame = function()
  {
    if(this.goodFrame)
    {
      this.goodFrame.style.height = (this.containerEl.offsetHeight) + "px";
      this.goodFrame.style.width = (this.textBoxEl.offsetWidth) + "px";
    }
  }

  this.onTypeAheadSuccess = function()
  {
    this.dropDownEl.hide();
    this.textBoxEl.style.background = "#e1e9f6";
    if(this.onSuccess && !this.pEvent)
    {
      this.onSuccess(this);
    }
  }

   this.onTypeAheadFailure = function()
  {
    this.textBoxEl.style.background = "#FFFFFF";
  }

	this.refocus = function()
	{
		this.reFocused = true;
		this.textBoxEl.blur();
		setTimeout("Registry[" + this.registryIndex + "].focus();", 10);
	}

	this.focus = function()
	{
		this.textBoxEl.focus();
	}

	this.handleKeyUp = function(event)
	{
		if(!event && window.event)
		{
			event = window.event;
		}

		
		// avoids double-firing of events in safari
		if(event.keyCode == 40 || event.keyCode == 38)
		{
        if(this.isSafari && (this.fireCount++ % 2 == 1))
        {
      //    return;
        }
      
	//		this.refocus();
		}

    // fast typing check
		var value = this.textBoxEl.value;
		var sLen = this.getSelectedLength();
	  var uLen = this.getUnselectedLength();
		if(sLen > 0 && uLen != -1)
		{
			value = value.substring(0, uLen);
		}
		this.currentInputValue = value;

		var keyIgnore = false;
		switch(this.lastKeyCode)
		{
      case 13:
      case 9:
        keyIgnore = true;
        break;
			case 38:
				keyIgnore = true;
//				this.selectPrevDropDown();
        if(this.onUp)
        {
          this.onUp(this);
        }
				break;
			case 40:
				keyIgnore = true;
//				this.selectNextDropDown();
        if(this.onDown)
        {
          this.onDown(this);
        }
				break;
		}

    this.pEvent = 0;
    if(event.pEvent)
    {
      this.pEvent = event.pEvent;
    }

		if(!keyIgnore && /*this.currentInputValue != this.lastInputValue &&*/ this.onInputChange)
		{
      this.onInputChange(this);
    }
    if(this.lastKeyCode == 13)
    {
      this.lastKeyCode = -1;
      _lastKeyCode = -1;
    }
		
		this.lastInputValue = this.currentInputValue;
	}

 	this.getSelectedLength = function()
	{
    var el = this.textBoxEl;
  	var len = -1;
  	if(el.createTextRange)
		{
    	var selection = document.selection.createRange().duplicate();
    	len = selection.text.length;
  	}
		else if(el.setSelectionRange)
		{
    	len = el.selectionEnd - el.selectionStart;
  	}
  	return len;
	}

		
	this.getUnselectedLength = function()
	{
    var el = this.textBoxEl;
		var len = 0;
		if(el.createTextRange)
		{
			var selection = document.selection.createRange().duplicate();
			selection.moveEnd("textedit", 1);
			len = el.value.length - selection.text.length;
		}
		else if(el.setSelectionRange)
		{
			len = el.selectionStart;
		}
		else
		{
			len = -1;
		}
		return len;
	}

	this.handleKeyDown = function(event)
	{
		if(!event && window.event)
		{
			event = window.event;
		}
		if(event)
		{
			this.lastKeyCode = event.keyCode;
      _lastKeyCode = event.keyCode;
		}

		switch(this.lastKeyCode)
		{
			case 38:
				break;
			case 40:
				break;
      case 27:
        this.textBoxEl.value = "";
        break;
			case 13:
      case 9:
        //formEl.onsubmit();
        if(this.selectedIndex != -1)
        {
          this.textBoxEl.value = this.selectedEl._value;
          this.defaultTextEl.hide();
          this.onTypeAheadSuccess();
        }
        this.dropDownEl.hide();
        this.defaultDropDownEl.hide();
        this.setFrame();
        break;
			case 3:
				this.dropDownEl.hide();
        this.defaultDropDownEl.hide();
        this.setFrame();
				break;	
		}

		switch(this.lastKeyCode)
		{
			case 38:
				this.selectPrevDropDown();
        if(this.onUp)
        {
          this.onUp(this);
        }
				break;
			case 40:
				this.selectNextDropDown();
        if(this.onDown)
        {
          this.onDown(this);
        }
				break;
		}

		if(event && (event.keyCode == 13 || event.keyCode == 38 || event.keyCode == 40))
		{
		  event.cancelBubble = true;
 		  event.returnValue = false;
		}
	}

	this.selectPrevDropDown = function()
	{
		this.selectDropDown(this.selectedIndex-1);
	}
	this.selectNextDropDown = function()
	{
		this.selectDropDown(this.selectedIndex+1);
	}
	
	this.selectDropDown = function(index)
	{
    this.textBoxEl.value = this.lastTypedValue;
		if((this.dropDownCount + this.defaultDropDownCount) <= 0)
		{
			return;
		}

    if(this.dropDownCount > 0)
    {
		  this.dropDownEl.show();
      this.defaultDropDownEl.show();
    }
    else
    {
      this.dropDownEl.hide();
      //this.defaultDropDownEl.hide();
    }
    this.setFrame();

    var usingDefaultDropDown = false;
    if(index >= this.dropDownCount && this.defaultDropDownCount > 0)
    {
      usingDefaultDropDown = true;
    }
		
		if(index >= this.dropDownCount + this.defaultDropDownCount)
		{
			index = this.dropDownCount + this.defaultDropDownCount - 1;
		}

		if(this.selectedIndex != -1 && index != this.selectedIndex)
		{
			this.selectedIndex = -1;
			this.selectedEl.unselect();
		}
		
		if(index < 0)
		{
			this.selectedIndex = -1;

      // commented out. safari issue erasing the text box
//		this.textBoxEl.focus();
			return;
		}
		
		this.selectedIndex = index;
    if(usingDefaultDropDown)
    {
      this.selectedEl = this.defaultDropDownEl.childNodes[index-this.dropDownCount];
    }
    else
    {
		  this.selectedEl = this.dropDownEl.childNodes[index];
    }
		this.selectedEl.select();
		
		this.textBoxEl.value = this.selectedEl._value;
	}

  this.displaySuggestList = function(names, ids, locs)
  {
		if(names.length != ids.length)
		{
			return false;
		}

		var dropDownEl = this.dropDownEl;
		while(dropDownEl.childNodes.length > 0)
		{
			dropDownEl.removeChild(dropDownEl.childNodes[0]);
		}

    if(this.selectedEl)
    {
      this.selectedEl.unselect();
    }

    //match_i used to cap items shown in non-ajax version
    var match_i = 0;
    var termsArr;
    var term;
    var matchFound;
    var name;
    var match_id;
    var filter = this.currentInputValue.toUpperCase();
    filter = filter.replace(/^\s+|\s+$/,'');
	  for(var i = 0; i < names.length && match_i < 10; i++)
	  {
      name = names[i];
      if(this.useFilter)
      {
        if(!filter)
        {
           continue;
        }

        match_id = ids[i];
        if(window._ignoreList && _ignoreList[match_id] && _ignoreList[match_id] == 1)
        {
          continue;
        }

        matchFound = 0;
        if(name.toUpperCase().indexOf(filter) == 0)
        {
          matchFound = 1;
        }
              
        if(!matchFound)
        {
          termsArr = name.split(/\s+/);
          for(var termIdx in termsArr)
          {
            term = termsArr[termIdx];
            if(term.toUpperCase().indexOf(filter) == 0)
            {
              matchFound = 1;
              break;
            }
          }
        }
                
        if(!matchFound)
        {
          continue;
        }

        match_i++;
      }

      var listEl = this.createListElement(name, ids[i], locs[i], i);
      dropDownEl.appendChild(listEl);
    }

    // now reset the indexes for the default drop down
    for(var i = 0; i < this.defaultDropDownEl.childNodes.length; i++)
    {
      var listEl = this.defaultDropDownEl.childNodes[i];
      listEl._index = i + this.dropDownEl.childNodes.length;
    }

		return true;
	}

  this.createListElement = function(name, id, loc, index)
  {
		var listEl = document.createElement("div");
		listEl._value = name;
    listEl._loc = loc;
		listEl._id = id;
    listEl._index = index;

    listEl.setName = function(name)
    {
      this.nameEl.innerHTML = name;
    }

    listEl.setLoc = function(loc)
    {
      if (this.locEl)
        this.locEl.innerHTML = loc;
    }

		listEl.select = function()
		{
			this.className = "list_element_container_selected";
      this.nameEl.className = "list_element_name_selected";
      if(this.locEl)
      {
        this.locEl.className = "list_element_loc_selected";
      }
      if(oThis.idEl)
      {
        oThis.idEl.value = this._id;
      }
		}

		listEl.unselect = function()
		{
			this.className = "list_element_container";
      this.nameEl.className = "list_element_name";
      if(this.locEl)
      {
        this.locEl.className = "list_element_loc";
      }
      if(oThis.idEl)
      {
    //    oThis.idEl.value = -1;
      }
		}

		listEl.onmousedown = function()
		{		
			oThis.textBoxEl.value = this._value;	
      if(oThis.idEl)
      {
		    oThis.idEl.value = this._id;
      }
      oThis.onTypeAheadSuccess();

      if(oThis.formEl)
      {
     //   oThis.formEl.submit();
      }

      if(oThis.onListElMouseDown)
      {
        oThis.onListElMouseDown(oThis, this);
      }
      oThis.setFrame();
	  } 

		listEl.onmouseover = function() 
		{
			if(oThis.selectedEl)
			{
				oThis.selectedEl.unselect();
			}
			oThis.selectedEl = this;
       oThis.selectedIndex = this._index;
			this.select();
		}

		listEl.onmouseout = function()
		{
			this.unselect();
		}
    listEl.style.zIndex = "101";

    var dividerEl;
    if(index == -1)
    {
      dividerEl = this.createDivider();
      listEl.appendChild(dividerEl);
    }

		var nameEl = document.createElement("div");
		nameEl.className = "list_element_name";
		nameEl.innerHTML = name;
		listEl.appendChild(nameEl);
    listEl.nameEl = nameEl;
    listEl.locEl = locEl;

    if(loc)
    {
      var locEl = document.createElement("div");
      locEl.className = "list_element_loc";
      locEl.innerHTML = loc;
      listEl.appendChild(locEl);
      listEl.locEl = locEl;
    }

    dividerEl = this.createDivider();
    listEl.appendChild(dividerEl);

	  listEl.unselect();

    return listEl;
  }

  this.createDivider = function()
  {
    var dividerEl = document.createElement("div");
    dividerEl.className = "list_element_divider";
    return dividerEl;
  }

  this.createDropDownContainer = function()
  {
    var containerEl = document.createElement("div");
    containerEl.className = "dropdown-container";
    this.containerEl = containerEl;
    this.positionDropDown();
  }
	
	this.createDropDown = function()
	{
/*
    var dropDownHeaderEl = document.createElement("div");
    dropDownHeaderEl.className = "header";
    dropDownHeaderEl.style.display = "none";
    dropDownHeaderEl.innerHTML = "Did you mean...";
    
    this.containerEl.appendChild(dropDownHeaderEl);
    this.dropDownHeaderEl = dropDownHeaderEl;
*/

		var dropDownEl = document.createElement("div");
		dropDownEl.className = "dropdown";
		dropDownEl.style.display = "none";
    dropDownEl.style.zIndex = "101";
	
		dropDownEl.hide = function()
		{
      this.style.display = "none";
//      oThis.dropDownHeaderEl.style.display = "none";
		}
		dropDownEl.show = function()
		{
      this.style.display = "";
//      oThis.dropDownHeaderEl.style.display = "";
		
			// safari doesn't always position this correctly on initialization, so explicitly call it here.
			oThis.positionDropDown();
		}
	
		this.containerEl.appendChild(dropDownEl);
		this.dropDownEl = dropDownEl;
	}

  this.createDefaultDropDown = function()
  {
    var defaultDropDownHeaderEl = document.createElement("div");
    defaultDropDownHeaderEl.className = "typeahead_header";
    defaultDropDownHeaderEl.style.display = "none";
    defaultDropDownHeaderEl.innerHTML = "Search elsewhere...";

    this.containerEl.appendChild(defaultDropDownHeaderEl);
    this.defaultDropDownHeaderEl = defaultDropDownHeaderEl;

    var defaultDropDownEl = document.createElement("div");
		defaultDropDownEl.style.display  = "none";

    defaultDropDownEl.show = function()
    {
      if(oThis.defaultDropDownCount > 0)
      {
        this.style.display = "";
        oThis.defaultDropDownHeaderEl.style.display = "";
      }
      else
      {
        oThis.dropDownEl.style.borderBottom = "1px solid #777";
      }
    }

    defaultDropDownEl.hide = function()
    {
      this.style.display = "none";
      oThis.defaultDropDownHeaderEl.style.display = "none";
    }

    var index = 0;
    for(var option in this.defaultOptions)
    {
      var listEl = this.createListElement(option, this.defaultOptions[option], "", index);
      index++;
      defaultDropDownEl.appendChild(listEl);
    }

    defaultDropDownEl.className = "default-dropdown";
    defaultDropDownEl.hide();
		this.containerEl.appendChild(defaultDropDownEl);
    this.defaultDropDownEl = defaultDropDownEl;
		this.defaultDropDownCount = defaultDropDownEl.childNodes.length;
  }
  
  this.createDefaultText = function()
  {
    var defaultTextEl = document.createElement("div");
    defaultTextEl.className = "default-text";
    defaultTextEl.style.display = "none";
    
    defaultTextEl.hide = function()
    {
      this.style.display = "none";
    }

    defaultTextEl.show = function()
    {
      this.style.display = "";
      if(oThis.defaultDropDownCount == 0)
      {
        this.style.borderBottom = "1px solid #777";
      }
    }

    defaultTextEl.setDefault = function()
    {
      this.innerHTML = instructions; 
    }

    defaultTextEl.setText = function(text)
    {
      this.innerHTML = text;
    }

    defaultTextEl.setDefault();
  
    if(!this.defaultOptions)
    {
      defaultTextEl.style.borderBottom = "0px solid";
    }

    this.containerEl.appendChild(defaultTextEl);
    this.defaultTextEl = defaultTextEl;
  }

	this.positionDropDown = function()
	{
		var containerEl = this.containerEl;
		if(containerEl)
		{
      if (this.resize) {
        containerEl.style.left = elementX(this.textBoxEl)  + "px";
        containerEl.style.top = elementY(this.textBoxEl) + this.textBoxEl.offsetHeight + "px";
      }
			if(!this.isIE)
			{
				containerEl.style.width = this.textBoxEl.offsetWidth + "px";
			}
			else
			{
				containerEl.style.width = this.textBoxEl.offsetWidth + "px";
			}
		}
	}

  this.getText = function()
  {
    return this.textBoxEl.value;
  }

  this.getSelectedText = function()
  {
    return this.selectedEl ? this.selectedEl._value : '';
  }
  
  this.noMatches = function() 
  {
      return this._noMatches; 
  }

  this.getID = function()
  {
    return this.selectedEl ? this.selectedEl._id : 0;
  }

  this.setText = function(q, reset)
  {
    this.textBoxEl.setText(q, reset);
  }

	this.init = function()
	{	
        this._noMatches = false;
		this.registryIndex = _registryIndex;
		Registry[_registryIndex++] = this;
		
		this.lastKeyCode = -1;
	
		this.currentInputValue = textBoxEl.value;
    this.lastTypedValue = "";
		this.lastInputValue = "";

		this.dropDownCount = 0;
    this.defaultDropDownCount = 0;
	
		this.selectedIndex = -1;
		this.selectedEl = null;
		
		this.reFocused = false;

    textBoxEl.setAttribute("placeholder", placeholderText);
    textBoxEl.style.color = '#777';
    textBoxEl.ph = placeholderText;

    textBoxEl.oThis = this;
		
		textBoxEl.onblur = function()
		{
			if(!oThis.reFocused)
			{
				oThis.dropDownEl.hide();
        oThis.defaultTextEl.hide();
        oThis.defaultDropDownEl.hide();
			}
      if(oThis.selectedIndex == -1)
      {
        //this.value = "";
        oThis.idEl.value = -1; 
      }
			oThis.reFocused = false;

			var ph = this.getAttribute("placeholder");
			if(this.isFocused && ph && (this.value == "" || this.value == ph))
			{
				this.isFocused = 0;
				this.value = ph;
				this.style.color = '#777';
			}
      oThis.setFrame();
		}	

		textBoxEl.onfocus = function()
		{
            // need this because this is called from a setTimeout
            var oThis = this.oThis;
			if(!this.isFocused)
			{
				this.isFocused = 1;
				if(oThis.selectedIndex == -1 && this.value == this.getAttribute("placeholder"))
				{
					this.value = '';
				}

			}
            if(oThis.dropDownCount > 0 || oThis.defaultTextEl.innerHTML != '')
            {
                if (oThis.dropDownCount == 0) {
                    oThis.defaultTextEl.show();
                }

                if(this.createTextRange)
                {
                    var t = this.createTextRange();
                    t.moveStart("character", 0);
                    t.select();
                }
                else if(this.setSelectionRange)
                {
                    this.setSelectionRange(0, this.value.length);
                }

                oThis.dropDownEl.show();
                oThis.defaultDropDownEl.show();
                oThis.positionDropDown();
                oThis.setFrame();
            }
            this.style.color = '#000';
		}

		textBoxEl.onkeyup = function(event)
		{
			oThis.handleKeyUp(event);
		}

		textBoxEl.setText = function(q, reset)
		{
			var ph = this.getAttribute("placeholder");
      this.isFocused = 0;
      if(q)
      {
        this.style.color = '#000';
        this.value = q;
        var ev = new Object();
        ev.keyCode = 0;
        ev.pEvent = 1;
        oThis.handleKeyUp(ev);
      }
    
			else if(ph && ph != "")
			{
        if(reset)
        {
          this.value = "";
          this.style.color = '#000';
        }
        else
        {
				  this.value = ph;
				  this.style.color = '#777';
        }
				this.isFocused = 0;
        oThis.textBoxEl.style.background = "#FFFFFF";
			}
      else
      {
        this.value = "";
        oThis.textBoxEl.style.background = "#FFFFFF";
      }
		}

    if(formEl)
    {
		  formEl.onsubmit = function()
		  {
        oThis.setFrame();
        if(_lastKeyCode == 13) 
        { 
          _lastKeyCode = -1;
          return false;
        }
		  	if(oThis.selectedIndex != -1 && oThis.selectedEl)
		  	{
		  		oThis.idEl.value = oThis.selectedEl._id;
			  }
			  //this.submit();
        return true;
		  }
    }
		this.formEl = formEl;

		this.textBoxEl = textBoxEl;

		this.idEl = idEl;
		this.onInputChange = onInputChangeHandler;
    this.onSuccess = onSuccessHandler;
    this.defaultOptions = defaultOptions;
    this.useFilter = useFilter;
    this.onUp = onUpHandler;
    this.onDown = onDownHandler;
    this.onListElMouseDown = onListElMouseDownHandler;
    this.showNoMatches = showNoMatches;

    this.fireCount = 0;
    this.isIE = 0;
    this.isSafari = 0;
    if(navigator)
    {
      this.browser = navigator.userAgent.toLowerCase();
      if(this.browser.indexOf("safari") != -1)
      {
        this.isSafari = 1;
      }
      if(this.browser.indexOf("msie") != -1)
      {
        this.isIE = 1;
      }
    }
			
    //var blank_spot = ge('blank_spot');
    var blank_spot = rootEl;
    this.createDropDownContainer();
		this.createDropDown();
    this.createDefaultText();
    this.createDefaultDropDown();
    this.positionDropDown();
    var savior = document.createElement("div");
    savior.id = "savior";
    this.containerEl.id = "dropdown";
    this.goodFrame = null;
    if(rootEl)
    {
      if(blank_spot && this.isIE)
      {
        rootEl.appendChild(savior);
      }
      rootEl.appendChild(this.containerEl);
    }

    if(blank_spot == rootEl && this.isIE) 
    {
      var goodFrame = document.createElement('iframe');
      goodFrame.id = "goodFrame";
      goodFrame.style.width = "0px";
      goodFrame.style.height = "0px";
      goodFrame.style.zIndex = "98";
      blank_spot.insertBefore(goodFrame, blank_spot.firstChild);
      blank_spot.style.zIndex="99";
      this.goodFrame = goodFrame;
    }
	}
	
	var oThis = this;	
	this.init();

	if(!window.onresize)
	{
		window.onresize = function(event)
		{
			for(var idx in Registry)
			{
				Registry[idx].positionDropDown();
			}
		}
	}
	
	textBoxEl.onkeydown = function(event)
	{
		oThis.handleKeyDown(event);
	}
}

function debug(str)
{
	document.getElementById("debug").innerHTML += str + "<BR>";
}

// === Get/Hide/Show/Toggle ===

function ge()
{
  var ea;
  for( var i = 0; i < arguments.length; i++ ) {
    var e = arguments[i];
    if( typeof e == 'string' )
      e = document.getElementById(e);
    if( arguments.length == 1 )
      return e;
    if( !ea )
      ea = new Array();
    ea[ea.length] = e;
  }
  return ea;
}

function show()
{
  for( var i = 0; i < arguments.length; i++ ) {
    var element = ge(arguments[i]);
    if (element && element.style) element.style.display = '';
  }
  return false;
}

function hide()
{
  for( var i = 0; i < arguments.length; i++ ) {
    var element = ge(arguments[i]);
    if (element && element.style) element.style.display = 'none';
  }
  return false;
}

function shown(el) {
    el = ge(el);
    return (el.style.display != 'none');
}

function toggle()
{
  for( var i = 0; i < arguments.length; i++ ) {
    var element = ge(arguments[i]);
    element.style.display = (element.style.display == 'block') ? 'none' : 'block';
  }
  return false;
}

function remove_node(node)
{
  if (node.removeNode)
    node.removeNode(true);
  else {
    for (var i=node.childNodes.length-1; i>=0; i--)
      remove_node(node.childNodes[i]);
      node.parentNode.removeChild(node);
    }
  return null;
}

// === Event Info Access ===

function mouseX(event)
{
  return event.pageX || (event.clientX +
    (document.documentElement.scrollLeft || document.body.scrollLeft));
}

function mouseY(event)
{
  return event.pageY || (event.clientY +
    (document.documentElement.scrollTop || document.body.scrollTop));
}

function pageScrollX()
{
  return document.body.scrollLeft || document.documentElement.scrollLeft;
}

function pageScrollY()
{
  return document.body.scrollTop || document.documentElement.scrollTop;
}

function elementX(obj)
{
  var curleft = 0;
  if (obj.offsetParent) {
    while (obj.offsetParent) {
      curleft += obj.offsetLeft;
      obj = obj.offsetParent;
    }
  }
  else if (obj.x)
    curleft += obj.x;
  return curleft;
}

function elementY(obj)
{
  var curtop = 0;
  if(obj.offsetParent) {
    while (obj.offsetParent) {
      curtop += obj.offsetTop;
      obj = obj.offsetParent;
    }
  }
  else if (obj.y)
    curtop += obj.y;
  return curtop;
}

// === Onload Registry ===

var onloadRegistry = new Array();

function onloadRegister(handler)
{
  onloadRegistry.push(handler);
}

function onloadRun()
{
  for( var index in onloadRegistry )
    onloadRegistry[index]();
}

window.onload = onloadRun;

// === Placeholder Text ===

function placeholderSetup(id) {
	var el = ge(id);
	if(!el) return;
	if(el.type != 'text') return;
	if(el.type != 'text') return;
	
	var ph = el.getAttribute("placeholder");
	if( ph && ph != "" ) {
		el.value = ph;
		el.style.color = '#777';
		el.is_focused = 0;
		el.onfocus = placeholderFocus;
		el.onblur = placeholderBlur;
	}
}

function placeholderFocus() {
  if(!this.is_focused) {
    this.is_focused = 1;
    this.value = '';
    this.style.color = '#000';

    var rs = this.getAttribute("radioselect");
    if( rs && rs != "" ) {
      var re = document.getElementById(rs);
      if(!re) { return; }
      if(re.type != 'radio') return;

      re.checked=true;
    }
  }
}

function placeholderBlur() {
  var ph = this.getAttribute("placeholder")
  if( this.is_focused && ph && this.value == "" ) {
		this.is_focused = 0;
    this.value = ph;
    this.style.color = '#777';
  }
}

// === Log Stub ===

function Log(){};
Log.prototype.show = function (){alert('log disabled')};
Log.prototype.error = function (){};
Log.prototype.warning = function (){};
Log.prototype.note = function (){};
Log.prototype.time = function (){};
log = new Log();

// === String Utilities ===

function escapeQuotes(word) {

  // jsesq is a key/acronym for javascript escaped single quote
  // jsdsq is a key/acronym for javascript escaped double quote

  escaped = word.replace(/'/g, ":jsesq:"); 
  escaped = escaped.replace(/"/g, ":jsedq:"); 
  escaped = escaped.replace(/\[/g, ":jselb:"); 
  escaped = escaped.replace(/\]/g, ":jserb:"); 
  escaped = escaped.replace(/\\/g, ":jsebs:"); 

  return escaped;
}

function unescapeQuotes(word) {

  // jsesq is a key/acronym for javascript escaped single quote
  // jsdsq is a key/acronym for javascript escaped double quote

  escaped = word.replace(/:jsesq:/g, "'"); 
  escaped = escaped.replace(/:jsedq:/g, '"'); 
  escaped = escaped.replace(/:jselb:/g, '\['); 
  escaped = escaped.replace(/:jserb:/g, '\]'); 
  escaped = escaped.replace(/:jsebs:/g, '\\'); 

  return escaped;
}

// === URI Handling ===

function escapeURI(u)
{
    if(encodeURIComponent) {
        return encodeURIComponent(u);
    }
    if(escape) {
        return escape(u);
    }
}

function goURI(href) {
  window.location.href = href;
}

//13th parallel
function getViewportWidth() {
  var width = 0;
  if( document.documentElement && document.documentElement.clientWidth ) {
    width = document.documentElement.clientWidth;
  }
  else if( document.body && document.body.clientWidth ) {
    width = document.body.clientWidth;
  }
  else if( window.innerWidth ) {
    width = window.innerWidth - 18;
  }
  return width;
};

function getViewportHeight() {
  var height = 0;
  if( document.documentElement && document.documentElement.clientHeight ) {
    height = document.documentElement.clientHeight;
  }
  else if( document.body && document.body.clientHeight ) {
    height = document.body.clientHeight;
  }
  else if( window.innerHeight ) {
    height = window.innerHeight - 18;
  }
  return height;
};

// === Deprecated ===
// --- Delete checkAgree when user profile picture editing moves to picture widget

function checkAgree() {
  if (document.frm.pic.value) {
    if (document.frm.agree.checked) {
      document.frm.submit();
    } else {
      show("error");
    }
  }
}

function isIE() {
 return (navigator.userAgent.toLowerCase().indexOf("msie") != -1);
}   
    
function getTableRowShownDisplayProperty() {
  if (isIE()) {
    return  'inline';
  } else {
    return 'table-row';
  }
}
  
function showTableRow()
{ 
  for( var i = 0; i < arguments.length; i++ ) {
    var element = ge(arguments[i]);
    if (element && element.style) element.style.display =
        getTableRowShownDisplayProperty();
  }
  return false;
} 
  
function getParentRow(el) {
    el = ge(el);
    while (el.tagName && el.tagName != "TR") {
        el = el.parentNode;
    }
    return el;
} 

function stopPropagation(e) {
    if (!e) var e = window.event;
    e.cancelBubble = true;
    if (e.stopPropagation) {
        e.stopPropagation();
    }
}

function show_standard_status(status) {
  s = ge('standard_status');
  if (s) {
    var header = s.firstChild;
    header.innerHTML = status;
    show('standard_status');
  }
}

function remove_node(node) {
  if (node.removeNode)
    node.removeNode(true);
  else {
    for (var i=node.childNodes.length-1; i>=0; i--)
      remove_node(node.childNodes[i]);
    node.parentNode.removeChild(node);
  }
  return null;
}

function adjustImage(obj, stop_word, max) {
  
  var pn=obj.parentNode;

  if (stop_word==null)
    stop_word='note_content';
  if (max==null) {
    while (pn.className.indexOf(stop_word)==-1)
      pn=pn.parentNode;
    if (pn.offsetWidth)
      max=pn.offsetWidth;
    else
      max=400;
  }

  obj.className=obj.className.replace('img_loading', 'img_ready');

  if (obj.width>max) {
    if (window.ActiveXObject) {
      try {
        var img_div=document.createElement('div');
        img_div.style.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src="' + obj.src.replace('"', '%22') + '", sizingMethod="scale")';
        img_div.style.width=max+'px';
        img_div.style.height=((max/obj.width)*obj.height)+'px';
        if (obj.parentNode.tagName=='A')
          img_div.style.cursor='pointer';
        obj.parentNode.insertBefore(img_div, obj);
        obj.removeNode(true);
      }
      catch (e) {
        obj.style.width=max+'px';
      }
    }
    else
      obj.style.width=max+'px';
  }
}

function set_opacity(obj, opacity) {
  try {
    obj.style.opacity=(opacity==1?'':opacity);
    obj.style.filter=(opacity==1?'':'alpha(opacity='+opacity*100+')');
  }
  catch (e) {}
}

function focus_login() {
  var email = ge("email");
  var pass = ge("pass");
  var dologin = ge("doquicklogin");
  if (email && pass) {
    if (email.value != "" && pass.value == "") {
      pass.focus();
    } else if (email.value == "") {
      email.focus();
    } else if (email.value != "" && pass.value != "") {
      dologin.focus();
    }
  }
}

function change_network(n_id, autosubmit)
{
  if(n_id == 'other') {
    hide('search_within');
    ge('sq').value = '';
    ge('n_selector').style.display = 'block';
    ge('sq').focus();
  } else {
    ge('n').value = n_id;
    if(autosubmit) {
      ge('search').submit();
    }  
  }
}

var Suggest = function(rootEl, q, formEl, textBoxEl, idEl, uri, param, successHandler, instructions, networkType, placeholderText, defaultOptions, showNoMatches, override_resize)
{
  this.onInputChange = function()
  {
    var currentInputValue = oThis.typeAheadObj.currentInputValue;
		var cache = oThis.getCache(currentInputValue);
		if(cache)
		{
			oThis.onSuggestRequestDone(currentInputValue, cache[0], cache[1], cache[2]);
		}
		else
		{
      var typeStr = "";
      if(oThis.networkType)
      {
        typeStr = "&t=" + oThis.networkType;
      }
			var q = escapeURI(currentInputValue);
			var ajax = new Ajax(oThis.onAjaxDone, oThis.onAjaxFail);
			ajax.key = currentInputValue;
      ajax.pEvent = oThis.typeAheadObj.pEvent;
			ajax.get(oThis.suggestURI, oThis.suggestParam + "=" + q + typeStr);
		}
  }

	this.onAjaxFail = function()
	{
//		alert("ajax call failed");
	}
	
	this.onAjaxDone = function(ajaxObj, responseText)
	{
		var suggestNames = [];
		var suggestIDs = [];
    var suggestLocs = [];
		eval(responseText);
		oThis.onSuggestRequestDone(ajaxObj.key, suggestNames, suggestIDs, suggestLocs, ajaxObj.pEvent);
	}

	this.onSuggestRequestDone = function(key, names, ids, locs, pEvent)
	{
		this.setCache(key, names, ids, locs);
		if(this.typeAheadObj.displaySuggestList(names, ids, locs))
		{
      this.typeAheadObj.pEvent = pEvent;
			this.typeAheadObj.onListChange();
		}
	}
	
	this.getCache = function(key)
	{
		return this.suggestCache[key.toUpperCase()];
	}

	this.setCache = function(key, names, ids, locs)
	{
		this.suggestCache[key.toUpperCase()] = new Array(names, ids, locs);
	}

	this.init = function()
	{	
		this.suggestURI = uri;
		this.suggestParam = param;
		this.suggestCache = [];
    this.networkType = networkType;
    if(!instructions)
    {
      instructions = "Type to select a network";
    }

    if(!defaultOptions)
    {
   //   defaultOptions = {"All of Facebook": -1};
    }
    else
    {
    //  defaultOptions['All of Facebook'] = -1;
    }

    this.typeAheadObj = new TypeAhead(rootEl, formEl, textBoxEl, idEl, defaultOptions, instructions, 0, successHandler, this.onInputChange, null, null, null, placeholderText, showNoMatches, override_resize);
    this.typeAheadObj.setText(q);
  }

	var oThis = this;	
	this.init();
}

function debug(str)
{
	document.getElementById("debug").innerHTML += str + "<BR>";
}

function Ajax(doneHandler, failHandler)
{
  newAjax = this;
  this.onDone = doneHandler;
  this.onFail = failHandler;
  this.transport = this.getTransport();
  this.transport.onreadystatechange = ajaxTrampoline(this);
}
Ajax.prototype.get = function (uri, query)
{
  if( typeof query != 'string' )
    query = ajaxArrayToQueryString(query);
  fullURI = uri+(query ? ('?'+query) : '');
  this.transport.open('GET', fullURI, true );
  this.transport.send('');
}

Ajax.prototype.post = function (uri, data)
{
  if( typeof data != 'string' )
    data = ajaxArrayToQueryString(data);
  var post_form_id=ge('post_form_id');
  if (post_form_id)
    data+='&post_form_id='+post_form_id.value;
  this.transport.open('POST', uri, true);
  this.transport.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  this.transport.send(data);
}

Ajax.prototype.stateDispatch = function ()
{
  if( this.transport.readyState == 1 && this.showLoad )
    ajaxShowLoadIndicator();
  
  if( this.transport.readyState == 4 ) {
    if( this.showLoad )
      ajaxHideLoadIndicator();
    if( this.transport.status >= 200 &&
        this.transport.status < 300 &&
        this.transport.responseText.length > 0 ) {
      if( this.onDone ) this.onDone(this, this.transport.responseText);
    } else {
      if( this.onFail ) this.onFail(this);
    }
  }
}

Ajax.prototype.getTransport = function ()
{
  var ajax = null;
  
  try { ajax = new XMLHttpRequest(); }
  catch(e) { ajax = null; }
  
  try { if(!ajax) ajax = new ActiveXObject("Msxml2.XMLHTTP"); }
  catch(e) { ajax = null; }
  
  try { if(!ajax) ajax = new ActiveXObject("Microsoft.XMLHTTP"); }
  catch(e) { ajax = null; }
  
  return ajax;
}

function ajaxTrampoline(ajaxObject)
{
  return function () { ajaxObject.stateDispatch(); };
}

function ajaxArrayToQueryString(queryArray)
{
  var sep = '';
  var query = "";
  
  for( var key in queryArray ) {
    query = query +
      sep +
      encodeURIComponent(key) +
      '=' +
      encodeURIComponent(queryArray[key]);
    sep = '&';
  }
  return query;
}

var ajaxLoadIndicatorRefCount = 0;

function ajaxShowLoadIndicator()
{
  indicatorDiv = ge('ajaxLoadIndicator');
  if( !indicatorDiv ) {
    indicatorDiv = document.createElement("div");
    indicatorDiv.id = 'ajaxLoadIndicator';
    indicatorDiv.innerHTML = 'Loading';
    indicatorDiv.className = 'ajaxLoadIndicator';
    document.body.appendChild(indicatorDiv);
  }
  
  indicatorDiv.style.top = (5 + pageScrollY()) + 'px';
  indicatorDiv.style.left = (5 + pageScrollX()) + 'px';
  indicatorDiv.style.display = 'block';
  ajaxLoadIndicatorRefCount++;
}

function ajaxHideLoadIndicator()
{
  ajaxLoadIndicatorRefCount--;
  if( ajaxLoadIndicatorRefCount == 0 )
    ge('ajaxLoadIndicator').style.display = '';
}
