import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import _regeneratorRuntime from "@babel/runtime/regenerator";
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
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";

var _dec, _dec2, _class, _class2, _temp;

import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { style } from 'typestyle';
import LinearProgress from '@material-ui/core/LinearProgress';
import * as beautify from 'js-beautify';
import { Pos } from 'codemirror';
import LineWidget from './LineWidget';
import Editor from './Editor';
import MenuBar from './MenuBar';
import AssetPane from './AssetPane';
import ErrorPane from './ErrorPane';
import foldAsset from './foldAsset';
import { withTheme } from '@material-ui/core';
import preserveTrailingSpaceBeautify from '../../utils/preserveTrailingSpaceBeautify';
import withFiles from '../../store/withFiles';
import FixAndMessage from './FixAndMessage';
import CardFloatingBar from '../CardFloatingBar';
import PlayMenu from './PlayMenu';
import { Home } from '@material-ui/icons';
var cn = {
  root: style({
    position: 'absolute',
    width: '100%',
    height: '100%',
    display: 'flex',
    flexDirection: 'column',
    alignItems: 'stretch'
  }),
  editorContainer: style({
    flex: '1 1 auto',
    position: 'relative'
  }),
  barButton: style({
    padding: 0,
    lineHeight: 2
  }),
  barButtonLabel: style({
    fontSize: '.5rem'
  }),
  progress: style({
    borderRadius: 0
  }),
  blank: style({
    flex: '1 1 auto'
  }),
  icon: style({
    width: 44,
    alignSelf: 'center'
  }),
  menuBarContainer: style({
    display: 'flex',
    padding: 8
  })
};

var getCn = function getCn(props) {
  return {
    tabContainer: style({
      flex: 1,
      display: 'flex',
      borderColor: props.theme.palette.primary.main,
      borderStyle: 'solid',
      borderWidth: '0px 0px 1px 1px',
      alignItems: 'center'
    })
  };
};

var SourceEditor = (_dec = withTheme(), _dec2 = withFiles({}), _dec(_class = _dec2(_class = (_temp = _class2 =
/*#__PURE__*/
function (_PureComponent) {
  _inherits(SourceEditor, _PureComponent);

  function SourceEditor() {
    var _getPrototypeOf2;

    var _this;

    _classCallCheck(this, SourceEditor);

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

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

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "state", {
      file: null,
      babelError: null,
      showHint: false,
      hasHistory: false,
      hasChanged: false,
      loading: false,
      snippets: [],
      showLineWidget: true
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleCodemirror", function (codemirror) {
      _this.codemirror = codemirror;

      var onChange = function onChange(cm) {
        _this.setState({
          hasHistory: cm.historySize().undo > 0,
          hasChanged: cm.getValue('\n') !== _this.state.file.text
        });
      };

      _this.codemirror.on('change', onChange);

      _this.codemirror.on('swapDoc', onChange);

      _this.codemirror.on('swapDoc', _this.foldAll);

      _this.foldAll(codemirror);

      _this.forceUpdate();
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "foldAll", function (cm) {
      var opt = {
        rangeFinder: foldAsset
      };

      for (var line = cm.lineCount() - 1; line >= 0; line--) {
        cm.foldCode(new Pos(line, 0), opt, 'fold');
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "runApp",
    /*#__PURE__*/
    function () {
      var _ref = _asyncToGenerator(
      /*#__PURE__*/
      _regeneratorRuntime.mark(function _callee(href) {
        var file, text, nextFile;
        return _regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                file = _this.state.file;

                if (!(!_this.codemirror || !file)) {
                  _context.next = 3;
                  break;
                }

                return _context.abrupt("return");

              case 3:
                _this.beautify(_this.codemirror); // Auto beautify


                text = _this.codemirror.getValue();

                _this.setState({
                  loading: true,
                  babelError: null
                }); // Like a watching


                _context.prev = 6;
                nextFile = file.set({
                  text: text
                });
                _context.next = 10;
                return nextFile.transpiled;

              case 10:
                _context.next = 12;
                return _this.props.putFile(nextFile);

              case 12:
                // 再読み込み
                _this.props.setLocation(href);

                _context.next = 20;
                break;

              case 15:
                _context.prev = 15;
                _context.t0 = _context["catch"](6);

                _this.props.globalEvent.emit('message.editor', {
                  data: {
                    value: file.name
                  }
                }); // もう一度ファイルを開かせる


                _this.setState({
                  babelError: _context.t0
                });

                console.error(_context.t0);

              case 20:
                _this.setState({
                  loading: false
                });

              case 21:
              case "end":
                return _context.stop();
            }
          }
        }, _callee, this, [[6, 15]]);
      }));

      return function (_x) {
        return _ref.apply(this, arguments);
      };
    }());

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleUndo", function () {
      _this.codemirror.undo();
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleRestore", function () {
      var file = _this.state.file;
      var cm = _this.codemirror;
      if (!file || !cm) return;

      var _cm$getScrollInfo = cm.getScrollInfo(),
          left = _cm$getScrollInfo.left,
          top = _cm$getScrollInfo.top;

      _this.codemirror.scrollTo(left, top); // 変更を加える前の状態(前回保存したところ)に戻す


      while (cm.historySize().undo > 0) {
        cm.undo(); // ひとつ前に戻す

        if (cm.getValue() === file.text) {
          // 前回の保存内容と同じになった
          break;
        }
      }

      if (cm.getValue() !== file.text) {
        // 履歴を遡っても同じにはならなかった(履歴が混在している)
        cm.clearHistory();
        cm.setValue(file.text);
      }

      _this.codemirror.scrollTo(left, top);

      _this.runApp();
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "beautify", function () {
      var file = _this.state.file;
      if (!file) return;

      var prevValue = _this.codemirror.getValue();

      var setValueWithoutHistory = function setValueWithoutHistory(replacement) {
        // undo => beautify => setValue することで history を 1 つに
        var _this$codemirror$getS = _this.codemirror.getScrollInfo(),
            left = _this$codemirror$getS.left,
            top = _this$codemirror$getS.top;

        _this.codemirror.undo();

        _this.codemirror.setValue(replacement);

        _this.codemirror.scrollTo(left, top);
      }; // import .jsbeautifyrc


      var configs = {};

      try {
        var _this$props$glob = _this.props.glob('**/.jsbeautifyrc'),
            _this$props$glob2 = _slicedToArray(_this$props$glob, 1),
            runCommand = _this$props$glob2[0];

        if (runCommand) {
          configs = JSON.parse(runCommand.text);
        }
      } catch (error) {
        console.error(error);
      }

      if (file.is('javascript') || file.is('json')) {
        setValueWithoutHistory(preserveTrailingSpaceBeautify(prevValue, configs.js || {}));
      } else if (file.is('html')) {
        setValueWithoutHistory(beautify.html(prevValue, configs.html || {}));
      } else if (file.is('css')) {
        setValueWithoutHistory(beautify.css(prevValue, configs.css || {}));
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "setShowLineWidget", function (showLineWidget) {
      _this.setState({
        showLineWidget: showLineWidget
      });
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "saveFileIfNeeded",
    /*#__PURE__*/
    _asyncToGenerator(
    /*#__PURE__*/
    _regeneratorRuntime.mark(function _callee2() {
      var cm, file, text, nextFile;
      return _regeneratorRuntime.wrap(function _callee2$(_context2) {
        while (1) {
          switch (_context2.prev = _context2.next) {
            case 0:
              cm = _this.codemirror;
              file = _this.state.file;

              if (!(!cm || !file)) {
                _context2.next = 4;
                break;
              }

              return _context2.abrupt("return");

            case 4:
              text = cm.getValue(); // 現在のコード

              if (!(file.text == text)) {
                _context2.next = 7;
                break;
              }

              return _context2.abrupt("return");

            case 7:
              // 変わっていない
              nextFile = file.set({
                text: text
              });
              _context2.prev = 8;
              _context2.next = 11;
              return nextFile.transpiled;

            case 11:
              _context2.next = 13;
              return _this.props.putFile(nextFile);

            case 13:
              _context2.next = 19;
              break;

            case 15:
              _context2.prev = 15;
              _context2.t0 = _context2["catch"](8);

              _this.setState({
                babelError: _context2.t0
              });

              throw _context2.t0;

            case 19:
            case "end":
              return _context2.stop();
          }
        }
      }, _callee2, this, [[8, 15]]);
    })));

    return _this;
  }

  _createClass(SourceEditor, [{
    key: "componentDidUpdate",
    value: function componentDidUpdate(prevProps) {
      if (prevProps.files !== this.props.files && this.state.file) {
        this.setState({
          snippets: this.props.getConfig('snippets')(this.state.file)
        });
      }
    }
  }, {
    key: "setValue",
    value: function setValue(value) {
      var _this$codemirror$getS2 = this.codemirror.getScrollInfo(),
          left = _this$codemirror$getS2.left,
          top = _this$codemirror$getS2.top;

      this.codemirror.setValue(value);
      this.codemirror.scrollTo(left, top);
    }
  }, {
    key: "render",
    value: function render() {
      var _this2 = this;

      var _this$props = this.props,
          iconUrl = _this$props.iconUrl,
          localization = _this$props.localization;
      var _this$state = this.state,
          file = _this$state.file,
          showHint = _this$state.showHint;

      if (!file) {
        return null;
      } // const snippets = this.props.getConfig('snippets')(file);


      var extraKeys = {
        'Ctrl-Enter': function CtrlEnter() {
          // Key Binding された操作の直後にカーソルが先頭に戻ってしまう(?)ため,
          // それをやり過ごしてから実行する
          window.setTimeout(_this2.runApp, 10);
        },
        'Ctrl-Alt-B': function CtrlAltB() {
          // Key Binding された操作の直後にカーソルが先頭に戻ってしまう(?)ため,
          // それをやり過ごしてから実行する
          window.setTimeout(_this2.beautify, 10);
        }
      };
      var foldOptions = {
        widget: ' ... ',
        minFoldSize: 1,
        scanUp: false
      };

      if (file.is('javascript')) {
        foldOptions.rangeFinder = foldAsset;
      }

      var showBackButton = this.props.filePath !== this.props.filePathToBack;
      var dcn = getCn(this.props);
      return React.createElement("div", {
        className: cn.root
      }, React.createElement(CardFloatingBar, {
        padding: 0
      }, localization.editorCard.title, iconUrl ? React.createElement("img", {
        src: iconUrl,
        alt: "",
        className: cn.icon
      }) : !showBackButton ? React.createElement(Home, {
        fontSize: "large",
        className: cn.icon
      }) : null, React.createElement("div", {
        className: dcn.tabContainer
      }, this.codemirror && React.createElement(AssetPane, {
        label: this.props.label,
        codemirror: this.codemirror,
        runApp: this.runApp,
        localization: localization,
        globalEvent: this.props.globalEvent,
        filePath: this.props.filePath,
        filePathToBack: this.props.filePathToBack,
        isExpandingEditorCard: this.props.isExpandingEditorCard,
        setExpandingEditorCard: this.props.setExpandingEditorCard,
        saveFileIfNeeded: this.saveFileIfNeeded
      }), React.createElement(PlayMenu, {
        runApp: this.runApp,
        href: this.props.href,
        localization: localization,
        hasChanged: this.state.hasChanged
      }))), this.state.loading ? React.createElement(LinearProgress, {
        color: "primary",
        className: cn.progress
      }) : null, React.createElement("div", {
        className: cn.editorContainer
      }, React.createElement(Editor, {
        file: file,
        loadConfig: this.props.loadConfig,
        showHint: showHint,
        snippets: this.state.snippets,
        codemirrorRef: this.handleCodemirror,
        extraKeys: extraKeys,
        foldOptions: foldOptions,
        localization: this.props.localization
      })), React.createElement(ErrorPane, {
        error: this.state.babelError,
        localization: localization,
        onRestore: this.handleRestore,
        canRestore: this.state.hasHistory
      }), React.createElement("div", {
        className: cn.menuBarContainer
      }, React.createElement(MenuBar, {
        localization: localization,
        href: this.props.href,
        handleUndo: this.handleUndo,
        runApp: this.runApp,
        hasHistory: this.state.hasHistory,
        tabs: this.props.tabs,
        filePath: this.props.filePath,
        showLineWidget: this.state.showLineWidget,
        setShowLineWidget: this.setShowLineWidget,
        label: this.props.label,
        filePathToBack: this.props.filePathToBack,
        globalEvent: this.props.globalEvent,
        isExpandingEditorCard: this.props.isExpandingEditorCard,
        setExpandingEditorCard: this.props.setExpandingEditorCard
      })), this.codemirror && React.createElement(LineWidget, {
        show: this.state.showLineWidget,
        codemirror: this.codemirror,
        runApp: this.runApp,
        localization: localization
      }), React.createElement(FixAndMessage, {
        codemirror: this.codemirror,
        localization: this.props.localization
      }));
    }
  }], [{
    key: "getDerivedStateFromProps",
    value: function getDerivedStateFromProps(nextProps, prevState) {
      var file = nextProps.files.find(function (file) {
        return file.name === nextProps.filePath;
      });

      if (file && file !== prevState.file) {
        return {
          file: file,
          showHint: !file.is('json'),
          snippets: nextProps.getConfig('snippets')(file)
        };
      }

      return null;
    }
  }]);

  return SourceEditor;
}(PureComponent), _defineProperty(_class2, "propTypes", {
  theme: PropTypes.object.isRequired,
  filePath: PropTypes.string.isRequired,
  setLocation: PropTypes.func.isRequired,
  href: PropTypes.string.isRequired,
  getConfig: PropTypes.func.isRequired,
  loadConfig: PropTypes.func.isRequired,
  reboot: PropTypes.bool.isRequired,
  localization: PropTypes.object.isRequired,
  openFileDialog: PropTypes.func.isRequired,
  tabs: PropTypes.array.isRequired,
  label: PropTypes.string.isRequired,
  iconUrl: PropTypes.string.isRequired,
  filePathToBack: PropTypes.string.isRequired,
  globalEvent: PropTypes.object.isRequired,
  isExpandingEditorCard: PropTypes.bool.isRequired,
  setExpandingEditorCard: PropTypes.func.isRequired,
  // Injected by withFiles (for JSX)
  files: PropTypes.array.isRequired,
  glob: PropTypes.func.isRequired,
  putFile: PropTypes.func.isRequired
}), _temp)) || _class) || _class);
export { SourceEditor as default };