/* 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";

const {
  createFactory,
} = require("resource://devtools/client/shared/vendor/react.mjs");

const TextNode = createFactory(
  require("resource://devtools/client/inspector/markup/components/TextNode.js")
);

loader.lazyRequireGetter(
  this,
  "getAutocompleteMaxWidth",
  "resource://devtools/client/inspector/markup/utils.js",
  true
);
loader.lazyRequireGetter(
  this,
  "getLongString",
  "resource://devtools/client/inspector/shared/utils.js",
  true
);
loader.lazyRequireGetter(
  this,
  "InplaceEditor",
  "resource://devtools/client/shared/inplace-editor.js",
  true
);

/**
 * Creates a simple text editor node, used for TEXT and COMMENT
 * nodes.
 */
class TextEditor {
  /**
   * @param  {MarkupContainer} container
   *         The container owning this editor.
   * @param  {DOMNode} node
   *         The node being edited.
   * @param  {string} type
   *         The type of editor to build. This can be either 'text' or 'comment'.
   */
  constructor(container, node, type) {
    this.container = container;
    this.markup = this.container.markup;
    this.node = node;
    this._selected = false;

    this.showTextEditor = this.showTextEditor.bind(this);

    this.buildMarkup(type);
  }
  buildMarkup(type) {
    const doc = this.markup.doc;

    this.elt = doc.createElement("span");
    this.elt.classList.add("editor", type);

    getLongString(this.node.getNodeValue()).then(value => {
      this.textNode = this.ReactDOM.render(
        TextNode({
          showTextEditor: this.showTextEditor,
          type,
          value,
        }),
        this.elt
      );
    });
  }

  get ReactDOM() {
    // Reuse the toolbox's ReactDOM to avoid loading react-dom.js again in the
    // Inspector's BrowserLoader.
    return this.container.markup.inspector.ReactDOM;
  }

  get selected() {
    return this._selected;
  }

  set selected(value) {
    if (value === this._selected) {
      return;
    }
    this._selected = value;
    this.update();
  }

  showTextEditor(element) {
    new InplaceEditor({
      cssProperties: this.markup.inspector.cssProperties,
      done: (val, commit) => {
        if (!commit) {
          return;
        }
        getLongString(this.node.getNodeValue()).then(oldValue => {
          this.container.undo.do(
            () => {
              this.node.setNodeValue(val);
            },
            () => {
              this.node.setNodeValue(oldValue);
            }
          );
        });
      },
      element,
      maxWidth: () => getAutocompleteMaxWidth(element, this.container.elt),
      multiline: true,
      stopOnReturn: true,
      trimOutput: false,
    });
  }

  async update() {
    try {
      const value = await getLongString(this.node.getNodeValue());

      if (this.textNode.state.value !== value) {
        this.textNode.setState({ value });
      }
    } catch (e) {
      console.error(e);
    }
  }

  destroy() {
    this.ReactDOM.unmountComponentAtNode(this.elt);
  }

  /**
   * Stub method for consistency with ElementEditor.
   */
  getInfoAtNode() {
    return null;
  }
}

module.exports = TextEditor;
