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

const CC = Components.classes;
const CI = Components.interfaces;
const CU = Components.utils;

CU.import("resource:///modules/FlockCastUtils.jsm");

const SAVE_INT = 10; // in seconds (for recovery)
const FLOCK_RICH_DND_SERVICE_CONTRACTID = "@flock.com/rich-dnd-service;1";
const FLOCK_RICH_CONTENT_FLAVOUR = "application/x-flock-rich-content";

const kXULNS =
      "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";

var gDraftId = null;
var gRecoveryId = null;

var gOverrideParagraphBehavior = false;
// var gHasChanged = false;
var gLastSaved = "";
var gWebService;
var gB;
var gMetricsService = Components.classes["@flock.com/metrics-service;1"]
                      .getService(Components.interfaces.flockIMetricsService);

var gEditor = null;
var gNotificationBox = null;

/*
 * Coop stuff
 */

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

/*
 * Helpers
 */

function getHoursMinutes() {
    var time = new Date();
    var minutes = time.getMinutes();
    var hours = time.getHours();
    if (hours < 10)
        hours = "0" + hours.toString();
    if (minutes < 10)
        minutes = "0" + minutes.toString();

    return hours+':'+minutes;
}

function $(aId) {
  return document.getElementById(aId);
}

var BlogCommandController = {
  getFunctor: function CC_getFunctor(aCmd) {
    if (aCmd in this) {
      return this[aCmd];
    }
    return null;
  },

  supportsCommand: function CC_supportsCommand(aCmd) {
    return (this[aCmd] != null);
  },

  isCommandEnabled: function(aCmd) {
    return (this[aCmd] && this[aCmd].isEnabled());
  },

  doCommand: function(aCmd) {
    this[aCmd].exec();
  },

  doCommandWithParams: function(aCmd, aEnum) {
    var params = flock.lang.toArray(aEnum);
    if (this[aCmd]) {
      if (typeof this[aCmd] == "object" &&
          "exec" in this[aCmd])
      {
        return this[aCmd].exec.apply(this, params);
      }
      return this[aCmd].apply(this, params);
    }
    return null;
  },

  onEvent: function(aEvent) { },

  cmd_flock_blogNewPost: {
    isEnabled: function cmd_flock_blogNewPost_isEnabled () {
      return true;
    },
    exec: function cmd_flock_blogNewPost_exec() {
      flock_blog.service.openEditor("", "", "");
    }
  },

  cmd_flock_blogPublishPost: {
    isEnabled: function cmd_flock_blogPublishPost_isEnabled() {
      return true;
    },
    exec: function cmd_flock_blogPublishPost_exec() {
      // Save the post
      BlogCommandController.cmd_flock_blogSavePost.exec();

      // Setup an account if needed
      if (flock_blog.service.accountCount() == 0) {
        flock_blogOpenWizard();
      }

      var strbundle = document.getElementById("editorStringBundle");
      var msgtxt = strbundle.getString("flock.blog.editor.saver");

      // If the user didn't setup a blog, don't continue
      if (flock_blog.service.accountCount() == 0) {
        message(msgtxt);
        return;
      }

      // Get the xhtml source (from the editor or the source pane)
      var html;
      if (($("editordeck").selectedIndex == 0) ||
          ($("editordeck").selectedIndex == 2)) {
        html = gEditor.getXHtml();
      } else {
        html = $("editsource").value;
      }

      var strbundle = document.getElementById("blogStringBundle");

      var params = {
        title: $("flock-blog-title").value,
        tags: $("flock-blog-tags").value,
        html: html,
        draftId: gDraftId
      };

      window.published = false;
      window.permalink = null;
      window.blogURL = null;
      window.openDialog("blogMetadata.xul", "", "chrome,modal,centerscreen", params);

      if (window.published) {
        // Report to the FB news feed
        if (window.publishFeedStory === true && FlockCastUtils.isActive()) {
          var fbapi = CC["@flock.com/api/facebook;1"]
                      .getService(CI.flockIFacebookAPI);
          var link = window.permalink ? window.permalink : window.blogURL;
          fbapi.reportBlog(null, window.account, params.title, html, link);
        }

        // Open a window showing the blog
        if (window.blogURL) {
          var wm = CC["@mozilla.org/appshell/window-mediator;1"]
                   .getService(CI.nsIWindowMediator);
          recent = wm.getMostRecentWindow("navigator:browser");

          var linkprefs = CC["@mozilla.org/preferences-service;1"]
                          .getService(CI.nsIPrefService)
                          .getBranch("browser.link.");
          var newWindow = linkprefs.getIntPref ("open_newwindow");

          if (newWindow == 2) {
            recent.open(window.blogURL);
          }
          else {
            var browser = recent.document.getElementById("content");
            browser.loadOneTab(window.blogURL, null, null, null, false);
          }
        }

        if (gRecoveryId) {
          flock_blog.service.removeRecovery(gRecoveryId);
        }

        window._timer.cancel();
        window._timer = null;
        window.close();
      }
      else {
        message(msgtxt);
      }
    }
  },

  cmd_flock_blogSavePost: {
    isEnabled: function cmd_flock_blogSavePost_isEnabled() {
      return hasChanged();
    },
    exec: function cmd_flock_blogSavePost_exec() {
      var html;
      if (($("editordeck").selectedIndex == 0) ||
          ($("editordeck").selectedIndex == 2)) {
        html = gEditor.getXHtml();
      } else {
        html = $("editsource").value;
      }

      gDraftId = flock_blog.service
                           .saveDraft(gDraftId,
                                      document.getElementById("flock-blog-title")
                                              .value,
                                      html,
                                      document.getElementById("flock-blog-tags")
                                              .value);
      updateLastSaved();
      goUpdateCommand("cmd_flock_blogSavePost");
    }
  },

  cmd_flock_blogOpenPost: {
    isEnabled: function cmd_flock_blogOpenPost_isEnabled() {
      return true;
    },
    exec: function cmd_flock_blogOpenPost_exec() {
      window.openDialog("chrome://flock/content/blog/blogOpenPost.xul",
                        "openDraftDialog", "chrome,modal,centerscreen", null);
    }
  },

  cmd_flock_blogClose: {
    isEnabled: function cmd_flock_blogClose_isEnabled() {
      return true;
    },
    exec: function cmd_flock_blogClose_exec() {
      if (editorOnclose()) {
        window._timer.cancel();
        window._timer = null;
        window.close();
      }
    }
  },

  cmd_flock_blogLink: {
    isEnabled: function cmd_flock_blogLink_isEnabled() {
      return gEditor.linkEnabled();
    },
    exec: function cmd_flock_blogLink_exec() {
      gEditor.link();
    }
  },

  cmd_flock_blogUnlink: {
    isEnabled: function cmd_flock_blogUnlink_isEnabled() {
      return gEditor.unlinkEnabled();
    },
    exec: function cmd_flock_blogUnlink_exec() {
      gEditor.execCommand("unlink");
    }
  }
};

/*
 * load/close functions
 */

editorOnload = function() {
  gMetricsService.report("BlogDialog-Opened", null);

  if (window.arguments) {
    var params = window.arguments[0].QueryInterface(Components.interfaces.nsIDialogParamBlock);
    gDraftId = params.GetString(0);
  }
  else {
    gDraftId = null;
  }

  var title = "";
  var content = "";
  var tags = "";

  // Hide unwanted stuff designed for browser.xul
  $('viewTopbarMenu').setAttribute('hidden', 'true');

  gNotificationBox = $("notificationBox");
  gEditor = new editorWidget($('editordeck'), $('edit'));
  updateLastSaved();

  if (gDraftId) { // Load post
    var draft = flock_blog.service.getDraft(gDraftId);
    if (draft) {
      title = draft.title;
      content = draft.content;
      tags = draft.tags;
    }
  }
  else { // new post
    title = params.GetString(1);
    content = params.GetString(2);
    tags = params.GetString(3);
  }

  if (content && content != "")
    gEditor.setContent(content);
  if (title != "")
    $("flock-blog-title").setAttribute("value", title);
  $("flock-blog-tags").value = tags;

  flock_blogEditorSetTitle();
  window.document.commandDispatcher.updateCommands('focus');

  try { $("flock-blog-title").select(); } catch(e) { }

  if (gDraftId) {
    // We only run it for 'open post', not for 'blog this' before we want the
    // the confirmation dialog to appear after Blog This even if the user didn't touch
    // the post
    updateLastSaved();
  }

  window.controllers.appendController(BlogCommandController);
  window.addEventListener("focus",
    function blog_onfocus() {
      window.document.commandDispatcher.updateCommands("focus");
    },
    false);
  window.addEventListener("click",
    function blog_onclick() {
      window.document.commandDispatcher.updateCommands("click");
    },
    false);
  window.document.commandDispatcher.updateCommands("focus");
  
  // autosave for recovery
  var sync = {
    notify: function saveRecovery(aTimer) {
      if (!window.document) {
        // Clear the timer when the blog editor window is closed
        if (aTimer) {
          aTimer.cancel();
        }
        return;
      }

      var html = window.document.getElementById("editsource").value;
      if (($("editordeck").selectedIndex == 0) ||
          ($("editordeck").selectedIndex == 2))
      {
        html = gEditor.getXHtml();
      }

      var title = window.document.getElementById("flock-blog-title").value;
      var tags = window.document.getElementById("flock-blog-tags").value;
      gRecoveryId =
        flock_blog.service.saveRecovery(gRecoveryId, title, html, tags);
    }
  }

  window._timer = CC["@mozilla.org/timer;1"].createInstance(CI.nsITimer);
  window._timer.initWithCallback(sync, SAVE_INT * 1000, 
                                 CI.nsITimer.TYPE_REPEATING_SLACK);
};


editorOnunload = function() {
  gMetricsService.report("BlogDialog-Close", null);
  window.controllers.removeController(BlogCommandController);
}


editorOnclose = function() {
  var close = flock_blogEditorCanClose();
  if (close) {
    if (gRecoveryId)
      flock_blog.service.removeRecovery(gRecoveryId);
    try { 
      gEditor.uninit(); 
    } catch(e) { } 
  }
  return close;
};

/*
 * Toolbar customization
 */

function BrowserCustomizeToolbar()
{
  window.openDialog("chrome://flock/content/blog/customizeToolbar.xul",
                    "CustomizeToolbar",
                    "chrome,all,dependent",
                    document.getElementById("shelfEditorToolbox"));
}

/*
 * Function related to saving drafts
 */

function flock_blogEditorCanClose()
{
  var result;
  var strbundle=document.getElementById("editorStringBundle");
  var saveentry=strbundle.getString("flock.blog.post.save.entry");
  var doyouwanttosave=strbundle.getString("flock.blog.post.save.draft");

  if(!hasChanged())
    return true;

  var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
  var flags=promptService.BUTTON_TITLE_SAVE * promptService.BUTTON_POS_0 +
      promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_1 +
      promptService.BUTTON_TITLE_DONT_SAVE * promptService.BUTTON_POS_2;

  result = promptService.confirmEx(window, saveentry, doyouwanttosave, flags,
       null, null, null, null, {});
  
  switch (result){
    case 0: // Save
      BlogCommandController.doCommand("cmd_flock_blogSavePost");
      return true;
    case 1: // Cancel
      return false;
    case 2: // Don't save
      return true;
    default:
      return true;
  }
}


function onClickInEditor(event)
{
  $('edit').contentWindow.focus();
  if (event.rangeParent && (event.rangeParent.nodeName == "BODY")) {
    if (!gEditor.getXHtml().match(/[^\s\n]/))
      gEditor.mNSHTMLEditor.beginningOfDocument();
  }
}


function flock_blogEditorSetTitle() {
    var strbundle = document.getElementById("editorStringBundle");
    var title = strbundle.getString("flock.blog.settitle.message") + " " + $("flock-blog-title").value;
    // window.title = title;
    window.document.title = title;
}


function updateLastSaved() {
  gLastSaved = $("flock-blog-title").value + gEditor.getXHtml() + $('flock-blog-tags').value;
}


function onTitleKeypress(aEvent) {
  // gHasChanged = true;
  switch(aEvent.keyCode) {
    case aEvent.DOM_VK_TAB:
      if (gEditor.viewSource)
        $('editsource').focus();
      else {
        $('edit').contentWindow.focus();
        if (!gEditor.getXHtml().match(/[^\s\n]/))
          gEditor.mNSHTMLEditor.beginningOfDocument();
      }
      aEvent.preventDefault();
      break;
    default:
      ;
    }
};


function hasChanged() {
  return (gLastSaved != $("flock-blog-title").value + gEditor.getXHtml() + $('flock-blog-tags').value);
}


function onEditorKeypress(e) {
  goUpdateCommand("cmd_flock_blogSavePost");
}


/*
 * Sidebar
 */

// |forceOpen| is a bool that indicates that the sidebar should be forced open.  In other words
// the toggle won't be allowed to close the sidebar.
function toggleSidebar(aCommandID, forceOpen) {

  var sidebarBox = document.getElementById("sidebar-box");
  if (!aCommandID)
    aCommandID = sidebarBox.getAttribute("sidebarcommand");

  var elt = document.getElementById(aCommandID);
  var sidebar = document.getElementById("sidebar");
  var sidebarTitle = document.getElementById("sidebar-title");
  var sidebarSplitter = document.getElementById("sidebar-splitter");

  if (!forceOpen && elt.getAttribute("checked") == "true") {
    elt.removeAttribute("checked");
    sidebarBox.setAttribute("sidebarcommand", "");
    sidebarTitle.setAttribute("value", "");
    sidebarBox.hidden = true;
    sidebarSplitter.hidden = true;
    if (aCommandID != "flock_NewsSidebarBroadcaster" && content) {
      content.focus();
    }
    return;
  }

  var elts = document.getElementsByAttribute("group", "sidebar");
  for (var i = 0; i < elts.length; ++i)
    elts[i].removeAttribute("checked");

  elt.setAttribute("checked", "true");;

  if (sidebarBox.hidden) {
    sidebarBox.hidden = false;
    sidebarSplitter.hidden = false;
  }

  var url = elt.getAttribute("sidebarurl");
  var title = elt.getAttribute("sidebartitle");
  if (!title)
    title = elt.getAttribute("label");
  sidebar.setAttribute("src", url);
  sidebarBox.setAttribute("src", url);
  sidebarBox.setAttribute("sidebarcommand", elt.id);
  sidebarTitle.setAttribute("value", title);
}

// |aCommandId| the command id of the sidebar that has just been toggled.
// |aMetricsKey| [optional] is a string that represents the metrics key that
// will be used if the sidebar is opened.  Metrics not reporting if this arg
// is not supplied.
// |aTarget| [optional] the event.target that is responsible for toggleSidebar
// being called.
// |aMetricsSource| [optional] is a string that represents the source of the
// toggle. If not supplied, aTarget will be used to generate this string.  If
// supplied, aTarget will be ignored.
function reportOpenMetric(aCommandID, aMetricsKey, aTarget, aMetricsSource) {
  var sidebarBox = document.getElementById("sidebar-box");
  if (!aCommandID) {
    aCommandID = sidebarBox.getAttribute("sidebarcommand");
  }

  var elt = document.getElementById(aCommandID);
  var metricsValue = "Unknown";

  if (elt.getAttribute("checked") != "true") {
    // The sidebar is not already open/visible
    if (aMetricsKey) {
      // Only report if a metrics key was passed in
      if (aMetricsSource) {
        // An explicit source was passed in, we'll use it
        metricsValue = aMetricsSource;
      } else {
        // No explicit source as passed in, we will try to generate one from
        // aTarget
        if (aTarget && aTarget instanceof CI.nsIDOMElement) {
          if (aTarget.namespaceURI == kXULNS && aTarget.localName) {
            metricsValue  = aTarget.localName;
#ifdef XP_MACOSX
            if (aTarget.localName  == "menuitem") {
              // Mac OS seems to have a bug where if a menu item is accessed via
              // either a menu item click or a keyboard sortcut then the
              // target.localName will be "menuitem" where as in other OS's it
              // will be "key" for keyboard shortcut and "menuitem" for menu
              metricsValue += "/key";
            }
#endif
            if (aTarget.id) {
              // Append the id to the localName so we have a good idea what
              // element was responsible for calling us.
              metricsValue += "-" + aTarget.id;
            }
          }
        }
      }
      gMetricsService.report(aMetricsKey, metricsValue);
    }
  }
}

// |aCommandId| id of the sidebar that is about to be toggled.
// |aMetricsKey| [optional] is a string that represents the metrics key that
// will be used if the sidebar is opened.  Metrics not reporting if this arg
// is not supplied.
// |aTarget| [optional] the event.target that is responsible for toggleSidebar
// being called.
// |aMetricsSource| [optional] is a string that represents the source of the
// toggle. If not supplied, aTarget will be used to generate this string.  If
// supplied, aTarget will be ignored.
// |aForceOpen| is a bool that indicates that the sidebar should be forced open.  In other words
// the toggle won't be allowed to close the sidebar.
function toggleSidebarWithMetric(aCommandID, aMetricsKey, aTarget, aMetricsSource, aForceOpen) {
  reportOpenMetric(aCommandID, aMetricsKey, aTarget, aMetricsSource);
  toggleSidebar(aCommandID, aForceOpen);
}

function editImageContext() {
  var node = gEditor.mNSHTMLEditor.selection.getRangeAt(0).cloneContents().firstChild;
  if (node.nodeName != "IMG")
    return;

  var params = {
    URL: node.getAttribute("src"),
    title: node.getAttribute("title"),
    alt: node.getAttribute("alt"),
    cancelled: false,
    align: ""
  };
  if (node.hasAttribute("style")) {
    if (node.getAttribute("style").match("left"))
      params.align = "left";
    else if (node.getAttribute("style").match("right"))
      params.align = "right";
    else if (node.getAttribute("style").match("center"))
      params.align = "center";
  }

  window.openDialog("chrome://flock/content/blog/imageProperties.xul",
                    "_blank", "modal,centerscreen", params);
  if (!params.cancelled) {
    var style;
    switch (params.align) {
      case "left":
        style="margin: 10px 10px 0pt 0pt; float: left;";
        break;
      case "right":
        style="margin: 0pt 0pt 10px 10px; float: right;";
        break;
      case "center":
        style="margin: 0px auto 10px; display: block; text-align: center;";
        break;
      default:
        style="";
    }

    imgnode = gEditor.mNSHTMLEditor.getSelectedElement ('img');
    imgnode.setAttribute("src", params.URL);
    imgnode.setAttribute("title", params.title);
    imgnode.setAttribute("alt", params.alt);
    imgnode.setAttribute("style", style);
  }
}

function updateContextMenuImage(event) {
  var node = gEditor.mNSHTMLEditor.selection.getRangeAt(0).cloneContents().firstChild;
  if (node)
    $("edit-image-context").hidden = (node.nodeName != "IMG");
  else
    $("edit-image-context").hidden = true;
}

/*
 * Spellchecking
 */

function updateContextMenu(event) {
  InlineSpellCheckerUI.clearSuggestionsFromMenu();
  InlineSpellCheckerUI.clearDictionaryListFromMenu();

  InlineSpellCheckerUI.init(gEditor.mNSHTMLEditor);
  InlineSpellCheckerUI.initFromEvent(document.popupRangeParent, document.popupRangeOffset);

  var canSpell = InlineSpellCheckerUI.canSpellCheck;
  var onMisspelling = InlineSpellCheckerUI.overMisspelling;
  $("spell-check-enabled").hidden = !canSpell;
  // $("spell-separator").hidden = !(canSpell || this.possibleSpellChecking);
  $("spell-separator").hidden = canSpell;
  if (canSpell)
    document.getElementById("spell-check-enabled").setAttribute("checked", InlineSpellCheckerUI.enabled);
  $("spell-add-to-dictionary").hidden = !onMisspelling;

  // suggestion list
  $("spell-suggestions-separator").hidden = !onMisspelling;
  if (onMisspelling) {
      var menu = $("blogEditorContext");
      var suggestionsSeparator = document.getElementById("spell-add-to-dictionary");
      var numsug = InlineSpellCheckerUI.addSuggestionsToMenu (menu, suggestionsSeparator , 5);
      $("spell-no-suggestions").hidden = (numsug > 0);
  } else {
      $("spell-no-suggestions").hidden = true;
  }

  // dictionary list
  $("spell-dictionaries").hidden = !InlineSpellCheckerUI.enabled;
  if (canSpell) {
    var dictMenu = $("spell-dictionaries-menu");
    var dictSep = $("spell-language-separator");
    InlineSpellCheckerUI.addDictionaryListToMenu(dictMenu, dictSep);
  }
}

function formatURL(aFormat, aIsPref) {
  var formatter = Components.classes["@mozilla.org/toolkit/URLFormatterService;1"].getService(Components.interfaces.nsIURLFormatter);

  return aIsPref ? formatter.formatURLPref(aFormat) : formatter.formatURL(aFormat);
}

function addDictionaries() {
  var uri = formatURL("browser.dictionaries.download.url", true);

  var locale = "-";
  try {
    var prefService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
    locale = prefService.getComplexValue("intl.accept_languages", Components.interfaces.nsIPrefLocalizedString).data;
  }
  catch (e) { }

  var version = "-";
  try {
    version = Components.classes["@mozilla.org/xre/app-info;1"]
                            .getService(Components.interfaces.nsIXULAppInfo)
                            .version;
  }
  catch (e) { }

  uri = uri.replace(/%LOCALE%/, escape(locale));
  uri = uri.replace(/%VERSION%/, version);

  var prefService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
  var newWindowPref = prefService.getIntPref("browser.link.open_newwindow");
  var where = newWindowPref == 3 ? "tab" : "window";

  openUILinkIn(uri, where);
}


/*
 * Stuff that I don't know where to put
 */

function ljuser()
{
  var strbundle = document.getElementById("editorStringBundle");
  var msgtxt = strbundle.getString("flock.blog.editor.lj.msg");

  var userid = prompt(msgtxt, "");
  var html = '<lj user="'+userid+'">';
  $('edit').contentWindow.document.execCommand("inserthtml", false, html);
}

function execCommand(cmd)
{
  $('edit').contentWindow.document.execCommand(cmd, false, null);
}

function message(aText) {
  const priority = gNotificationBox.PRIORITY_INFO_LOW;
  gNotificationBox.appendNotification(aText, "blog-autosave",
                                              "chrome://flock/skin/common/Info.png",
                                               priority, null);
}

function openBlogHelp() {
  window.open('http://help.flock.com/content.php?title=_Writing___Editing_Blog_Posts', 'FlockHelp', 'width=555,height=545,resizable,scrollbars');
}

var editorDNDObserver =
{
  onDragOver: function eDND_onDragOver(aEvent, aFlavour, aDragSession) {
  },

  onDrop: function eDND_onDrop(aEvent, aXferData, aDragSession)
  {
    // Bail if we are not dragging rich content
    if (!aDragSession.isDataFlavorSupported(FLOCK_RICH_CONTENT_FLAVOUR)) {
      return;
    }

    var target = aEvent.target;
    if (target.localName.toLowerCase() == "html") {
      // Get the BODY element
      target = target.lastChild;
    }

    // Drop content on the target
    if (target instanceof CI.nsIDOMXULTextBoxElement &&
        target.id == "editsource")
    {
      // Plaintext
      var caretPos = target.selectionEnd;
      var currentValue = target.value;
      target.value = currentValue.substring(0, caretPos)
                   + this._addRichContent(aDragSession)
                   + currentValue.substring(caretPos);
      // Note: We do not need to add the breadcrumb in this case
    } else if (target instanceof CI.nsIDOMHTMLBodyElement &&
               target.id == "editor-body")
    {
      // Richtext
      var doc = target.ownerDocument;
      if (doc instanceof CI.nsIDOMHTMLDocument) {
        // Drop rich content at current insertion point
        // (Currently does not follow the mouse cursor!)
        doc.execCommand("insertHTML",
                        false,
                        this._addRichContent(aDragSession));
      }
      // Note: We do not need to add the breadcrumb in this case
    }
  },

  getSupportedFlavours: function eDND_getSupportedFlavours()
  {
    var flavours = new FlavourSet();
    flavours.appendFlavour(FLOCK_RICH_CONTENT_FLAVOUR);
    return flavours;
  },

  _addRichContent: function eDND__addRichContent(aDragSession)
  {
    var service = CC[FLOCK_RICH_DND_SERVICE_CONTRACTID]
                  .getService(CI.flockIRichDNDService);
    var flavours = service.getRichSelection(aDragSession, null, null);
    var dataObj = {};
    var len = {};
    flavours.getTransferData("text/html", dataObj, len);
    return dataObj.value.QueryInterface(CI.nsISupportsString).data;
  }
}

/*
 * Imported from browser.js and simplified (because we know that
 * the current window is not a browser, so we don't need to keep the charset)
 */
function OpenBrowserWindow() {
  var handler = CC["@mozilla.org/browser/clh;1"]
                .getService(CI.nsIBrowserHandler);
  var defaultArgs = handler.defaultArgs;

  win = window.openDialog("chrome://browser/content/",
                          "_blank",
                          "chrome,all,dialog=no",
                          defaultArgs);

  return win;
}
