"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.RemoteSelection = void 0;

var _tinycolor = require("@ctrl/tinycolor");

var _Validation = require("./Validation");

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

var RemoteSelection =
/*#__PURE__*/
function () {
  _createClass(RemoteSelection, null, [{
    key: "_addDynamicStyleElement",

    /**
     * A helper method to add a style tag to the head of the document that will
     * style the color of the selection. CodeMirror only allows setting the
     * class name of decorations, so we can not set a style property directly.
     * This method will create, add, and return the style tag for this element.
     *
     * @param className
     *   The className to use as the css selector.
     * @param color
     *   The color to set for the selection.
     * @returns
     *   The style element that was added to the document head.
     *
     * @private
     * @internal
     */
    value: function _addDynamicStyleElement(className, color) {
      _Validation.Validation.assertString(className, "className");

      _Validation.Validation.assertString(color, "color");

      var rgbaColor = new _tinycolor.TinyColor(color).setAlpha(0.3).toRgbString();
      var css = ".".concat(className, " {\n         background-color: ").concat(rgbaColor, ";\n       }").trim();
      var styleElement = document.createElement("style");
      styleElement.innerText = css;
      document.head.appendChild(styleElement);
      return styleElement;
    }
    /**
     * A helper method to ensure the start position is before the end position.
     *
     * @param start
     *   The current start position.
     * @param end
     *   The current end position.
     * @return
     *   An object containing the correctly ordered start and end positions.
     *
     * @private
     * @internal
     */

  }, {
    key: "_swapIfNeeded",
    value: function _swapIfNeeded(start, end) {
      if (start.line < end.line || start.line === end.line && start.ch <= end.ch) {
        return {
          start: start,
          end: end
        };
      } else {
        return {
          start: end,
          end: start
        };
      }
    }
    /**
     * The userland id of the selection.
     * @internal
     */

  }]);

  /**
   * Constructs a new remote selection.
   *
   * @internal
   */
  function RemoteSelection(codeEditor, id, classId, color, onDisposed) {
    _classCallCheck(this, RemoteSelection);

    this._editor = codeEditor;
    this._id = id;
    this._className = "codemirror-remote-selection-".concat(classId);
    this._styleElement = RemoteSelection._addDynamicStyleElement(this._className, color);
    this._onDisposed = onDisposed;
  }
  /**
   * Gets the userland id of this selection.
   */


  _createClass(RemoteSelection, [{
    key: "getId",
    value: function getId() {
      return this._id;
    }
    /**
     * Gets the start position of the selection.
     *
     * @returns
     *   The start position of the selection.
     */

  }, {
    key: "getStartPosition",
    value: function getStartPosition() {
      return _objectSpread({}, this._startPosition);
    }
    /**
     * Gets the start position of the selection.
     *
     * @returns
     *   The start position of the selection.
     */

  }, {
    key: "getEndPosition",
    value: function getEndPosition() {
      return _objectSpread({}, this._endPosition);
    }
    /**
     * Sets the selection using zero-based text indices.
     *
     * @param start
     *   The start index to set the selection to.
     * @param end
     *   The end index to set the selection to.
     */

  }, {
    key: "setIndices",
    value: function setIndices(start, end) {
      var startPosition = this._editor.posFromIndex(start);

      var endPosition = this._editor.posFromIndex(end);

      this.setPositions(startPosition, endPosition);
    }
    /**
     * Sets the selection using CodeMirrors's line / ch coordinate system.
     *
     * @param start
     *   The start position to set the selection to.
     * @param end
     *   The end position to set the selection to.
     */

  }, {
    key: "setPositions",
    value: function setPositions(start, end) {
      // this._decorations = this._editor.deltaDecorations(this._decorations, []);
      var ordered = RemoteSelection._swapIfNeeded(start, end);

      this._startPosition = ordered.start;
      this._endPosition = ordered.end;

      this._render();
    }
    /**
     * Makes the selection visible if it is hidden.
     */

  }, {
    key: "show",
    value: function show() {
      this._render();
    }
    /**
     * Makes the selection hidden if it is visible.
     */

  }, {
    key: "hide",
    value: function hide() {
      if (this._marker) {
        this._marker.clear();
      }
    }
    /**
     * Determines if the selection has been permanently removed from the editor.
     *
     * @returns
     *   True if the selection has been disposed, false otherwise.
     */

  }, {
    key: "isDisposed",
    value: function isDisposed() {
      return this._disposed;
    }
    /**
     * Permanently removes the selection from the editor.
     */

  }, {
    key: "dispose",
    value: function dispose() {
      if (!this._disposed) {
        this._styleElement.parentElement.removeChild(this._styleElement);

        this.hide();
        this._disposed = true;

        this._onDisposed();
      }
    }
    /**
     * A helper method that actually renders the selection as a marker within
     * the CodeMirror Editor.
     *
     * @private
     * @internal
     */

  }, {
    key: "_render",
    value: function _render() {
      if (this._marker) {
        this._marker.clear();
      }

      this._marker = this._editor.markText(this._startPosition, this._endPosition, {
        className: this._className
      });
    }
  }]);

  return RemoteSelection;
}();

exports.RemoteSelection = RemoteSelection;