// BEGIN FLOCK GPL
//
// Copyright Flock Inc. 2005-2009
// http://flock.com
//
// This file may be used under the terms of the
// GNU General Public License Version 2 or later (the "GPL"),
// http://www.gnu.org/licenses/gpl.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// END FLOCK GPL

Cu.import("resource:///modules/FlockPrefsUtils.jsm");

const SELECTED_SEARCH_ENGINE_PREF = "browser.search.selectedEngine";
const SEARCH_ELSEWHERE_PREF = "flock.search.elsewhereEngines";
const LIVE_SEARCH_PREF = "flock.liveSearch.enabledServices";

const PLACEHOLDER_ICON = "chrome://flock/skin/search/placeholderIcon16.png";

const SEARCH_AREA_SUFFIX = "_SearchResults";
const LIVESEARCH_CONTAINER_SUFFIX = "liveSearch_";

var searchFlyout = {

  init: function() {
    this._logger = Cc["@flock.com/logger;1"].createInstance(Ci.flockILogger);
    this._logger.init("searchflyout");

    this.mFlyout = document.getElementById("searchFlyout");
    this.mIsOpen = false;

    this.prefs = Cc["@mozilla.org/preferences-service;1"]
                 .getService(Ci.nsIPrefBranch2);
    this.prefs.addObserver("flock.liveSearch.enabledServices", this, false);
  },
  
  uninit: function() {
    this.prefs.removeObserver("flock.liveSearch.enabledServices", this);
  },
  
  focus: function() {
    this.mFlyout.focus();
  },
  
  hide: function() {
    this._logger.debug("hiding the flyout");
    this.mFlyout.hidePopup();
  },
  
  show: function() {
    if (this.isOpen()) {
      return;
    }
    this._logger.debug("showing the flyout");
    searchbarController.updateSearchElsewhere();
    searchbarController.updateNavigatableResults();
    searchbarController.clearSelection();
    this.mFlyout.showPopup(document.getElementById("searchbar"),
                           -1,
                           -1,
                           "popup",
                           "bottomleft",
                           "topleft");
  },
  
  toggle: function() {
    if (this.isOpen()) {
      this.hide();
    } else {
      searchbarController.focus();
      this.show();
    }
  },
  
  isOpen: function() {
    return this.mIsOpen;
  },
  
  observe: function(aSubject, aTopic, aData) {
    if (aData == LIVE_SEARCH_PREF) {
      var services = this.prefs.getCharPref(LIVE_SEARCH_PREF);
      var serviceList = services.replace(/,(?:\s*)$/, "").split(",");
      LiveSearchBuilder.removeUnneededLiveSearchService(serviceList);
      searchbarController.doLiveSearch(searchbarController.mSearchbar.value);
    }
  },
  
  handleEvent: function(aEvent) {
    switch (aEvent.type) {
      case "load":
        this.init();
        break;
      case "unload":
        this.uninit();
        break;
    }
  }
};

var searchbarController = {

  debugLog: function(debugMessage) {
    if ("_logger" in this) {
      this._logger.debug(debugMessage);
    }
  },

  mSearchTimer: null,
  mCurrentIndex: null,
  mResults: null,
  mSelectedItem: null,
  mSearchbar: null,
  mFlyoutXULContainer: null,
  mPrefService: null,
  mSearchMgrService: null,
  mSearchElsewhereXulContainer: null,

  _bundle: null,

  init: function() {
    this.mSearchbar = document.getElementById("searchbar");
    // We're not on the toolbar
    if (!this.mSearchbar) {
      return;
    }
    this._logger = Cc["@flock.com/logger;1"].createInstance(Ci.flockILogger);
    this._logger.init("searchbarcontroller");
    this._metrics = Cc["@flock.com/metrics-service;1"]
                    .getService(Ci.flockIMetricsService);
    this.debugLog("init");
    this.mFlyout = document.getElementById("searchFlyout");
    this.addEventListeners();
    this.mCurrentIndex = -1;
    this.mResults = []; // used for keyboard navigation of results rows
    this.mFlyoutXULContainer = document.getElementById("flyoutContainer");
    this.mSearchElsewhereXulContainer = document.getElementById("searchElsewhereContainer");
    this.mSearchMgrService = Cc["@flock.com/search-manager;1"].getService(Ci.flockISearchManager);

    this.mSearchTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
    this.mInitTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
    this.mShowFlyoutTimer = Cc["@mozilla.org/timer;1"]
                            .createInstance(Ci.nsITimer);
    this.mPrefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefService);
    this.mPrefBranch = this.mPrefService.QueryInterface (Ci.nsIPrefBranch2);
    this.mPrefBranch.addObserver(SELECTED_SEARCH_ENGINE_PREF, this, false);
    this.mPrefBranch.addObserver(SEARCH_ELSEWHERE_PREF, this, false);
    var sbs = CC["@mozilla.org/intl/stringbundle;1"]
              .getService(CI.nsIStringBundleService);
    var sprop = "chrome://flock/locale/search/search.properties";
    this._bundle = sbs.createBundle(sprop);

    // reference rdf services
    this.mRDFService = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
    this.mRdfContainerUtils = Cc["@mozilla.org/rdf/container-utils;1"].getService(Ci.nsIRDFContainerUtils);

    this.doLiveSearch(null);
    this.updateNavigatableResults();
    this.mInitTimer.initWithCallback(this, 50, Ci.nsITimer.TYPE_ONE_SHOT);
  },
  
  uninit: function() {
    // We're not on the toolbar
    if (!this.mSearchbar) {
      return;
    }
    this.debugLog("uninit");
    this.mPrefService.removeObserver(SELECTED_SEARCH_ENGINE_PREF, this);
    this.mPrefBranch.removeObserver(SEARCH_ELSEWHERE_PREF, this);
    this.removeListeners();

    // null created timers
    this.mSearchTimer = null;
    this.mInitTimer = null;
    this.mShowFlyoutTimer = null;
  },
  
  handleEvent: function(aEvent) {
    this.debugLog("handleEvent: type = " + aEvent.type);
    switch (aEvent.type) {
      case "load":
        this.init();
        break;
      case "unload":
        this.uninit();
        break;
      case "blur":
        searchFlyout.hide();
        break;
      case "input":
        this.mSearchTimer.cancel();
        this.mSearchTimer.initWithCallback(this, 500, Ci.nsITimer.TYPE_ONE_SHOT);
        this.mShowFlyoutTimer
            .initWithCallback(this, 10, Ci.nsITimer.TYPE_ONE_SHOT);
        break;
      case "keypress":
        this.handleKeyInput(aEvent);
        break;
      case "select":
        // this event is for tab selection change
        searchFlyout.hide();
        break;
      case "focus":
        //this.mSearchbar.select();
        break;
    }
  },

  doLiveSearch: function(aSearchText) {
    var theEnum = this.mSearchMgrService.enabledServices;
    while (theEnum.hasMoreElements()) {
      var service = theEnum.getNext();
      LiveSearchBuilder.addLiveSearchServiceBox(service.serviceName,
                                                service.shortName);
    }
    if (aSearchText != null && aSearchText.length > 0) {
      this.mSearchMgrService.search(aSearchText, 4,
                                    LiveSearchBuilder.searchCallback);
    } else {
      if (service) {
        LiveSearchBuilder.addEmptyResults(service.shortName);
      }
    }
    this.clearSelection();
  },

  handleKeyInput: function(aEvent) {
    this.debugLog("handleKeyInput: keyCode = " + aEvent.keyCode + " charCode = " + aEvent.charCode);
    if (aEvent.metaKey || aEvent.ctrlKey || aEvent.altKey) {
      return;
    }
    if (aEvent.keyCode == KeyEvent.DOM_VK_ESCAPE) {
      searchFlyout.hide();
      aEvent.stopPropagation();
      aEvent.preventDefault();
      return;
    }
    if (aEvent.charCode != 0 ||
        aEvent.keyCode == KeyEvent.DOM_VK_BACK_SPACE ||
        aEvent.keyCode == KeyEvent.DOM_VK_DELETE)
    {
      this.mSearchTimer.cancel();
      this.mSearchTimer.initWithCallback(this, 500, Ci.nsITimer.TYPE_ONE_SHOT);
      searchFlyout.show();
    } else if (aEvent.keyCode == KeyEvent.DOM_VK_TAB) {
      searchFlyout.hide();
    } else if (aEvent.keyCode == KeyEvent.DOM_VK_DOWN) {
      if (searchFlyout.isOpen()) {
        this.selectNextItem();
      } else {
        searchFlyout.show();
      }
      aEvent.stopPropagation();
      aEvent.preventDefault();
    } else if (aEvent.keyCode == KeyEvent.DOM_VK_UP) {
      if (searchFlyout.isOpen()) {
        this.selectPreviousItem();
      }
      aEvent.stopPropagation();
      aEvent.preventDefault();
    } else if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN ||
               aEvent.keyCode == KeyEvent.DOM_VK_ENTER)
    {
      // check if our live results has a selected item from key navigation
      var selectedItem = this.getItemAtIndex(this.mCurrentIndex);
      if (selectedItem && selectedItem.id) {
        if (selectedItem.id == "prefs") {
          openPreferences("paneSearching");
        } else if (selectedItem.hasAttribute("searchElsewhere")) {
          var engineName = selectedItem.getAttribute("searchElsewhere");
          this._metrics.report("SearchBox-FlyoutSearchElsewhere", engineName);
          var url = this.getSearchElsewhereQString(engineName);
          openUILinkIn(url,
                       getBoolPref("browser.search.openintab") ? "tab"
                                                               : "current");
        } else {
          if (selectedItem.hasAttribute("liveSearchFullResults")) {
            var shortName = selectedItem.getAttribute("liveSearchFullResults");
            this._metrics.report("SearchBox-FlyoutLiveSearchFullResults",
                                 shortName);
          } else if (selectedItem.hasAttribute("liveSearchResult")) {
            var shortName = selectedItem.getAttribute("liveSearchResult");
            this._metrics.report("SearchBox-FlyoutLiveSearch", shortName);
          }
          openUILinkIn(selectedItem.getAttribute("url"),
                       getBoolPref("browser.search.openintab") ? "tab" : "current" );
        }
        aEvent.stopPropagation();
      }
      else {
        // Nothing was selected from the flyout so it must be a search
        this._metrics.report("Search", this.mSearchbar.currentEngine.name);
      }
      searchFlyout.hide();
    } else {
      this.debugLog("handleKeyInput: Unhandled keyCode = " + aEvent.keyCode);
    }
  },

  selectNextItem: function() {
    if (this.mCurrentIndex == this.mResults.length - 1) {
      this.mCurrentIndex = 0;
    } else {
      this.mCurrentIndex++;
    }
    this.selectItemAtIndex(this.mCurrentIndex);
  },

  selectPreviousItem: function() {
    if (this.mCurrentIndex == -1) {
      this.mSelectedItem = null;
      return;
    }
    if (this.mCurrentIndex == 0) {
      this.mCurrentIndex = this.mResults.length - 1;
    } else {
      this.mCurrentIndex--;
    }
    this.selectItemAtIndex(this.mCurrentIndex);
  },

  selectItemAtIndex: function(aIndex) {
    if (this.mSelectedItem) {
      this.mSelectedItem.removeAttribute("selected");
    }

    var selectedItem = this.getItemAtIndex(aIndex);
    if (selectedItem) {
      this.mSelectedItem = selectedItem;
      this.mSelectedItem.setAttribute("selected", true);
    }
    this._logger.debug("selectItemAtIndex: aIndex = " + aIndex + " mSelectedItem = " + this.mSelectedItem.getAttribute("url"));
  },
  
  selectItem: function(aItem) {
    var itemIndex;
    for (var c = 0; c < this.mResults.length; c++) {
      if (this.mResults[c] == aItem) {
        itemIndex = c;
        break;
      }
    }
    if (this.mSelectedItem) {
      this.mSelectedItem.removeAttribute("selected");
    }
    this.mSelectedItem = aItem;
    this.mCurrentIndex = itemIndex;
    this.mSelectedItem.setAttribute("selected", true);
    this._logger.debug("selectItem: aItem = " + this.mSelectedItem + " mSelectedItem = " + this.mSelectedItem.getAttribute("url"));
  },
  
  clearSelection: function() {
    if (this.mSelectedItem) {
      this.mSelectedItem.removeAttribute("selected");
      this.mSelectedItem = null;
      this.mCurrentIndex = -1;
    }
  },

  getItemAtIndex: function(aIndex) {
    return this.mResults[aIndex];
  },
  
  focus: function() {
    this.mSearchbar.focus();
  },

  updateNavigatableResults: function() {
    var results = this.mFlyout.getElementsByAttribute("result", "true");
    var items = [];
    for (var j = 0; j < results.length; j++) {
      items.push(results[j]);
    }
    this.mResults = items;
  },

  addEventListeners: function() {
    this.debugLog("addEventListeners");
    this.mSearchbar.addEventListener("keypress", this, true);
    this.mSearchbar.addEventListener("focus", this, true);
    this.mSearchbar.addEventListener("input", this, true);
    this.mSearchbar.addEventListener("blur", this, true);
    document.getElementById("content").tabContainer.addEventListener("select", this, false);
    //window.addEventListener("click", this, true);
  },

  removeListeners: function() {
    this.debugLog("removeListeners");
    this.mSearchbar.removeEventListener("keypress", this, true);
    this.mSearchbar.removeEventListener("focus", this, true);
    this.mSearchbar.removeEventListener("input", this, true);
    this.mSearchbar.removeEventListener("blur", this, true);
    document.getElementById("content").tabContainer.removeEventListener("select", this, false);
    //window.removeEventListener("click", this, true);
  },

  updateSearchElsewhere: function() {
    this.debugLog("updateSearchElsewhere");
    var theEnum = this.mSearchMgrService.searchElsewhereList;

    var kids = this.mSearchElsewhereXulContainer.childNodes;
    for (var i = kids.length - 1; i >= 0; i--) {
      if (!(kids[i].getAttribute("dontDelete"))) {
        this.mSearchElsewhereXulContainer.removeChild(kids[i]);
      }
    }

    if (theEnum.hasMoreElements()) {
      document.getElementById("engineResultsContainer").removeAttribute("hidden");
    } else {
      document.getElementById("engineResultsContainer").setAttribute("hidden", "true");
    }

    while (theEnum.hasMoreElements()) {
      var engineItem = theEnum.getNext();
      engineItem.QueryInterface(Ci.nsISearchEngine);
      var hbox = document.createElement("hbox");
      var label = document.createElement("label");
      var icondiv = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
      var icon = document.createElementNS("http://www.w3.org/1999/xhtml", "img");
      icondiv.appendChild(icon);
      var url = this.getSearchElsewhereQString(engineItem.name);
      this.mSearchElsewhereXulContainer.appendChild(hbox);
      hbox.setAttribute("result", true);
      hbox.setAttribute("class", "flock-result");
      hbox.appendChild(icondiv);
      hbox.appendChild(label);
      hbox.setAttribute("onmouseover", "searchbarController.selectItem(this);");
      hbox.setAttribute("onmouseout", "searchbarController.clearSelection();");
      hbox.setAttribute("onclick",
                        "Components.classes['@flock.com/metrics-service;1']" 
                        + ".getService(Components.interfaces.flockIMetricsService)" 
                        + ".report('SearchBox-FlyoutSearchElsewhere', '" + engineItem.name + "');" +
                        "var url = searchbarController.getSearchElsewhereQString('"+engineItem.name+"');"
                        + "if (getBoolPref('browser.search.openintab')) {"
                        + "  openUILinkIn(url, 'tab');"
                        + "} else {"
                        + "  openUILink(url, event);"
                        + "}" );
      hbox.setAttribute("id", engineItem.name + "fullResults");
      hbox.setAttribute("searchElsewhere", engineItem.name);
      icon.setAttribute("src", engineItem.iconURI ? engineItem.iconURI.spec
                                                  : PLACEHOLDER_ICON);
      label.setAttribute("value", engineItem.name);
      label.setAttribute("class", "primary-result");
    }
  },

  getSearchElsewhereQString: function(aEngineName) {
    this.debugLog("getSearchElsewhereQString: aEngineName = " + aEngineName);
    var engine = this.mSearchbar.searchService.getEngineByName(aEngineName);
    if (!engine) {
      return null;
    }
    var query = this.mSearchbar.value;
    engine.QueryInterface(Ci.flockISearchEngine);
    var searchSubmission = engine.getSubmissionByContext(query, null, "l");
    var itemActionString = searchSubmission.uri.spec;
    return itemActionString;
  },
  
  notify: function(aTimer) {
    if (aTimer == this.mSearchTimer) {
      this.doLiveSearch(this.mSearchbar.value);
      aTimer.cancel();
    } else if (aTimer == this.mInitTimer) {
      this.updateSearchElsewhere();
    } else if (aTimer == this.mShowFlyoutTimer) {
      searchFlyout.show();
    }
  },
  
  observe: function(aSubject, aTopic, aData) {
    this.debugLog("observe: aTopic = " + aTopic);
    if (aTopic == "nsPref:changed") {
      switch (aData) {
        case SELECTED_SEARCH_ENGINE_PREF:
          this.mSearchbar.currentEngine =
            this.mSearchbar.searchService.currentEngine;
          break;

        case SEARCH_ELSEWHERE_PREF:
          this.updateSearchElsewhere();
          break;

        default:
          break;
      }
    }

    this.updateNavigatableResults();
  }
};

var LiveSearchBuilder = {
  searchCallback: {
    foundResults: function LSBSC_foundResults(aResults, aShortName, aQuery) {
      var count = aResults.length;
      if (count == 0) {
        LiveSearchBuilder.addEmptyResults(aShortName);
      } else {
        LiveSearchBuilder.updateLiveSearchResults(aShortName, aResults);
      }
      var resultBox = document.getElementById(aShortName + SEARCH_AREA_SUFFIX);
      if (!resultBox) {
        return;
      }
      resultBox.setAttribute("empty", count == 0);
      resultBox.removeAttribute("busy");

      // create the view all results item
      var hbox = document.createElement("hbox");
      var label = document.createElement("label");
      var service = searchbarController.mSearchMgrService
                                       .getServiceFromShortname(aShortName);
      if (service && count > 0) {
        var engineQString = service.getFullResultsURL(aQuery);
        if (engineQString) {
          hbox.setAttribute("result", true);

          hbox.onclick = function itemAction(aEvent) {
            if (getBoolPref("browser.search.openintab", false)) {
              openUILinkIn(engineQString, "tab");
            } else {
              openUILink(engineQString, aEvent);
            }
            Cc["@flock.com/metrics-service;1"]
              .getService(Ci.flockIMetricsService)
              .report("SearchBox-FlyoutLiveSearchFullResults", aShortName);
            document.getElementById("searchFlyout").hidePopup();
            aEvent.preventDefault();
          };
          label.setAttribute("value", flockGetString("search/search",
                                                     "flock.search.showAll",
                                                     [service.serviceName]));
          hbox.appendChild(label);
          hbox.setAttribute("onmouseover",
                            "searchbarController.selectItem(this);");
          hbox.setAttribute("onmouseout",
                            "searchbarController.clearSelection();");
          hbox.setAttribute("id", service.shortName+"FullResults");
          hbox.setAttribute("liveSearchFullResults", aShortName);
          hbox.setAttribute("url", engineQString);
          hbox.setAttribute("class", "view-all-results flock-result");

          // so its accessible by our key nav
          hbox.setAttribute("result", "true");

          resultBox.appendChild(hbox);
        }
      }
      searchbarController.updateNavigatableResults();
    },

    searchStarted: function sc_searchStarted(aShortName) {
      dump(aShortName + " search started >>> \n");
      var liveSearchElem = document.getElementById(aShortName);
      if (liveSearchElem) {
        liveSearchElem.firstChild.nextSibling.firstChild.hidden = false;
        liveSearchElem.removeAttribute("empty");
        liveSearchElem.setAttribute("busy", true);
      }
    }
  },
  // Removes old results from the Service's SearchResult area in the UI
  removeLiveSearchResults: function lsb_remove(aServiceName) {
    var oldResult = document.getElementById(aServiceName + SEARCH_AREA_SUFFIX);
    if (oldResult) {
      while (oldResult.hasChildNodes()) {
        oldResult.removeChild(oldResult.firstChild);
      }
    }
    return oldResult;
  },

  // Gets the Service's SearchResult area if it exists, otherwise it creates a
  // new SearchResult area for the Service 
  getLiveSearchServiceContainer:function lsb_getSeachContainer(aServiceName) {
    var resultContainer = this.removeLiveSearchResults(aServiceName);
    if (!resultContainer) {
      resultContainer = document.createElement("vbox");
      resultContainer.setAttribute("id", aServiceName + SEARCH_AREA_SUFFIX);
      resultContainer.setAttribute("flex", "1");
      resultContainer.setAttribute("class", "search-results-container");
      resultContainer.setAttribute("service", aServiceName);
      searchbarController.mFlyoutXULContainer.appendChild(resultContainer);
    }
    return resultContainer;
  },

  // Updates the live results retrieve from the service
  updateLiveSearchResults: function LSB_update(aServiceName, aSearchResults) {
    var resultContainer = this.getLiveSearchServiceContainer(aServiceName);

    for (var i = 0; i < aSearchResults.length; i++) {
      var res = aSearchResults[i];
      var hbox = document.createElement("hbox");
      hbox.setAttribute("id", res.url);
      hbox.setAttribute("liveSearchResult", aServiceName);
      hbox.setAttribute("class", "flock-result");
      hbox.setAttribute("result", "true");
      hbox.setAttribute("flex", "1");
      hbox.setAttribute("url", res.url);
      hbox.setAttribute("onmouseover", "searchbarController.selectItem(this);");
      hbox.setAttribute("onmouseout", "searchbarController.clearSelection();");
      hbox.onclick = function onClickSearchResults(aEvent) {
        var url = this.getAttribute("url");
        Cc["@flock.com/metrics-service;1"]
        .getService(Ci.flockIMetricsService)
        .report("SearchBox-FlyoutLiveSearch", aServiceName);
        if (getBoolPref("browser.search.openintab")) {
          openUILinkIn(url, "tab");
        } else {
          openUILink(url, aEvent);
        }
        document.getElementById("searchFlyout").hidePopup();
        aEvent.preventDefault();
      };

      var favicon = document.createElement("image");
      favicon.setAttribute("class", "searchflyout-favicon");
      favicon.setAttribute("src", res.icon);
      hbox.appendChild(favicon);
      var title = document.createElement("label");
      title.setAttribute("class", "searchflyout-label");
      title.setAttribute("crop", "end");
      title.setAttribute("value", res.title);
      title.setAttribute("tooltiptext", res.url);
      hbox.appendChild(title);

      if (res.category) {
        var catContainer = document.createElement("hbox");
        catContainer.setAttribute("class", "subcat-container");
        catContainer.setAttribute("flex", "1");
        var catTitle = document.createElement("box");
        catTitle.setAttribute("flex", "1");
        catTitle.setAttribute("class", "subcat-title");
        var cTitle = document.createElement("label");
        cTitle.setAttribute("flex", "1");
        cTitle.setAttribute("value", res.category);
        catTitle.appendChild(cTitle);
        catContainer.appendChild(catTitle);
        catContainer.appendChild(hbox);
        resultContainer.appendChild(catContainer);
      } else {
        resultContainer.appendChild(hbox);
      }
    }
  },

  // Adds the Service Live Search Category Title to the UI
  addLiveSearchServiceBox: function lsb_add(aServiceName, aShortName)
  {
    var service_id = LIVESEARCH_CONTAINER_SUFFIX + aShortName;
    if (document.getElementById(service_id)) {
      return;
    }
    var hbox = document.createElement("hbox");
    hbox.setAttribute("class", "result-container");
    hbox.setAttribute("flex", "flex");
    hbox.setAttribute("id", service_id);
    // Child box
    var c_box = document.createElement("box");
    c_box.setAttribute("class", "search-results-title");
    var service = document.createElement("label");
    service.setAttribute("class", "livesearch-engine-title");
    service.setAttribute("value", aServiceName);
    c_box.appendChild(service);
    hbox.appendChild(c_box);
    searchbarController.mFlyoutXULContainer.appendChild(hbox);
    this.addEmptyResults(aShortName);
  },

  // Adds the Empty results label
  addEmptyResults: function LSS_addEmptyResults(aShortName) {
    var resultContainer = this.getLiveSearchServiceContainer(aShortName);
    var noResultLabel = document.createElement("label");
    noResultLabel.setAttribute("class", "no-results-found");
    var noResultText =
      searchbarController._bundle.GetStringFromName("flock.search.noResults");
    noResultLabel.setAttribute("value", noResultText);
    resultContainer.appendChild(noResultLabel);
  },

  removeUnneededLiveSearchService:
  function lss_removeUnneededLiveSearchService(aServiceList) {
    for (var c in searchbarController.mFlyoutXULContainer.childNodes) {
      var found = false;
      var serviceBox = searchbarController.mFlyoutXULContainer.childNodes[c];
      if (!serviceBox ||
          !(serviceBox instanceof Ci.nsIDOMElement) ||
          !(serviceBox.hasAttribute("service")))
      {
        continue;
      }
      for each (service in aServiceList) {
        if (serviceBox.getAttribute("service") == service) {
          found = true;
        }
      }
      if (!found) {
        var service = serviceBox.getAttribute("service");
        this.removeLiveSearchResults(service);
        var serviceId = LIVESEARCH_CONTAINER_SUFFIX + service;
        var liveSearchContainer = document.getElementById(serviceId);
        if (liveSearchContainer) {
          searchbarController.mFlyoutXULContainer
                             .removeChild(liveSearchContainer);
        }
        searchbarController.mFlyoutXULContainer.removeChild(serviceBox);
      }
    }
  }
};

var FlockSearch = {};

FlockSearch.updatePopup =
function FlockSearch_updatePopup() {
  var searchButton = document.getElementById("favoritesSearchButton");

  // Clear out the old menuitems
  var container = searchButton.firstChild;
  while (container.lastChild) {
    container.removeChild(container.lastChild);
  }
  
  var searchService = Cc["@mozilla.org/browser/search-service;1"].getService(Ci.nsIBrowserSearchService);
  var newMenuItem, miObj;
  var engines = gBrowser.mCurrentBrowser.engines;
  if (engines && engines.length > 0) {
    for (var c = 0; c < engines.length; c++) {
      newMenuItem = document.createElement("menuitem");
      miObj = {
        class: "menuitem-iconic",
        label: engines[c].title,
        oncommand: "FlockSearch.addEngine(this); FlockSearch.updateMessage(); event.stopPropagation();",
        src: engines[c].icon,
        uri: engines[c].uri
      };
      if (searchService.getEngineByName(engines[c].title)) {
        miObj.image = "chrome://flock/skin/common/star16.png";
        miObj.disabled = "true";
      }
      for (p in miObj) {
        newMenuItem.setAttribute(p, miObj[p]);
      }
      newMenuItem.setAttribute("discovered", "false");
      searchButton.firstChild.appendChild(newMenuItem);
    }
  }
}

FlockSearch.updateMessage =
function FlockSearch_updateMessage() {
  var nBox = gBrowser.getNotificationBox(); 
  nBox.removeCurrentNotification("search-discovered");
  
  var brand = brandGetString("brand", "brandShortName");
  var message = flockGetString("search/search",
                               "flock.search.engine.added",
                               [brand, brand]);
  nBox.appendUniqueNotification(message,
                                  "search-discovered-info",
                                  (document.getElementById("page-proxy-favicon"))?document.getElementById("page-proxy-favicon").src:null,
                                  nBox.FLOCK_PRIORITY_MEDIUM,
                                  null);
}

FlockSearch.addEngine =
function FlockSearch_addEngine(aTarget) {
  var searchService = Cc["@mozilla.org/browser/search-service;1"]
                      .getService(Ci.nsIBrowserSearchService);
  var type = Ci.nsISearchEngine.DATA_XML;
  searchService.addEngine(aTarget.getAttribute("uri"),
                          type,
                          aTarget.getAttribute("src"),
                          true);
  var elsewhereList =
    FlockPrefsUtils.getLocalizedPref(SEARCH_ELSEWHERE_PREF, "").split(",");
  elsewhereList.push(aTarget.getAttribute("label"));
  FlockPrefsUtils.setLocalizedPref(SEARCH_ELSEWHERE_PREF,
                                   elsewhereList.join(","));
};

window.addEventListener("load", searchFlyout, false);
window.addEventListener("unload", searchFlyout, false);

window.addEventListener("load", searchbarController, false);
window.addEventListener("unload", searchbarController, false);
