import _objectSpread from "@babel/runtime/helpers/objectSpread";
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
import _createClass from "@babel/runtime/helpers/createClass";
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
import _inherits from "@babel/runtime/helpers/inherits";
import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import CodeMirror from 'codemirror';
import deepEqual from 'deep-equal';
import includes from 'lodash/includes';

var CodeMirrorComponent =
/*#__PURE__*/
function (_PureComponent) {
  _inherits(CodeMirrorComponent, _PureComponent);

  function CodeMirrorComponent() {
    var _getPrototypeOf2;

    var _this;

    _classCallCheck(this, CodeMirrorComponent);

    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
      args[_key] = arguments[_key];
    }

    _this = _possibleConstructorReturn(this, (_getPrototypeOf2 = _getPrototypeOf(CodeMirrorComponent)).call.apply(_getPrototypeOf2, [this].concat(args)));

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "state", {
      // File ごとに存在する CodeMirror.Doc インスタンスのキャッシュ
      docs: new Map()
    });

    return _this;
  }

  _createClass(CodeMirrorComponent, [{
    key: "componentDidMount",
    value: function componentDidMount() {
      // initialize CodeMirror
      this.codeMirror = CodeMirror.fromTextArea(this.ref, this.options);
      var id = this.props.id;
      var doc = this.codeMirror.getDoc();
      doc.setValue(this.props.value); // set default value

      doc.clearHistory();
      this.state.docs.set(id, doc);
    }
  }, {
    key: "componentWillUnmount",
    value: function componentWillUnmount() {
      this.state.docs.clear();
      this.codeMirror.toTextArea();
      this.codeMirror = null; // GC??
    }
  }, {
    key: "componentDidUpdate",
    value: function componentDidUpdate(prevProps) {
      // タブ, value の更新
      if (prevProps.id !== this.props.id) {
        // 次のタブ (or undefined)
        var doc = this.state.docs.get(this.props.id);

        if (!doc) {
          // 新しく開かれたタブ（キャッシュに存在しない）
          // copy をもとに新しい Doc を作り、 value を更新
          doc = this.codeMirror.getDoc().copy(false);
          doc.setValue(this.props.value); // value の更新

          doc.clearHistory();
          this.state.docs.set(this.props.id, doc);
        } // 現在のタブと入れ替え


        this.codeMirror.swapDoc(doc);
      } // options の更新


      var ignoreKeys = ['id', 'value'];

      var _arr = Object.entries(this.props);

      for (var _i = 0; _i < _arr.length; _i++) {
        var _arr$_i = _slicedToArray(_arr[_i], 2),
            key = _arr$_i[0],
            nextValue = _arr$_i[1];

        if (includes(ignoreKeys, key)) continue;

        if (!deepEqual(prevProps[key], this.props[key])) {
          // options の変更を CodeMirror に伝える
          this.codeMirror.setOption(key, nextValue);
        }
      }
    }
  }, {
    key: "getCodeMirror",
    value: function getCodeMirror() {
      return this.codeMirror;
    }
  }, {
    key: "render",
    value: function render() {
      var _this2 = this;

      return React.createElement("textarea", {
        ref: function ref(_ref) {
          return _this2.ref = _ref;
        }
      });
    }
  }, {
    key: "options",
    get: function get() {
      var gutters = [];

      if (this.props.lineNumbers) {
        gutters.push('CodeMirror-linenumbers');
      }

      if (this.props.foldGutter) {
        gutters.push('CodeMirror-foldgutter');
      }

      return _objectSpread({}, this.props, {
        gutters: gutters
      });
    }
  }]);

  return CodeMirrorComponent;
}(PureComponent);

_defineProperty(CodeMirrorComponent, "propTypes", {
  id: PropTypes.string.isRequired,
  // CodeMirror options
  value: PropTypes.string.isRequired,
  mode: PropTypes.string,
  lineNumbers: PropTypes.bool.isRequired,
  indentUnit: PropTypes.number.isRequired,
  indentWithTabs: PropTypes.bool.isRequired,
  matchBrackets: PropTypes.bool.isRequired,
  autoCloseBrackets: PropTypes.bool.isRequired,
  keyMap: PropTypes.string.isRequired,
  foldOptions: PropTypes.object,
  dragDrop: PropTypes.bool.isRequired,
  extraKeys: PropTypes.object.isRequired,
  readOnly: PropTypes.bool.isRequired,
  foldGutter: PropTypes.bool.isRequired
});

_defineProperty(CodeMirrorComponent, "defaultProps", {
  mode: null,
  lineNumbers: true,
  indentUnit: 4,
  indentWithTabs: true,
  matchBrackets: true,
  autoCloseBrackets: true,
  keyMap: 'default',
  dragDrop: false,
  extraKeys: {},
  readOnly: false,
  foldGutter: false
});

export { CodeMirrorComponent as default };