/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

var { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;

var { SpellCheckHelper } = Cu.import("resource://gre/modules/InlineSpellChecker.jsm");

this.EXPORTED_SYMBOLS = [ "InlineSpellCheckerContent" ]

var InlineSpellCheckerContent = {
  _spellChecker: null,
  _manager: null,

  initContextMenu(event, editFlags, messageManager) {
    this._manager = messageManager;

    let spellChecker;
    if (!(editFlags & (SpellCheckHelper.TEXTAREA | SpellCheckHelper.INPUT))) {
      // Get the editor off the window.
      let win = event.target.ownerDocument.defaultView;
      let editingSession = win.QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIWebNavigation)
                              .QueryInterface(Ci.nsIInterfaceRequestor)
                              .getInterface(Ci.nsIEditingSession);
      spellChecker = this._spellChecker =
        new InlineSpellChecker(editingSession.getEditorForWindow(win));
    } else {
      // Use the element's editor.
      spellChecker = this._spellChecker =
        new InlineSpellChecker(event.target.QueryInterface(Ci.nsIDOMNSEditableElement).editor);
    }

    this._spellChecker.initFromEvent(event.rangeParent, event.rangeOffset)

    this._addMessageListeners();

    if (!spellChecker.canSpellCheck) {
      return { canSpellCheck: false,
               initialSpellCheckPending: true,
               enableRealTimeSpell: false };
    }

    if (!spellChecker.mInlineSpellChecker.enableRealTimeSpell) {
      return { canSpellCheck: true,
               initialSpellCheckPending: spellChecker.initialSpellCheckPending,
               enableRealTimeSpell: false };
    }

    let dictionaryList = {};
    let realSpellChecker = spellChecker.mInlineSpellChecker.spellChecker;
    realSpellChecker.GetDictionaryList(dictionaryList, {});

    // The original list we get is in random order. We need our list to be
    // sorted by display names.
    dictionaryList = spellChecker.sortDictionaryList(dictionaryList.value).map((obj) => {
      return obj.id;
    });
    spellChecker.mDictionaryNames = dictionaryList;

    return { canSpellCheck: spellChecker.canSpellCheck,
             initialSpellCheckPending: spellChecker.initialSpellCheckPending,
             enableRealTimeSpell: spellChecker.enabled,
             overMisspelling: spellChecker.overMisspelling,
             misspelling: spellChecker.mMisspelling,
             spellSuggestions: this._generateSpellSuggestions(),
             currentDictionary: spellChecker.mInlineSpellChecker.spellChecker.GetCurrentDictionary(),
             dictionaryList: dictionaryList };
  },

  uninitContextMenu() {
    for (let i of this._messages)
      this._manager.removeMessageListener(i, this);

    this._manager = null;
    this._spellChecker = null;
  },

  _generateSpellSuggestions() {
    let spellChecker = this._spellChecker.mInlineSpellChecker.spellChecker;
    try {
      spellChecker.CheckCurrentWord(this._spellChecker.mMisspelling);
    } catch (e) {
      return [];
    }

    let suggestions = new Array(5);
    for (let i = 0; i < 5; ++i) {
      suggestions[i] = spellChecker.GetSuggestedWord();
      if (suggestions[i].length === 0) {
        suggestions.length = i;
        break;
      }
    }

    this._spellChecker.mSpellSuggestions = suggestions;
    return suggestions;
  },

  _messages: [
      "InlineSpellChecker:selectDictionary",
      "InlineSpellChecker:replaceMisspelling",
      "InlineSpellChecker:toggleEnabled",

      "InlineSpellChecker:recheck",

      "InlineSpellChecker:uninit"
    ],

  _addMessageListeners() {
    for (let i of this._messages)
      this._manager.addMessageListener(i, this);
  },

  receiveMessage(msg) {
    switch (msg.name) {
      case "InlineSpellChecker:selectDictionary":
        this._spellChecker.selectDictionary(msg.data.index);
        break;

      case "InlineSpellChecker:replaceMisspelling":
        this._spellChecker.replaceMisspelling(msg.data.index);
        break;

      case "InlineSpellChecker:toggleEnabled":
        this._spellChecker.toggleEnabled();
        break;

      case "InlineSpellChecker:recheck":
        this._spellChecker.mInlineSpellChecker.enableRealTimeSpell = true;
        break;

      case "InlineSpellChecker:uninit":
        this.uninitContextMenu();
        break;
    }
  }
};
