// 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

var _logger = Cc["@flock.com/logger;1"].createInstance(Ci.flockILogger);
_logger.init("myworld");

var _coop = Cc["@flock.com/singleton;1"]
            .getService(Ci.flockISingleton)
            .getSingleton("chrome://flock/content/common/load-faves-coop.js")
            .wrappedJSObject;

const BLOG_SVC = Cc["@flock.com/flock-blog;1"].getService(Ci.flockIBlogService);

const PREFS = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
const PREF_BROWSER_STARTUP_HOMEPAGE = "browser.startup.homepage";
const PREF_MYWORLD_CURRENT_ENGINE   = "flock.myworld.currentEngine";
const PREF_MYWORLD_TITLE            = "flock.myworld.currentTitle";
const PREF_MYWORLD_WIDGETS_LAYOUT = "flock.myworld.widgets.layout";
const PREF_OPEN_SEARCH_IN = "flock.myworld.search.openLocation";
const XMLHTTPREQUEST_CONTRACTID     = "@mozilla.org/xmlextras/xmlhttprequest;1";
const nsIXMLHttpRequest             = Components.interfaces.nsIXMLHttpRequest;
const PEOPLE_PREFERRED_SERVICES_LIST_PREF = "flock.people.preferredServiceList";
const SBS = Cc["@mozilla.org/intl/stringbundle;1"]
            .getService(Ci.nsIStringBundleService);
const BRANDING_BUNDLE = "chrome://branding/locale/brand.properties";
const TWITTER_SEARCH_XUL = "chrome://flock/content/start/twittersearch.xul";
const TWITTER_CONTRACT_ID = "@flock.com/people/twitter;1";
const TS_CONTRACT_ID = "@flock.com/webservice/twittersearch;1";

const MYWORLD_TITLE_FONTSCALE_LC = 13;
const MYWORLD_TITLE_FONTSCALE_UC = 19;

const nsIPrefLocalizedString = Components.interfaces.nsIPrefLocalizedString;

var gMyworldTitleMinWidth;
var gMyworldWidgets = [];
var gMyworldWidgetsVisible = 0;

var currentEng;

var gObsrvr = null;
var gAccountObsrvr = null;
var gTimer = null;
var gFadeTimer = null;

function onUnload() {
  this.gMetrics.report("MyWorld-Close", null);

  if (gTimer) {
    gTimer.cancel();
  }
  if (gFadeTimer) {
    gFadeTimer.cancel();
  }

  this.removeWidgetObservers();
}

function onLoad()
{
  gTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  gTimer.initWithCallback({
    notify: function myworld_loadColumnLayoutTimer() {
      loadColumnLayout();
    }
  }, 100, Ci.nsITimer.TYPE_ONE_SHOT);

  _logger.debug("onLoad");

  // Show widget buttons on load of myworld, then fade them out after
  // a few seconds.
  document.getElementById("ftcontainerID")
          .setAttribute("showButtons", "true");
  gFadeTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  gFadeTimer.initWithCallback({
    notify: function myworld_fadeTimer() {
      fadeOutControls();
    }
  }, 7000, Ci.nsITimer.TYPE_ONE_SHOT);

  document.getElementById("focusOnLoad").select();

  this.gMetrics.report("MyWorld-Opened", null);
  
  checkDefaultHomepage();  

  loadEngines();

  loadMyWorldTitle();

  resizeFunction(null);

  window.addEventListener("resize", resizeFunction, false);

  // This is a necessary hack, please see
  // https://bugzilla.mozilla.org/show_bug.cgi?id=196057
  window.onload = null;
}

function checkDefaultHomepage() {
   var defhbox = document.getElementById("makedefault");

   // Remove to re-build
   while(defhbox.firstChild) {
      defhbox.removeChild(defhbox.firstChild);
   }

   // check if flock is in the default
   if(PREFS.getPrefType(PREF_BROWSER_STARTUP_HOMEPAGE)) {
      var homepage = PREFS.getComplexValue(PREF_BROWSER_STARTUP_HOMEPAGE, nsIPrefLocalizedString).data;
      if(homepage.indexOf("about:myworld") >= 0) {
        return; 
      }
   }
   
   // Add to page if necessary
   var button = document.createElement("button");
   button.setAttribute("onclick", "makeDefaultHomepage()");
   button.setAttribute("class", "defaultHomepageBtn");
   
   var label = document.createElement("label");
   label.setAttribute("class", "myworldHomepage");
   label.setAttribute("value", flockGetString("start/myworld", "flock.myworld.homepage.set"));
   
   button.appendChild(label);
   defhbox.appendChild(button);
}

function loadEngines() {
  // Get a list of all search engines
  var searchService = Cc["@mozilla.org/browser/search-service;1"].getService(Ci.nsIBrowserSearchService);
  if (!searchService) return;

  var engines = searchService.getVisibleEngines({ });

  var eMenu = document.getElementById("engineMenuID");

  // delete list before re-creating it
  var existingChildrenCount = eMenu.childNodes.length;
  for(var z=existingChildrenCount;z>0;z--)
  {
    var existChild = eMenu.childNodes[z-1];
    eMenu.removeChild(existChild);
  }

  var currentEngine;
  // Get current myworld engine
  if (PREFS.getPrefType(PREF_MYWORLD_CURRENT_ENGINE)) {
    currentEngine = PREFS.getCharPref(PREF_MYWORLD_CURRENT_ENGINE);
  }

  if (!currentEngine || !searchService.getEngineByName(currentEngine)) {
    // If myworld engine doesnt exist, use current default engine
    if (!searchService.currentEngine) return;
    currentEngine = searchService.currentEngine.name;
  }

  PREFS.setCharPref(PREF_MYWORLD_CURRENT_ENGINE, currentEngine);

    // Add them to the menu
  for(var i=engines.length-1;i>=0;--i) {
    var menuitem = document.createElementNS(kXULNS, "menuitem");
    menuitem.setAttribute("label", engines[i].name);
    menuitem.setAttribute("id", engines[i].name);
    menuitem.setAttribute("class", "engine-menuitem");
    menuitem.setAttribute("engine", engines[i].name);
    menuitem.setAttribute("image", engines[i].iconURI);
    menuitem.setAttribute("oncommand", "selectEngine(this)");

    if(engines[i].name == currentEngine) {
      menuitem.setAttribute("selected", "true");
      currentEng = engines[i];
    }

    if(engines[i].iconURI) {
      menuitem.setAttribute("image", engines[i].iconURI.spec);

      // Also set the image of the selected item
      if(engines[i].name == currentEngine) {
        var engineImageID = document.getElementById("engineImageID");
        engineImageID.setAttribute("src",engines[i].iconURI.spec);
      }
    }

    eMenu.insertBefore(menuitem, eMenu.firstChild);
    menuitem.engine = engines[i];
  }
}

function toggleEngineMenu() {
  var popup = document.getElementById("engineMenuID");
  var popButton = document.getElementById("popButton");

  popup.showPopup(popButton, -1, -1, "popup", "bottomleft", "topleft");
}

function selectEngine(engine) {
  var engineName  = engine.getAttribute("engine");
  var engineImage = engine.getAttribute("image");
  this.gMetrics.report("MyWorld-SearchEngineChange", engineName);

  if(engineImage != "" && engineImage != null) {
    var engineImageID = document.getElementById("engineImageID");
    engineImageID.setAttribute("src",engineImage);
  }

  // Set current engine
  var searchService = Cc["@mozilla.org/browser/search-service;1"].getService(Ci.nsIBrowserSearchService);
  var engines = searchService.getVisibleEngines({ });

  for(var i=engines.length-1;i>=0;--i) {
    if(engines[i].name == engineName) {
      currentEng = engines[i];
      PREFS.setCharPref(PREF_MYWORLD_CURRENT_ENGINE, currentEng.name);
      return;
    }
  }
}

function refreshDateTime()
{
  var timeLabel = document.getElementById("timeUpdated");

  var time = new Date();

  var dtFormat = flockGetString("start/myworld", "flock.myworld.dateTimeFormat");

  // see bug 9830#31
  dtFormat = dtFormat.replace("%e", time.getDate());

  var thedate = time.toLocaleFormat(dtFormat);

  timeLabel.setAttribute("value", thedate);

  this.os.notifyObservers(null, "refresh-myworld-date", null);
  setTimeout("refreshDateTime()", (60 - time.getSeconds() + 1) * 1000);
}

function uploadPhotos(event)
{
  if(event.button == 2) {
    return; 
  }

  this.gMetrics.report("Uploader-Open", "MyWorldUploadButton");
  var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
  var win = wm.getMostRecentWindow('navigator:browser');
  if (win) {
    win.FlockMedia.getUploadSvc().launchUploader();
  }
}

function createBlogPost(event)
{
  if(event.button == 2) {
    return; 
  }
  
  this.gMetrics.report("BlogDialog-Open", "MyWorldBlogButton");
  BLOG_SVC.openEditor("","","");
}

function searchboxKeyPress(event,query) {
  if (event.keyCode == KeyEvent.DOM_VK_RETURN) {
    searchFunction(query);
  }
}

function searchFunction(query)
{
  var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
  var win = wm.getMostRecentWindow('navigator:browser');
  if (win) {
    currentEng.QueryInterface(Ci.flockISearchEngine);
    var submission = currentEng.getSubmissionByContext(query, null, "w");
    if (!submission) { return; }

    this.gMetrics.report("MyWorld-Search", currentEng.name);

    // Check to see where we should open.
    var openLocation;
    if (PREFS.getPrefType(PREF_OPEN_SEARCH_IN)) {
      openLocation = PREFS.getCharPref(PREF_OPEN_SEARCH_IN);
    } else {
      openLocation = "tab";
      PREFS.setCharPref(PREF_OPEN_SEARCH_IN, openLocation);
    }

    // Double check to see if it's one of the 3 choices.  Default to tab.
    switch (openLocation) {
      case "tab":
      case "window":
      case "current":
      break;

      default: {
        openLocation = "tab";
        PREFS.setCharPref(PREF_OPEN_SEARCH_IN, openLocation);
      }
      break;
    }

    win.openUILinkIn(submission.uri.spec, openLocation);
  }
}

function makeDefaultHomepage() {
  // Make My World the default homepage
  PREFS.setCharPref(PREF_BROWSER_STARTUP_HOMEPAGE, "about:myworld");

  checkDefaultHomepage();

  var notificationBox = getNotificationBox();
  if(notificationBox) {
    var message = flockGetString("start/myworld", "flock.myworld.homepage");
    notificationBox.appendNotification( message,
                                        "myworldadded",
                                        "chrome://flock/skin/common/Info.png",
                                        notificationBox.FLOCK_PRIORITY_MEDIUM,
                                        null,
                                        null);
  
  }
}

function getNotificationBox() {

  var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
           .getService(Ci.nsIWindowMediator);
  var win = wm.getMostRecentWindow('navigator:browser');
  if (win) {
    var gBrowser = win.getBrowser();
    var notificationBox = gBrowser.getNotificationBox();

    return notificationBox;
  }

  return null;
}

function initWidgetObservers() {
  // Add observer for refresh
  var inst = this;
  if (!gObsrvr) {
    gObsrvr = {};
    gObsrvr.observe = function engineManager_observer(aEngine, aTopic, aVerb) {
      if(aTopic == "browser-search-engine-modified") {
        aEngine.QueryInterface(Ci.nsISearchEngine);
        switch (aVerb) {
          case "engine-added":
          case "engine-removed":
            setTimeout("loadEngines()", 1000);
        }
      }
      //for each widget, an observer is added with the form
      //refresh-myworld-{widget.label}
      if (aTopic.match(/^refresh-myworld/)) {
        _logger.debug("resizeWidgetContainer");
        inst.resizeWidgetContainer();
      }
    }
    // Add observer for engines added
    this.os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
    this.os.addObserver(gObsrvr, "browser-search-engine-modified", false);
    this.os.addObserver(gObsrvr, "refresh-myworld-size", false);
  
    setTimeout("refreshDateTime()", 500);

    //resize window to account for iframe content
    setTimeout("resizeWidgetContainer()", 500);
  }
  if (!gAccountObsrvr) {
    gAccountObsrvr = {
      setTwitterElemsVis: function acctObs_setTwitterElemsVis(aVisible) {
        for each (var column in gMyworldWidgets) {
          if (column.label == "twittersearch") {
            var twitterSearch = document.getElementById(column.id + "-iframe")
                                        .contentWindow
                                        .wrappedJSObject
                                        .gTwitterSearch;
            // Update reply button visibility.
            twitterSearch.doLayout();

            // Update topic and login button visibility.
            var topicBtn
              = document.getElementById(column.id + "-twitter-topic-button");
            var loginBtn
              = document.getElementById(column.id + "-twitter-login-button");
            if (column.type == "twittertopic" && topicBtn) {
              if (aVisible) {
                topicBtn.removeAttribute("hidden");
                loginBtn.setAttribute("hidden", "true");
              } else {
                topicBtn.setAttribute("hidden", "true");
                loginBtn.removeAttribute("hidden");
              }
            }
          }
        }
      },
      onAccountAuthenticated: function acctObs_onAccountAuthenticated(aAccount)
      {
        if (aAccount.getParam("serviceId") == TWITTER_CONTRACT_ID) {
          gAccountObsrvr.setTwitterElemsVis(true);
        }
      },
      onAccountRemoved: function acctObs_onAccountRemoved(aAccount) {
      },
      onAccountUnauthenticated:
      function acctObs_onAccountUnauthenticated(aAccount) {
        if (aAccount.getParam("serviceId") == TWITTER_CONTRACT_ID) {
          gAccountObsrvr.setTwitterElemsVis(false);
        }
      },
      onAccountRefreshing: function acctObs_onAccountRefreshing(aAccount) {
      },
      onAccountNoLongerRefreshing:
      function acctObs_onAccountNoLongerRefreshing(aAccount) {
      }
    };

    var accountService = Cc["@flock.com/account-service;1"]
                         .getService(Ci.flockIAccountService);
    accountService.addObserver(gAccountObsrvr);
  }
}

function removeWidgetObservers() {
  if (this.os) {
    this.os.removeObserver(gObsrvr, "browser-search-engine-modified");
    this.os.removeObserver(gObsrvr, "refresh-myworld-size");
  }
  var accountService = Cc["@flock.com/account-service;1"]
                       .getService(Ci.flockIAccountService);
  accountService.removeObserver(gAccountObsrvr);
}

/**
 * Gets the column layout from the pref store
 */
function getColumnLayout() {
  if (PREFS.getPrefType(PREF_MYWORLD_WIDGETS_LAYOUT)) {
    return PREFS.getComplexValue(PREF_MYWORLD_WIDGETS_LAYOUT,
                                 Ci.nsIPrefLocalizedString).data;
  } else {
    var columns = [];

    columns.push({
      label: "topsites",
      url: "chrome://flock/content/start/topsites.xul",
      properties_url: "chrome://flock/locale/start/myworld.properties",
      show: "false"
    });
    columns.push({
      label: "topfriends",
      url: "chrome://flock/content/start/topfriends.xul",
      properties_url: "chrome://flock/locale/start/myworld.properties",
      show: "false"
    });
    columns.push({
      label: "topmedia",
      url: "chrome://flock/content/start/topmedia.xul",
      properties_url: "chrome://flock/locale/start/myworld.properties",
      show: "true"
    });
    columns.push({
      label: "topfeeds",
      url: "chrome://flock/content/start/topfeeds.xul",
      properties_url: "chrome://flock/locale/start/myworld.properties",
      show: "true"
    });
    columns.push({
      label: "twittersearch",
      url: "chrome://flock/content/start/twittersearch.xul",
      properties_url: "chrome://flock/locale/start/myworld.properties",
      multiple: "true",
      show: "true"
    });

    var nsJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
    var layoutString = nsJSON.encode(columns);
    setColumnLayout(layoutString);
    return layoutString;
  }
}

/**
 * Sets the column layout in the pref store
 */
function setColumnLayout(aLayout) {
  PREFS.setCharPref(PREF_MYWORLD_WIDGETS_LAYOUT, aLayout);
}

/**
 * Loads column layout
 */
function loadColumnLayout() {
  var nsJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
  var layoutObj = nsJSON.decode(getColumnLayout());
  gMyworldWidgets = eval(layoutObj);
  //add additional observers for each widget
  initWidgetObservers();
    
  var containerElement = document.getElementById("ftcontainerID");
  // Insert child elements in reverse order.
  containerElement.setAttribute("dir", "reverse");

  //clean up existing dom within container if exists
  while (containerElement.hasChildNodes()) {
    containerElement.removeChild(containerElement.lastChild);
  }

  var colIndex = 0;
  var updateToLayout = false;
  gMyworldWidgetsVisible = 0;

  var widgetMenuPopup = document.getElementById("widgets-selector");
  for each (var column in gMyworldWidgets) {
    // Migration check: make sure properties_url is specified
    if (!column.properties_url) {
      column.properties_url = "chrome://flock/locale/start/myworld.properties";

      updateToLayout = true;
    }

    // Create columnId if one doesn't already exist.
    if (!column.id) {
      var now = (new Date()).getTime();
      column.id = column.label + ":" + now;
      column.url = column.url + "?id=" + now;
      updateToLayout = true;
    }

    var sb = SBS.createBundle(column.properties_url);

    // Add singleton widgets to widgets menu.
    if (!eval(column.multiple)) {
      var titleStr = sb.GetStringFromName("flock.myworld." + column.label
                                                           + ".title");
      //create menuitem for widget entry
      var widgetMenuItem = document.createElement("menuitem");
      widgetMenuItem.setAttribute("label", titleStr);
      widgetMenuItem.setAttribute("id", column.id + "-toggleItem");
      widgetMenuItem.setAttribute("class", "menuitem-iconic");
      widgetMenuItem.setAttribute("type", "checkbox");
      var command = "doWidgetToggle('" + column.id + "');";
      widgetMenuItem.setAttribute("oncommand", command);
      widgetMenuPopup.appendChild(widgetMenuItem);
    }

    if (eval(column.show)) {
      openWidget(column, sb);
    }
  }

  // Add the Twitter Search menu item.
  var separator = document.createElement("separator");
  separator.setAttribute("class", "groove");
  var widgetMenuItem = document.createElement("menuitem");
  widgetMenuItem.setAttribute("label", "New Twitter Search");
  widgetMenuItem.setAttribute("id", "new-twitter-search");
  widgetMenuItem.setAttribute("oncommand", "addTwitterSearch();");
  widgetMenuPopup.appendChild(separator);
  widgetMenuPopup.appendChild(widgetMenuItem);

  checkDiscoveryBox(gMyworldWidgetsVisible);

  refreshMoveItems();
  if (updateToLayout) {
    saveColumnLayout();
  }
}

/**
 * Saves column layout
 */
function saveColumnLayout() {
  var nsJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
  var newLayout = nsJSON.encode(gMyworldWidgets);

  var metricsValue = [];
  for (var i = 0; i < gMyworldWidgets.length; i++) {
    metricsValue.push({name: gMyworldWidgets[i].label,
                       position: i,
                       visible: (gMyworldWidgets[i].show == "true")});
  }
  // .report expects the value to be in an [ ] if it is a complex object,
  // even if it's already an [ ].
  gMetrics.report("MyWorld-LayoutChange", [metricsValue]);

  setColumnLayout(newLayout);
}

/**
 * Moves column left/right
 * aDirection = left/right
 */
function moveColumn(aWidgetId, aDirection) {
  var moveTarget = document.getElementById(aWidgetId);
  var parent = moveTarget.parentNode;
  var colIndex = moveTarget.getAttribute("col_index");
  var column = gMyworldWidgets[colIndex];
  var sibling2swap;

  switch (aDirection) {
    case "left": {
      sibling2swap = moveTarget.previousSibling;
      if (!sibling2swap || colIndex == 0) {
        // We can't go left anymore
        return false;
      }
      parent.removeChild(moveTarget);
      parent.insertBefore(moveTarget, sibling2swap);
    } break;
    case "right": {
      sibling2swap = moveTarget.nextSibling;
      if (!sibling2swap || gMyworldWidgets.length == colIndex) {
        return false;
      }
      parent.removeChild(moveTarget);
      parent.insertBefore(moveTarget, sibling2swap.nextSibling);
    } break;
    default: {
      // Not used yet or invalid choice
      return false;
    }
  }
  var newIndex = sibling2swap.getAttribute("col_index");
  gMyworldWidgets.splice(colIndex, 1);
  gMyworldWidgets.splice(newIndex, 0, column);
  this.updateCurrentColumnLayout();
  return true;
}

function updateCurrentColumnLayout() {
  checkDiscoveryBox(gMyworldWidgetsVisible);
  this.refreshMoveItems();
  this.saveColumnLayout();
}

function checkDiscoveryBox(aWidgetsVisible) {
  if (aWidgetsVisible == 0) {
    // Show the discovery box
    document.getElementById("noContentID").setAttribute("hidden", "false");
  } else {
    // Hide the discovery box
    document.getElementById("noContentID").setAttribute("hidden", "true");
  }
}

function closeWidget(aWidgetId) {
  var metrics = Components.classes["@flock.com/metrics-service;1"]
                .getService(Components.interfaces.flockIMetricsService)
  metrics.report("MyWorld-HideWidget", "close");

  var node = document.getElementById(aWidgetId);
  var colIndex = node.getAttribute("col_index");
  var column = gMyworldWidgets[colIndex];
  column.show = "false";
  gMyworldWidgetsVisible--;

  // Delete Twitter Search coop elements.
  var widgetSplit = aWidgetId.split(":");
  if (widgetSplit[0] == "twittersearch") {
    // Remove associated elements in coop.
    var id = widgetSplit[1];
    var twitterSearchUrn = "urn:flock:twitter:search:" + id;
    coopTwitterSearch = _coop.get(twitterSearchUrn);
    if (coopTwitterSearch) {
      var twitterSearchChildren = coopTwitterSearch.children;
      var childrenEnum = twitterSearchChildren.enumerate();
      while (childrenEnum.hasMoreElements()) {
        var searchItem = childrenEnum.getNext();
        twitterSearchChildren.remove(searchItem);
        searchItem.destroy();
      }
      coopTwitterSearch.destroy();
    }
  }

  var parent = node.parentNode;
  parent.removeChild(node);

  if (eval(column.multiple)) {
    gMyworldWidgets.splice(colIndex, 1);
  } else {
    // Uncheck singleton widget in the widget menu.
    var nodeMenuItem = document.getElementById(aWidgetId + "-toggleItem");
    nodeMenuItem.setAttribute("checked", "false");
  }
  
  this.updateCurrentColumnLayout();
}

function openWidget(aColumn, aBundle, aBeforeIndex) {
  var widgetId = aColumn.id;

  gMyworldWidgetsVisible++;

  var containerElement = document.getElementById("ftcontainerID");
  // iframe content for respective xul page
  var iframe = document.createElement("iframe");
  iframe.setAttribute("id", aColumn.id + "-iframe");
  iframe.setAttribute("flex", "1");
  iframe.setAttribute("src", aColumn.url);

  // widget container
  var widgetVbox = document.createElement("vbox");
  widgetVbox.setAttribute("label_val", aColumn.label);
  widgetVbox.setAttribute("iframe_src", aColumn.url);

  widgetVbox.setAttribute("properties_url", aColumn.properties_url);
  widgetVbox.setAttribute("widgetContainer", "true");
  widgetVbox.setAttribute("id", widgetId);
  widgetVbox.setAttribute("class", "col_hdr_container");
  widgetVbox.setAttribute("hidden", "false");

  var vboxContainer = document.createElement("vbox");

  // widget settings
  var widgetSettings = document.createElement("vbox");
  widgetSettings.setAttribute("class", "col_hdr_settings");
  var widgetSettingsHbox = document.createElement("hbox");
  widgetSettings.appendChild(widgetSettingsHbox);

  // Create left move button.
  var moveLeftBtn = document.createElement("toolbarbutton");
  moveLeftBtn.setAttribute("class", "widgetMoveBtn-left");
  var mvLeftTT = aBundle.GetStringFromName("flock.myworld.widgets.moveLeft");
  moveLeftBtn.setAttribute("tooltiptext", mvLeftTT);
  var moveCommand = "moveColumn('" + widgetId + "',";
  // Since orientation of widget container is reversed, left button
  // will move right.
  moveLeftBtn.setAttribute("oncommand", moveCommand + "'right');");
  moveLeftBtn.setAttribute("id", widgetId + "-moveLeft");

  // Create right move button.
  var moveRightBtn = document.createElement("toolbarbutton");
  moveRightBtn.setAttribute("class", "widgetMoveBtn-right");
  var mvRightTT = aBundle.GetStringFromName("flock.myworld.widgets.moveRight");
  moveRightBtn.setAttribute("tooltiptext", mvRightTT);
  // Since orientation of widget container is reversed, right button
  // will move left.
  moveRightBtn.setAttribute("oncommand", moveCommand + "'left');");
  moveRightBtn.setAttribute("id", widgetId + "-moveRight");

  // Attach moves button.
  widgetSettingsHbox.appendChild(moveLeftBtn);
  widgetSettingsHbox.appendChild(moveRightBtn);

  // close button
  var closeBtn = document.createElement("toolbarbutton");
  closeBtn.setAttribute("oncommand", "closeWidget('" + widgetId + "');");
  closeBtn.setAttribute("class", "widgetCloseBtn");
  var close = "flock.myworld.widgets.close";
  closeBtn.setAttribute("tooltiptext", aBundle.GetStringFromName(close));
  widgetSettingsHbox.appendChild(closeBtn);

  // Append widget buttons.
  vboxContainer.appendChild(widgetSettings);

  // widget title
  var title = document.createElement("label");
  title.setAttribute("id", widgetId + "-title-label");
  title.setAttribute("class", "favHeaderLabel");
  title.setAttribute("crop", "end");
  vboxContainer.appendChild(title);

  // widget sub title and help image
  var subHbox = document.createElement("hbox");
  subHbox.setAttribute("class", "col_hdr_bottom");

  var image = document.createElement("image");
  image.setAttribute("id", widgetId + "-whatsthis-image");
  image.setAttribute("class", "whatsThis");

  var whatsThis = "flock.myworld.whatsThis";
  image.setAttribute("value", aBundle.GetStringFromName(whatsThis));
  image.setAttribute("onclick", "popupWhatsThis(this)");
  var subTitle = document.createElement("label");
  subTitle.setAttribute("id", widgetId + "-subtitle-label");
  subTitle.setAttribute("class", "col_sub_hdr");
  var tooltip;
  var subTitleName;
  if (aColumn.type) {
    tooltip = "flock.myworld." + aColumn.type + ".tooltip";
    subTitleName = "flock.myworld." + aColumn.type + ".subTitle2";
  } else {
    tooltip = "flock.myworld." + aColumn.label + ".tooltip";
    subTitleName = "flock.myworld." + aColumn.label + ".subTitle2";
  }
  
  image.setAttribute("desc", tooltip);
  subTitle.setAttribute("value", aBundle.GetStringFromName(subTitleName));
  subTitle.setAttribute("onclick",
                        "popupWhatsThis(this.parentNode.childNodes[0])");

  subHbox.appendChild(image);
  subHbox.appendChild(subTitle);

  // Get the Twitter search term from coop.
  var searchTerm = "";
  var widgetSplit = widgetId.split(":");
  var id = widgetSplit[1];
  var twitterSearchUrn = "urn:flock:twitter:search:" + id;
  coopTwitterSearch = _coop.get(twitterSearchUrn);
  if (coopTwitterSearch && coopTwitterSearch.searchTerm) {
    searchTerm = coopTwitterSearch.searchTerm;
  }

  // Set widget title and tooltip.
  var titleStr;
  if (aColumn.type) {
    titleStr = aBundle.GetStringFromName("flock.myworld."
                                         + aColumn.type + ".title");
    titleStr += " " + searchTerm;
  } else {
    titleStr = aBundle.GetStringFromName("flock.myworld."
                                           + aColumn.label + ".title");
  }
  title.setAttribute("value", titleStr);
  title.setAttribute("tooltiptext", titleStr);
  title.setAttribute("onclick", this.doWidgetAction(aColumn.label));

  if (aColumn.label == "twittersearch") {
    // Topic button
    var topicbutton = document.createElement("toolbarbutton");
    topicbutton.setAttribute("id", widgetId + "-twitter-topic-button");
    topicbutton.setAttribute("class", "twitter-save-search-button");
    topicbutton.setAttribute("currentSearchTerm", searchTerm);
    topicbutton.setAttribute("oncommand",
                             "twitterTopicButtonClicked('" + widgetId + "');");
    var topicimageL = document.createElement("image");
    topicimageL.setAttribute("class", "twitter-save-search-buttonL");
    var topicmiddleLabel = document.createElement("label");
    topicmiddleLabel.setAttribute("class", "twitter-save-search-button-middle");
    var topicStr
      = aBundle.GetStringFromName("flock.myworld.twittertopic.button.label");
    topicmiddleLabel.setAttribute("value", topicStr);
    var topicimageR = document.createElement("image");
    topicimageR.setAttribute("class", "twitter-save-search-buttonR");
    topicbutton.appendChild(topicimageL);
    topicbutton.appendChild(topicmiddleLabel);
    topicbutton.appendChild(topicimageR);
    var spacer = document.createElement("spacer");
    spacer.setAttribute("id", widgetId + "-twitter-topic-button-spacer");
    spacer.setAttribute("flex", "1");
    subHbox.appendChild(spacer);
    subHbox.appendChild(topicbutton);

    // Login button
    var loginbutton = document.createElement("toolbarbutton");
    loginbutton.setAttribute("id", widgetId + "-twitter-login-button");
    loginbutton.setAttribute("class", "twitter-save-search-button");
    loginbutton.setAttribute("oncommand", "twitterLoginButtonClicked(event);");
    var loginimageL = document.createElement("image");
    loginimageL.setAttribute("class", "twitter-save-search-buttonL");
    var loginmiddleLabel = document.createElement("label");
    loginmiddleLabel.setAttribute("class", "twitter-save-search-button-middle");
    var loginStr
      = aBundle.GetStringFromName("flock.myworld.twittertopic.login.label");
    loginmiddleLabel.setAttribute("value", loginStr);
    var loginimageR = document.createElement("image");
    loginimageR.setAttribute("class", "twitter-save-search-buttonR");
    loginbutton.appendChild(loginimageL);
    loginbutton.appendChild(loginmiddleLabel);
    loginbutton.appendChild(loginimageR);
    subHbox.appendChild(loginbutton);

    if (aColumn.type == "twittersave") {
      topicbutton.setAttribute("hidden", "true");
      loginbutton.setAttribute("hidden", "true");
    } else if (aColumn.type == "twittertopic") {
      var twitterSvc = Cc[TWITTER_CONTRACT_ID]
                       .getService(Ci.flockIWebService);
      var acct = twitterSvc.getAccount(twitterSvc.getAuthenticatedAccount());

      // Only show the topic button if there is a logged in Twitter account.
      // If there are no logged in Twitter accounts, show the login button.
      if (acct) {
        loginbutton.setAttribute("hidden", "true");
      } else {
        topicbutton.setAttribute("hidden", "true");
      }
      // Do nothing.
    } else { // Twitter search widget.
      // Textbox
      var textBox = document.createElement("textbox");
      textBox.setAttribute("id", widgetId + "-twitter-search-textbox");
      textBox.setAttribute("class", "twitter-search-textbox");
      textBox.setAttribute("persist", "value");
      textBox.setAttribute("type", "autocomplete");
      textBox.setAttribute("autocompletesearch", "form-history");
      textBox.setAttribute("autocompletesearchparam", "twitter-search");
      textBox.setAttribute("onkeyup",
                           "twitterSearchOnKeyUp('" + widgetId + "', event);");
      textBox.setAttribute("value", searchTerm);
      textBox.setAttribute("currentSearchTerm", searchTerm);

      // Search button
      var button = document.createElement("toolbarbutton");
      button.setAttribute("id", widgetId + "-twitter-search-button");
      button.setAttribute("class", "twitter-search-button");
      var btncmd = "doSearch('" + widgetId + "'); "
                 + "gMetrics.report('MyWorldTwitterWidget-Search', [{ from: 'button' }]);";
      button.setAttribute("oncommand", btncmd);
      var imageL = document.createElement("image");
      imageL.setAttribute("class", "twitter-search-buttonL");
      var middleLabel = document.createElement("label");
      middleLabel.setAttribute("class", "twitter-search-button-middle");
      var searchStr
        = aBundle.GetStringFromName("flock.myworld.twittersearch.search.label");
      middleLabel.setAttribute("value", searchStr);
      var imageR = document.createElement("image");
      imageR.setAttribute("class", "twitter-search-buttonR");
      button.appendChild(imageL);
      button.appendChild(middleLabel);
      button.appendChild(imageR);

      // Save button
      var savebutton = document.createElement("toolbarbutton");
      savebutton.setAttribute("id", widgetId + "-twitter-save-search-button");
      savebutton.setAttribute("class", "twitter-save-search-button");
      if (!searchTerm) {
        savebutton.setAttribute("disabled", "true");
      }
      savebutton.setAttribute("oncommand",
                              "saveTwitterSearch('" + widgetId + "');");
      var saveimageL = document.createElement("image");
      saveimageL.setAttribute("class", "twitter-save-search-buttonL");
      var savemiddleLabel = document.createElement("label");
      savemiddleLabel.setAttribute("class",
                                   "twitter-save-search-button-middle");
      var saveSearchStr
        = aBundle.GetStringFromName("flock.myworld.twittersearch.savesearch.label");
      savemiddleLabel.setAttribute("value", saveSearchStr);
      var saveimageR = document.createElement("image");
      saveimageR.setAttribute("class", "twitter-save-search-buttonR");
      savebutton.appendChild(saveimageL);
      savebutton.appendChild(savemiddleLabel);
      savebutton.appendChild(saveimageR);

      // Trends button
      var trendsbutton = document.createElement("toolbarbutton");
      trendsbutton.setAttribute("id", widgetId + "-twitter-trends-button");
      trendsbutton.setAttribute("class", "twitter-save-search-button");
      trendsbutton.setAttribute("oncommand", "trendsClicked('" + widgetId + "');");
      var trendsimageL = document.createElement("image");
      trendsimageL.setAttribute("class", "twitter-save-search-buttonL");
      var trendsmiddleLabel = document.createElement("label");
      trendsmiddleLabel.setAttribute("class",
                                     "twitter-save-search-button-middle");
      var trendsStr
        = aBundle.GetStringFromName("flock.myworld.twittersearch.trends.label");
      trendsmiddleLabel.setAttribute("value", trendsStr);
      var trendsimageR = document.createElement("image");
      trendsimageR.setAttribute("class", "twitter-trends-buttonR");
      trendsbutton.appendChild(trendsimageL);
      trendsbutton.appendChild(trendsmiddleLabel);
      trendsbutton.appendChild(trendsimageR);

      image.setAttribute("hidden", "true");
      subTitle.setAttribute("hidden", "true");
      spacer.setAttribute("hidden", "true");
      topicbutton.setAttribute("hidden", "true");
      loginbutton.setAttribute("hidden", "true");
      subHbox.appendChild(textBox);
      subHbox.appendChild(button);
      subHbox.appendChild(savebutton);
      subHbox.appendChild(trendsbutton);
    }
  }

  vboxContainer.appendChild(subHbox);

  widgetVbox.appendChild(vboxContainer);
  widgetVbox.appendChild(iframe);
  if (aBeforeIndex < gMyworldWidgets.length) {
    var widgetId = gMyworldWidgets[aBeforeIndex].id;
    var beforeWidgetVbox = document.getElementById(widgetId)
    containerElement.insertBefore(widgetVbox, beforeWidgetVbox);
  } else {
    containerElement.appendChild(widgetVbox);
  }

  if (!eval(aColumn.multiple)) {
    var nodeMenuItem = document.getElementById(widgetId + "-toggleItem");
    nodeMenuItem.setAttribute("checked", "true");
  }
}

function getBrandedString(aString, aBundle) {
  var acUtils = Cc["@flock.com/account-utils;1"]
                .getService(Ci.flockIAccountUtils);

  // Get the pref that governs the set of preferred services.
  var preferredServices = [];
  if (PREFS.getPrefType(PEOPLE_PREFERRED_SERVICES_LIST_PREF)) {
    preferredServices = PREFS.getCharPref(PEOPLE_PREFERRED_SERVICES_LIST_PREF);
    if (preferredServices.length > 0) {
      preferredServices = preferredServices.split("|");
    }
  }

  // Sanitize the service list
  var socialServicesEnum =
    acUtils.getWebServicesByInterface("flockISocialWebService");
  while (socialServicesEnum.hasMoreElements()) {
    var svc = socialServicesEnum.getNext();
    var idx = preferredServices.indexOf(svc.shortName);

    var accountUrns = svc.getAccountUrns();
    if (accountUrns.hasMore()) {
      // Found a configured account so remove the service from the list
      if (idx > -1) { 
        preferredServices.splice(idx, 1);
      }
      continue;
    }

    // Add the service to our list if it's not already there
    if (idx < 0) {
      preferredServices.push(svc.shortName);
    }
  }

  // Construct the prettified list of preferred services
  var services = "";
  for (var i = 0; i < preferredServices.length; i++) { 
    if (preferredServices.length == 1 || services.length == 0) {
      services += ": ";
    } else if (i == (preferredServices.length - 1)) {
      services += " and ";
    } else if (services.length > 0) {
      services += ", ";
    }

    var svc = acUtils.getServiceFromShortname(preferredServices[i]);
    services += (svc && svc.title) ? svc.title : preferredServices[i];
  }

  var brand = SBS.createBundle(BRANDING_BUNDLE)
                 .GetStringFromName("brandShortName");

  return aBundle.formatStringFromName(aString, [brand, services, brand], 3);
}

function doWidgetToggle(aWidgetId) {
  var node = document.getElementById(aWidgetId);
  if (!node) {
    var rightColumnIndex = -1;
    for (var colIndex = gMyworldWidgets.length-1; colIndex >= 0; colIndex--) {
      var column = gMyworldWidgets[colIndex];
      if (eval(column.show)) {
        if (rightColumnIndex < 0) {
          rightColumnIndex = colIndex;
        }
      } else if (column.id == aWidgetId) {
        // If rightColumnIndex == -1, this means the first widget we ran into
        // was the right-most widget in the gMyworldWidgets array, which is
        // set NOT to show.
        if (rightColumnIndex != -1) {
          gMyworldWidgets.splice(colIndex, 1);
          gMyworldWidgets.splice(rightColumnIndex, 0, column);
        }
        column.show = "true";
        openWidget(column, SBS.createBundle(column.properties_url));
        this.updateCurrentColumnLayout();
        break;
      }
    }
  } else {
    this.closeWidget(aWidgetId);
    gMetrics.report("MyWorld-HideWidget", "uncheck");
  }
}

function refreshMoveItems() {
  var moveRight = null;
  for (var colIndex = gMyworldWidgets.length-1; colIndex >= 0; colIndex--) {
    var column = gMyworldWidgets[colIndex];
    var widgetId = column.id;
    var node = document.getElementById(widgetId);
    if (node) {
      node.setAttribute("col_index", colIndex);
      var moveLeft = document.getElementById(widgetId + "-moveLeft");
      if (moveRight) {
        // this is not the first column
        moveLeft.setAttribute("hidden", "false");
        moveRight.setAttribute("hidden", "false");
      } else {
        moveLeft.setAttribute("hidden", "true");
      }
      moveRight = document.getElementById(widgetId + "-moveRight");
    }
  }
  if (moveRight) {
    // handle the last column
    moveRight.setAttribute("hidden", "true");
  }
}

function setWidgetButtonsOpacity(level) {
  var children = document.getElementById("ftcontainerID")
                         .getElementsByAttribute("class", "col_hdr_settings");
  for (var i = 0; i < children.length; i++) {
    children[i].style.opacity = level;
  }
}

function restoreOpacity() {
  setWidgetButtonsOpacity(1);
  document.getElementById("ftcontainerID")
          .removeAttribute("showButtons");
}

function fadeOutControls() {
  // Fade out widget buttons.
  var level = 1.0;
  while (level >= 0) {
    setTimeout("setWidgetButtonsOpacity(" + level + ")",
               ((1.0 - level) * 1000) + 10);
    level -= 0.01;
  }

  // Restore button opacity.
  setTimeout("restoreOpacity()", 1030);
}

function doWidgetAction(aAction) {
  switch (aAction) {
    case "topsites": {
      return "openFavoritesManager(event);";
    } break;
    case "topfeeds": {
      return "openNewsSidebar(null, event, 'FaveHeaderLabel');";
    } break;
    case "topmedia": {
      return "openMediaBar(null, event);";
    } break;
    case "topfriends": {
      return "openPeopleSidebar(event);";
    } break;
  }
  return null;
}

/**
 * Load MyWorld Title
 */
function loadMyWorldTitle() {
  var titleElement = document.getElementById("myworld-title");
  if (PREFS.getPrefType(PREF_MYWORLD_TITLE)) {
    var myTitle = PREFS.getComplexValue(PREF_MYWORLD_TITLE,
                                        nsIPrefLocalizedString).data;
  } else {
    var myTitle = flockGetString("start/myworld", "flock.myworld.title");
  }
  titleElement.setAttribute("value", myTitle);
  titleElement.setAttribute("originalTitle", myTitle);

  // Get computed style for title to determine min-width
  var view = titleElement.ownerDocument.defaultView;
  var titleStyle = view.getComputedStyle(titleElement, "");
  gMyworldTitleMinWidth = (parseInt(titleStyle
                                    .getPropertyCSSValue("min-width")
                                    .cssText) || 0);
  //init title resize
  this.resizeMyWorldTitle(titleElement);

  document.title = myTitle;
}

function focusMyWorldTitle(obj) {
  obj.setAttribute("edit","true");
  obj.removeAttribute("readonly");
  obj.select();
}

/**
 * Handle KeyPress Events for the MyWorld Title
 */
function keypressMyWorldTitle(aEvent, obj) {
  switch (aEvent.keyCode) {
    case KeyEvent.DOM_VK_RETURN:
      document.commandDispatcher.advanceFocus();
      this.saveMyWorldTitle(obj);
      break;
    case KeyEvent.DOM_VK_TAB:
      this.saveMyWorldTitle(obj);
      break;
    case KeyEvent.DOM_VK_ESCAPE:
      obj.value = obj.getAttribute("originalTitle");
      document.commandDispatcher.advanceFocus();
      this.resizeMyWorldTitle(obj);
      break;
    default:
      //resize textbox
      this.resizeMyWorldTitle(obj);
      break;
   }
}

/**
 * Resize MyWorld Title
 */
function resizeMyWorldTitle(obj) {
  var strValue = obj.value;
  var strLength = strValue.length;
  if (strLength) {
    //need scaling factor for font-size used
    var scale = 0;
    var str = strValue.split("");
    for (var i = 0; i < str.length; i++) {
      if(str[i] != str[i].toLowerCase()) {
        scale += MYWORLD_TITLE_FONTSCALE_UC;
      } else {
        scale += MYWORLD_TITLE_FONTSCALE_LC;
      }
    }
    scale = (scale / str.length).toFixed();
    var newWidth = (strLength * scale).toFixed();
    if (newWidth > gMyworldTitleMinWidth) {
      obj.style.width = newWidth + "px";
    } else {
      obj.style.width = gMyworldTitleMinWidth + "px";
    }
  }

  // Make sure we place the search box properly after any resize to the title.
  resizeFunction(null);
}

/**
 * Saves MyWorld Title
 */
function saveMyWorldTitle(obj) {
  var origTitle = obj.getAttribute("originalTitle");

  // Get current myworld title
  if (PREFS.getPrefType(PREF_MYWORLD_TITLE)) {
    origTitle = PREFS.getComplexValue(PREF_MYWORLD_TITLE,
                                      nsIPrefLocalizedString).data;
  }
  if (origTitle == null) {
    // No pref and has never been changed, therefore we should use the existing
    // document title
    origTitle = document.title;
  }

  // Save and reset css states to appear unfocused
  if (obj.value != null) {
    obj.setAttribute("originalTitle", obj.value);
    obj.removeAttribute("edit");
    obj.setAttribute("readonly", "true");
    var str = Cc["@mozilla.org/supports-string;1"]
              .createInstance(Ci.nsISupportsString);
    str.data = obj.value;
    PREFS.setComplexValue(PREF_MYWORLD_TITLE, Ci.nsISupportsString, str);
    gMetrics.report("MyWorld-NameChange", null);
    document.title = obj.value;
  }
}

//ensure column container renders the height of the iframe content
function resizeWidgetContainer() {
  //reset height for changes in size
  var columnContainerHeight = 0;

  //calculate max height of the widgets
  for each (var column in gMyworldWidgets) {
    var widget = document.getElementById(column.id);
    if (widget && widget.childNodes[1] &&
        widget.getAttribute("hidden") != "true") {
      var colDoc = widget.childNodes[1].contentDocument.documentElement;
      if (colDoc.lastChild.boxObject) {
        var colHeight = colDoc.lastChild.boxObject.height;
        if (colHeight > columnContainerHeight) {
          //take into account the height for the widget header
          var headerOffset = widget.firstChild.boxObject.height;
          columnContainerHeight = colHeight + headerOffset;
        }
      }
    }
  }
  //set the size of the container
  document.getElementById("ftcontainerID")
          .setAttribute("style", "min-height:" + columnContainerHeight + "px");
}

function resizeFunction(aEvent) {
  var windowWidth = document.defaultView.innerWidth;

  var titleWidth = document.getElementById("titleID").boxObject.width;
  var searchBoxWidth = document.getElementById("searchBoxID").boxObject.width;

  if (windowWidth > (titleWidth + searchBoxWidth)) {
    var differenceWidth = windowWidth - (titleWidth + searchBoxWidth);
    document.getElementById("titleSpacerID")
            .setAttribute("width", differenceWidth - 80);
  } else {
    document.getElementById("titleSpacerID").setAttribute("width", "0");
  }
}

function popupWhatsThis(node) {
  var widgetVbox = node.parentNode.parentNode.parentNode;
  var sb = SBS.createBundle(widgetVbox.getAttribute("properties_url"));
  var popup = document.getElementById("whatsThisPopup");
  var div = document.getElementById("whatsThisText");
  div.innerHTML = getBrandedString(node.getAttribute("desc"), sb);
  popup.showPopup(node, -1, -1, "popup", "bottomleft", "topleft");
}

function trendsClicked(aWidgetId) {
  const TRENDS_DECK_RESULTS = 0;
  const TRENDS_DECK_THROBBER = 1;
  const TRENDS_DECK_ERROR = 2;

  var twitterSearch = Cc[TS_CONTRACT_ID]
                      .getService(Ci.flockITwitterSearch);
  var panel = document.getElementById("trends-panel");
  var box = document.getElementById("trends-box");
  var deck = document.getElementById("trends-deck");
  var button = document.getElementById(aWidgetId + "-twitter-trends-button");

  var trendsListener = {
    onSuccess: function trendsListener_onSuccess(aSubject, aTopic) {
      // Empty the menupopup
      while(box.firstChild) {
        box.removeChild(box.firstChild);
      }

      // Add new trends to menupopup
      var trends = aSubject.wrappedJSObject.trends;
      for (var i = 0; i < trends.length; i++) {
        var trend = trends[i];
        var label = document.createElement("label");
        label.setAttribute("value", trend.name);
        label.setAttribute("class", "trend");
        label.setAttribute("crop", "end");
        var command = "loadTrend('" + escape(trend.query) + "', '"
                    + aWidgetId +"');";
        label.setAttribute("onclick", command);
        box.appendChild(label);
      }
      
      deck.selectedIndex = TRENDS_DECK_RESULTS;
    },
    onError: function trendsListener_onError(aFlockError, aTopic) {
      deck.selectedIndex = TRENDS_DECK_ERROR;
    }
  };

  deck.selectedIndex = TRENDS_DECK_THROBBER;
  panel.showPopup(button, -1, -1, "popup", "bottomleft", "topleft");
  twitterSearch.getTrends(trendsListener);
  
  gMetrics.report("MyWorldTwitterWidget-Trends", null);
}

function loadTrend(aTrendQuery, aWidgetId) {
  document.getElementById("trends-panel").hidePopup();
  var textbox = document.getElementById(aWidgetId + "-twitter-search-textbox");
  textbox.value = unescape(aTrendQuery);
  textbox.setAttribute("value", textbox.value);
  document.getElementById(aWidgetId + "-twitter-save-search-button")
          .removeAttribute("disabled");
  doSearch(aWidgetId);
}

function twitterSearchOnKeyUp(aWidgetId, aEvent) {
  // Save value property as attribute so we can persist it.
  var searchTextBox
    = document.getElementById(aWidgetId + "-twitter-search-textbox");
  searchTextBox.setAttribute("value", searchTextBox.value);

  // Disable the save button if there is no text.
  var savebutton
    = document.getElementById(aWidgetId + "-twitter-save-search-button");
  if (!searchTextBox.value) {
    savebutton.setAttribute("disabled", "true");
  } else {
    savebutton.removeAttribute("disabled");
  }

  if (aEvent.keyCode == KeyEvent.DOM_VK_RETURN) {
    gMetrics.report("MyWorldTwitterWidget-Search", [{ from: "keypress" }]);
    doSearch(aWidgetId);
  } else if (aEvent.keyCode == KeyEvent.DOM_VK_ESCAPE) {
    twitterSearchDisengage(aWidgetId);
  }
}

function doSearch(aWidgetId) {
  var searchTextBox
    = document.getElementById(aWidgetId + "-twitter-search-textbox");
  var twitterSearch = document.getElementById(aWidgetId + "-iframe")
                              .contentWindow
                              .wrappedJSObject
                              .gTwitterSearch;
  if (searchTextBox.value) {
    var formHistory = Cc["@mozilla.org/satchel/form-history;1"]
                      .getService(Components.interfaces.nsIFormHistory2);
    formHistory.addEntry("twitter-search", searchTextBox.value);
    twitterSearch.enableSearch(searchTextBox.value);
  } else {
    twitterSearch.disableSearch();
  }
  searchTextBox.setAttribute("currentSearchTerm", searchTextBox.value)
  twitterSearchDisengage(aWidgetId);
}

function twitterSearchDisengage(aWidgetId) {
  var searchTextBox
    = document.getElementById(aWidgetId + "-twitter-search-textbox");
  var currentSearchTerm = searchTextBox.getAttribute("currentSearchTerm");
  searchTextBox.value = currentSearchTerm;
}

// Change the Twitter search widget into a saved search widget. Then add
// a new search widget to the left.
function saveTwitterSearch(aWidgetId) {
  var widget = document.getElementById(aWidgetId);
  var textBox = document.getElementById(aWidgetId + "-twitter-search-textbox");

  // Execute a new search if the textbox value is different that the
  // current search term.
  if (textBox.value != textBox.getAttribute("currentSearchTerm")) {
    var twitterSearch = document.getElementById(aWidgetId + "-iframe")
                                .contentWindow
                                .wrappedJSObject
                                .gTwitterSearch;
    var formHistory = Cc["@mozilla.org/satchel/form-history;1"]
                      .getService(Components.interfaces.nsIFormHistory2);
    formHistory.addEntry("twitter-search", textBox.value);
    twitterSearch.enableSearch(textBox.value);
    textBox.setAttribute("currentSearchTerm", textBox.value)
    gMetrics.report("MyWorldTwitterWidget-Search", [{ from: "button" }]);
  }

  // Convert widget header UI.
  if (textBox.value) {
    var index = widget.getAttribute("col_index");
    var column = gMyworldWidgets[index];
    var twitterSearch = document.getElementById(aWidgetId + "-iframe")
                                .contentWindow
                                .wrappedJSObject
                                .gTwitterSearch;

    // Search terms that begin with "#", and only contain alpha-numeric
    // or "-" characters are considered hashtags. If detect hashtag,
    // create topic widget. Otherrwise create saved search widget.
    if (textBox.value.match(/^#[a-zA-Z0-9\-]+$/)) {
      column.type = "twittertopic";

      var spacer
        = document.getElementById(aWidgetId + "-twitter-topic-button-spacer");
      var topicbutton
        = document.getElementById(aWidgetId + "-twitter-topic-button");
      var loginbutton
        = document.getElementById(aWidgetId + "-twitter-login-button");
      spacer.removeAttribute("hidden");
      if (twitterSearch.getAuthTwitterAccount()) {
        topicbutton.removeAttribute("hidden");
      } else {
        loginbutton.removeAttribute("hidden");
      }
      topicbutton.setAttribute("currentSearchTerm", textBox.value)
    } else {
      column.type = "twittersave";
    }

    // Set widget title and tooltip.
    var title = document.getElementById(aWidgetId + "-title-label");
    var sb = SBS.createBundle(column.properties_url);
    var txt = sb.GetStringFromName("flock.myworld." + column.type + ".title")
            + " " + textBox.value;
    title.setAttribute("value", txt);
    title.setAttribute("tooltiptext", txt);

    var image = document.getElementById(aWidgetId + "-whatsthis-image");
    var button = document.getElementById(aWidgetId + "-twitter-search-button");
    var savebutton
      = document.getElementById(aWidgetId + "-twitter-save-search-button");
    var trendsbutton
      = document.getElementById(aWidgetId + "-twitter-trends-button");
    var subTitle = document.getElementById(aWidgetId + "-subtitle-label");
    var tooltip = "flock.myworld." + column.type + ".tooltip";
    image.setAttribute("desc", tooltip);
    image.removeAttribute("hidden");
    subTitle.removeAttribute("hidden");
    textBox.setAttribute("hidden", "true");
    button.setAttribute("hidden", "true");
    savebutton.setAttribute("hidden", "true");
    trendsbutton.setAttribute("hidden", "true");
    subTitle.value
      = sb.GetStringFromName("flock.myworld." + column.type + ".subTitle2");

    addTwitterSearch(parseInt(index) + 1);
    gMetrics.report("MyWorldTwitterWidget-Save", [{ type: column.type }]);
  } else {
    twitterSearchDisengage(aWidgetId);
  }
}

function addTwitterSearch(aBeforeIndex) {
  var nsJSON = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);

  var now = (new Date()).getTime();
  var column = {
    id: "twittersearch:" + now,
    label: "twittersearch",
    url: "chrome://flock/content/start/twittersearch.xul?id=" + now,
    properties_url: "chrome://flock/locale/start/myworld.properties",
    multiple: "true",
    show: "true"
  };

  openWidget(column, SBS.createBundle(column.properties_url), aBeforeIndex);

  if (aBeforeIndex) {
    gMyworldWidgets.splice(aBeforeIndex, 0, column);
  } else {
    gMyworldWidgets.push(column);
  }

  updateCurrentColumnLayout();
}

function twitterTopicButtonClicked(aWidgetId) {
  var wm = Cc["@mozilla.org/appshell/window-mediator;1"]
           .getService(Ci.nsIWindowMediator);
  var win = wm.getMostRecentWindow("navigator:browser");

  var peopleSBBroadcaster
    = win.document.getElementById("flockPeopleSidebarBroadcaster");

  var topicbutton
    = document.getElementById(aWidgetId + "-twitter-topic-button");
  var searchTerm = topicbutton.getAttribute("currentSearchTerm");

  if (peopleSBBroadcaster.getAttribute("checked")) {
    this.os.notifyObservers(null,
                           "flock-people-trigger-status-change",
                           searchTerm);
  } else {
    peopleSBBroadcaster.setAttribute("prePopStatusText", searchTerm);
    win.toggleSidebar("flockPeopleSidebarBroadcaster",
                      "PeopleSidebar-Open",
                      null,
                      "MyWorldPostTopicClick",
                      true);
  }

  gMetrics.report("MyWorldTwitterWidget-PostToTopic", null);
}

function twitterLoginButtonClicked(aEvent) {
  var twitterSvc = Cc[TWITTER_CONTRACT_ID]
                   .getService(Ci.flockIWebService);
  openURLMyWorld(twitterSvc.loginURL, aEvent, false);
}

window.onload = onLoad;
window.onunload = onUnload;
