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

var _dec, _dec2, _dec3, _class, _class2, _temp;

import React, { PureComponent, Fragment } from 'react';
import { withTheme } from '@material-ui/core/styles';
import PropTypes from 'prop-types';
import { style, classes } from 'typestyle';
import { IconButton, Button, Collapse, Tooltip, Popover } from '@material-ui/core';
import { Close, Home, Add, ColorLens, ColorLensOutlined, MoreHoriz } from '@material-ui/icons';
import { fade } from '@material-ui/core/styles/colorManipulator';
import { Pos } from 'codemirror';
import { includes, intersection, forEach, uniq, uniqBy, differenceWith, debounce, flatten, without } from 'lodash';
import ReactResizeDetector from 'react-resize-detector';
import { assetRegExp } from '../../utils/keywords';
import replaceExistConsts from '../../utils/replaceExistConsts';
import AssetButton from './AssetButton';
import extractAssetNames from './extractAssetNames';
import AssetLink, { assetLinkWidth } from './AssetLink';
import ImmutableFile from '../../File/ImmutableFile';
import withFiles from '../../store/withFiles';
import withAsset from '../../store/withAsset';
var paneHeight = 80; // %

export var pathToInstall = 'modules'; // 後方互換性のために変更しない (TODO: feelesrc で上書きできるように)

var pathToAutoload = 'autoload.js'; // 後方互換性のために変更しない (TODO: feelesrc で上書きできるように)

var cn = {
  in: style({
    top: "".concat(100 - paneHeight, "vh")
  }),
  out: style({
    top: '100vh'
  }),
  label: style({
    flex: '0 0 100%',
    color: 'white',
    textAlign: 'center',
    marginTop: 16,
    fontWeight: 600
  }),
  wrapper: style({
    display: 'flex',
    flexWrap: 'wrap',
    justifyContent: 'center'
  }),
  assetLinkContainerClasses: {
    container: style({
      flex: 1
    }),
    wrapperInner: style({
      width: '100%',
      display: 'flex',
      alignItems: 'center'
    })
  },
  assetLinkButton: style({
    margin: 4,
    marginRight: 0,
    height: assetLinkWidth,
    width: assetLinkWidth,
    minWidth: assetLinkWidth // ButtonBase の minWidth を打ち消す

  }),
  blank: style({
    flex: '1 1 auto'
  }),
  popoverClasses: {
    paper: style({
      padding: '16px 8px 8px 4px'
    })
  },
  moreButton: style({
    padding: 6,
    margin: 6
  })
};

var getCn = function getCn(_ref) {
  var theme = _ref.theme;
  return {
    root: style({
      position: 'fixed',
      width: '100%',
      height: "".concat(paneHeight, "vh"),
      padding: theme.spacing.unit,
      boxSizing: 'border-box',
      zIndex: theme.zIndex.modal - 1,
      left: 0,
      transition: theme.transitions.create('top'),
      display: 'flex',
      flexDirection: 'column',
      backgroundColor: fade(theme.palette.text.primary, 0.75)
    }),
    scroller: style({
      flex: 1,
      overflowX: 'auto',
      overflowY: 'scroll',
      boxSizing: 'border-box',
      paddingBottom: 24,
      borderTopLeftRadius: 0,
      borderTopRightRadius: 0
    }),
    scopeWrapper: style({
      color: theme.palette.common.white,
      paddingLeft: theme.spacing.unit * 10,
      paddingRight: theme.spacing.unit * 10,
      paddingBottom: theme.spacing.unit * 4,
      fontWeight: 600
    }),
    scope: style({
      padding: theme.spacing.unit,
      marginRight: theme.spacing.unit,
      color: theme.palette.getContrastText(theme.palette.primary.main),
      backgroundColor: theme.palette.primary.main,
      borderRadius: theme.shape.borderRadius
    }),
    closer: style({
      position: 'absolute',
      top: theme.spacing.unit,
      right: theme.spacing.unit,
      color: theme.palette.common.white
    }),
    toggle: style({
      position: 'absolute',
      bottom: theme.spacing.unit,
      right: theme.spacing.unit,
      color: theme.palette.common.white
    }),
    categoryWrapper: style({
      display: 'flex',
      flexWrap: 'nowrap',
      paddingLeft: theme.spacing.unit * 10,
      paddingRight: theme.spacing.unit * 10,
      paddingBottom: theme.spacing.unit * 4,
      paddingTop: theme.spacing.unit * 4
    }),
    category: style({
      flex: 1,
      fontWeight: 600,
      cursor: 'pointer',
      color: theme.palette.grey[600],
      borderBottom: "4px solid ".concat(theme.palette.grey[600]),
      display: 'flex',
      flexDirection: 'column',
      alignItems: 'center',
      justifyContent: 'space-around',
      $nest: {
        '&>img': {
          maxWidth: 48,
          height: 48
        }
      }
    }),
    active: style({
      color: theme.palette.common.white,
      borderBottomColor: theme.palette.common.white
    }),
    previousLinkButton: style({
      borderColor: theme.palette.primary.main
    }),
    addButton: style({
      marginRight: theme.spacing.unit
    })
  };
};

var AssetPane = (_dec = withTheme(), _dec2 = withFiles({
  watch: '**/*.js'
}), _dec3 = withAsset({}), _dec(_class = _dec2(_class = _dec3(_class = (_temp = _class2 =
/*#__PURE__*/
function (_PureComponent) {
  _inherits(AssetPane, _PureComponent);

  function AssetPane() {
    var _getPrototypeOf2;

    var _this;

    _classCallCheck(this, AssetPane);

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

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

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "state", {
      show: false,
      activeCategoryIndex: -1,
      scopeIndexes: [],
      defaultScope: '',
      assetNamesOfLinks: [],
      showAllVariations: false,
      // 全ての色を同時に表示するモード
      showAllScopes: false,
      // 全てのスコープを表示するモード. scopeIndexes を考慮しない
      previousLabel: '',
      // リンクで移動する前の label を保持する (Home='')
      linkPopoverTarget: null,
      // オートインストール
      installingFileNames: null,
      // インストール中のモジュール名
      callback: {
        // インストール後の挙動
        type: '',
        // insertAsset | openFile | runApp
        payload: null // callback に必要な payload

      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "_widgets", new Map());

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "_pendingInstallModule", []);

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "insertAsset", function (_ref2) {
      var insertCode = _ref2.insertCode,
          line = _ref2.line;
      var cm = _this.props.codemirror; // バーが常に上に来るよう, 下に挿入

      var pos = new Pos(line + 1, 0);
      var end = new Pos(pos.line + insertCode.split('\n').length, 0);
      insertCode = '\n' + insertCode;
      cm.replaceRange(insertCode, pos, pos, 'asset'); // スクロール

      cm.scrollIntoView({
        from: pos,
        to: end
      }, 10); // カーソル (挿入直後に undo したときスクロールが上に戻るのを防ぐ)

      cm.focus();
      cm.setCursor(new Pos(end.line - 1, 0)); // Pane をとじる

      _this.handleClose(); // 新しいアセットが更新された可能性が高いので, アセットのリンクを更新


      _this.updateAssetLink(cm); // 実行


      _this.props.runApp();
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "updateAssetLink", function (cm) {
      // ソースコードに含まれるキーワードを抜き出して Scrapbox 風のリンクを表示する
      var assetPackage = _this.props.asset.assetPackage;
      var assetNamesOfLinks = extractAssetNames(cm.getValue()).filter(function (assetName) {
        return Boolean(assetPackage.module[assetName]);
      });

      _this.setState({
        assetNamesOfLinks: assetNamesOfLinks
      });
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "_availableScopes", []);

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "isAvailableScope", function (scopeName) {
      return includes(_this._availableScopes, scopeName);
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "isAvailableScopeIndex", function (scopeIndex) {
      return _this.props.asset.assetPackage.scopes[scopeIndex] && _this.isAvailableScope(_this.props.asset.assetPackage.scopes[scopeIndex].name);
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleUpdateWidget", function (cm) {
      _this._widgets.clear();

      _this._availableScopes = []; // init

      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = cm.getValue().split('\n').entries()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var _step$value = _slicedToArray(_step.value, 2),
              line = _step$value[0],
              text = _step$value[1];

          _this.updateWidget(cm, line, text);
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return != null) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "updateWidget", function (cm, line, text) {
      var asset = _this.props.asset; // Syntax: /*+ モンスター アイテム */

      var tokens = assetRegExp.exec(text);

      if (tokens) {
        var _this$_availableScope;

        var _tokens$map = tokens.map(function (t) {
          return t.replace(/\t/g, '    ');
        }),
            _tokens$map2 = _slicedToArray(_tokens$map, 5),
            _prefix = _tokens$map2[1],
            _left = _tokens$map2[2],
            _label = _tokens$map2[3],
            _right = _tokens$map2[4];

        var prefix = document.createElement('span');
        prefix.textContent = _prefix;
        prefix.classList.add('Feeles-asset-blank');
        var left = document.createElement('span');
        left.textContent = _left;
        left.classList.add('Feeles-asset-blank');
        var label = document.createElement('span');
        label.textContent = _label;
        var right = document.createElement('span');
        right.textContent = _right;
        right.classList.add('Feeles-asset-blank');
        var button = document.createElement('span');
        button.classList.add('Feeles-asset-button');

        button.onclick = function (event) {
          var scopeIndexes = [];
          var activeCategoryIndex = -1;
          var defaultScope = ''; // バーに書かれた文字列の中に scope.name があれば選択

          forEach(asset.assetPackage.scopes, function (scope, index) {
            if (includes(_label, scope.name)) {
              scopeIndexes.push(index); // 先頭のスコープで, 初期表示カテゴリと初期スコープを決める

              if (activeCategoryIndex < 0) {
                activeCategoryIndex = scope.defaultActiveCategory;
                defaultScope = scope.name;
              }
            }
          });

          _this.setState({
            show: true,
            scopeIndexes: scopeIndexes,
            showAllScopes: false,
            defaultScope: defaultScope,
            activeCategoryIndex: activeCategoryIndex
          });

          event.stopPropagation();
        };

        button.appendChild(left);
        button.appendChild(label);
        button.appendChild(right);
        var parent = document.createElement('div');
        parent.classList.add('Feeles-widget', 'Feeles-asset');
        parent.appendChild(prefix);
        parent.appendChild(button);

        _this._widgets.set(line, parent);

        var availableScopes = _label.split(' ').filter(function (s) {
          return s;
        });

        (_this$_availableScope = _this._availableScopes).unshift.apply(_this$_availableScope, _toConsumableArray(availableScopes));
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleRenderWidget", function (cm) {
      // remove old widgets
      var _arr = _toConsumableArray(document.querySelectorAll('.Feeles-asset'));

      for (var _i = 0; _i < _arr.length; _i++) {
        var widget = _arr[_i];

        if (widget.parentNode) {
          widget.parentNode.removeChild(widget);
        }
      } // render new widgets


      var _iteratorNormalCompletion2 = true;
      var _didIteratorError2 = false;
      var _iteratorError2 = undefined;

      try {
        for (var _iterator2 = _this._widgets.entries()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
          var _step2$value = _slicedToArray(_step2.value, 2),
              i = _step2$value[0],
              element = _step2$value[1];

          // fold されていないかを確認
          var lineHandle = cm.getLineHandle(i);

          if (lineHandle.height > 0) {
            cm.addWidget(new Pos(i, 0), element);
          }
        }
      } catch (err) {
        _didIteratorError2 = true;
        _iteratorError2 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
            _iterator2.return();
          }
        } finally {
          if (_didIteratorError2) {
            throw _iteratorError2;
          }
        }
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleIndexReplacement", function (cm, change) {
      if (!includes(['asset', 'paste'], change.origin)) return;
      var code = cm.getValue('\n');
      var sourceText = change.text.join('\n');
      var replacedText = replaceExistConsts(code, sourceText);

      if (sourceText !== replacedText) {
        change.update(change.from, change.to, replacedText.split('\n'));
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleIndentLine", function (cm, change) {
      if (!includes(['asset', 'paste'], change.origin)) return;
      var from = change.from;
      var to = new Pos(from.line + change.text.length, 0); // インデント

      for (var line = from.line; line < to.line; line++) {
        cm.indentLine(line);
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleClose", function () {
      _this.setState({
        show: false
      });
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "openFile",
    /*#__PURE__*/
    function () {
      var _ref4 = _asyncToGenerator(
      /*#__PURE__*/
      _regeneratorRuntime.mark(function _callee(_ref3) {
        var filePath, label, iconUrl;
        return _regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                filePath = _ref3.filePath, label = _ref3.label, iconUrl = _ref3.iconUrl;

                if (filePath) {
                  _context.next = 3;
                  break;
                }

                return _context.abrupt("return");

              case 3:
                _context.next = 5;
                return _this.props.saveFileIfNeeded();

              case 5:
                // リンクで移動する前に変更を保存する
                _this.props.globalEvent.emit('message.editor', {
                  data: {
                    value: filePath,
                    options: {
                      showBackButton: Boolean(label),
                      // アセットのコードを閉じて以前のファイルに戻るボタンを表示する
                      label: label,
                      // ↑そのボタンを、この名前で「${label}の改造をおわる」と表示
                      iconUrl: iconUrl
                    }
                  }
                });

                _this.handleClose(); // Pane をとじる


              case 7:
              case "end":
                return _context.stop();
            }
          }
        }, _callee, this);
      }));

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

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "installAssetModules", function (assetNames) {
      var callback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};

      if (_this.state.installingFileNames) {
        // すでに別のモジュールをインストール中
        _this._pendingInstallModule.push([assetNames, callback]); // 前回コールされた installModule の終了を待ってから実行する


        return;
      }

      var _this$props = _this.props,
          asset = _this$props.asset,
          files = _this$props.files; // module が存在するかどうか

      var _iteratorNormalCompletion3 = true;
      var _didIteratorError3 = false;
      var _iteratorError3 = undefined;

      try {
        for (var _iterator3 = assetNames[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
          var assetName = _step3.value;
          var mod = asset.assetPackage.module[assetName];
          if (!mod) throw new Error("".concat(assetName, " is not exist in asset.module")); // TODO: 例外処理
        }
      } catch (err) {
        _didIteratorError3 = true;
        _iteratorError3 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
            _iterator3.return();
          }
        } finally {
          if (_didIteratorError3) {
            throw _iteratorError3;
          }
        }
      }

      var toPath = function toPath(name) {
        return "".concat(pathToInstall, "/").concat(name, ".js");
      };

      var notInstalled = differenceWith(assetNames, files, function (assetName, file) {
        return toPath(assetName) === file.name;
      });

      if (notInstalled.length === 0) {
        // すでに全部インストールされている
        _this.executeCallback(callback);

        return;
      } // まずコールバックを設定してからファイルをコピー


      var installingFileNames = assetNames.map(toPath);

      _this.setState({
        installingFileNames: installingFileNames,
        callback: callback
      },
      /*#__PURE__*/
      _asyncToGenerator(
      /*#__PURE__*/
      _regeneratorRuntime.mark(function _callee2() {
        var autoload, text, _iteratorNormalCompletion4, _didIteratorError4, _iteratorError4, _iterator4, _step4, assetName, _iteratorNormalCompletion5, _didIteratorError5, _iteratorError5, _iterator5, _step5, _assetName, mod;

        return _regeneratorRuntime.wrap(function _callee2$(_context2) {
          while (1) {
            switch (_context2.prev = _context2.next) {
              case 0:
                autoload = _this.props.files.find(function (file) {
                  return file.name === pathToAutoload;
                });

                if (autoload) {
                  _context2.next = 3;
                  break;
                }

                throw new Error("".concat(pathToAutoload, " is not found"));

              case 3:
                // autoload.js の更新
                text = autoload.text;
                if (text && text.substr(-1) !== '\n') text += '\n';
                _iteratorNormalCompletion4 = true;
                _didIteratorError4 = false;
                _iteratorError4 = undefined;
                _context2.prev = 8;

                for (_iterator4 = notInstalled[Symbol.iterator](); !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
                  assetName = _step4.value;
                  text += "import '".concat(pathToInstall, "/").concat(assetName, "'\n");
                }

                _context2.next = 16;
                break;

              case 12:
                _context2.prev = 12;
                _context2.t0 = _context2["catch"](8);
                _didIteratorError4 = true;
                _iteratorError4 = _context2.t0;

              case 16:
                _context2.prev = 16;
                _context2.prev = 17;

                if (!_iteratorNormalCompletion4 && _iterator4.return != null) {
                  _iterator4.return();
                }

              case 19:
                _context2.prev = 19;

                if (!_didIteratorError4) {
                  _context2.next = 22;
                  break;
                }

                throw _iteratorError4;

              case 22:
                return _context2.finish(19);

              case 23:
                return _context2.finish(16);

              case 24:
                _context2.next = 26;
                return _this.props.putFile(new ImmutableFile({
                  type: autoload.type,
                  name: autoload.name,
                  text: text
                }));

              case 26:
                // ファイルのコピー
                _iteratorNormalCompletion5 = true;
                _didIteratorError5 = false;
                _iteratorError5 = undefined;
                _context2.prev = 29;
                _iterator5 = assetNames[Symbol.iterator]();

              case 31:
                if (_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done) {
                  _context2.next = 39;
                  break;
                }

                _assetName = _step5.value;
                mod = asset.assetPackage.module[_assetName];
                _context2.next = 36;
                return _this.props.putFile(new ImmutableFile({
                  type: 'text/javascript',
                  name: toPath(_assetName),
                  text: mod.code
                }));

              case 36:
                _iteratorNormalCompletion5 = true;
                _context2.next = 31;
                break;

              case 39:
                _context2.next = 45;
                break;

              case 41:
                _context2.prev = 41;
                _context2.t1 = _context2["catch"](29);
                _didIteratorError5 = true;
                _iteratorError5 = _context2.t1;

              case 45:
                _context2.prev = 45;
                _context2.prev = 46;

                if (!_iteratorNormalCompletion5 && _iterator5.return != null) {
                  _iterator5.return();
                }

              case 48:
                _context2.prev = 48;

                if (!_didIteratorError5) {
                  _context2.next = 51;
                  break;
                }

                throw _iteratorError5;

              case 51:
                return _context2.finish(48);

              case 52:
                return _context2.finish(45);

              case 53:
              case "end":
                return _context2.stop();
            }
          }
        }, _callee2, this, [[8, 12, 16, 24], [17,, 19, 23], [29, 41, 45, 53], [46,, 48, 52]]);
      })));
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "getDependencies", function (name) {
      var _foundList = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];

      var mod = _this.props.asset.assetPackage.module[name];
      if (!mod) return _foundList;

      _foundList.push(name);

      var _iteratorNormalCompletion6 = true;
      var _didIteratorError6 = false;
      var _iteratorError6 = undefined;

      try {
        for (var _iterator6 = extractAssetNames(mod.code)[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
          var dependency = _step6.value;

          if (!includes(_foundList, dependency)) {
            // 新しいアセットが見つかったら, 再帰的に依存アセットを探す
            _this.getDependencies(dependency, _foundList);
          }
        }
      } catch (err) {
        _didIteratorError6 = true;
        _iteratorError6 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion6 && _iterator6.return != null) {
            _iterator6.return();
          }
        } finally {
          if (_didIteratorError6) {
            throw _iteratorError6;
          }
        }
      }

      return _foundList;
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "getDependenciesFromCode", function (code) {
      var _foundList = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];

      var _iteratorNormalCompletion7 = true;
      var _didIteratorError7 = false;
      var _iteratorError7 = undefined;

      try {
        for (var _iterator7 = extractAssetNames(code)[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) {
          var dependency = _step7.value;

          if (!includes(_foundList, dependency)) {
            // 新しいアセットが見つかったら, 再帰的に依存アセットを探す
            _this.getDependencies(dependency, _foundList);
          }
        }
      } catch (err) {
        _didIteratorError7 = true;
        _iteratorError7 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion7 && _iterator7.return != null) {
            _iterator7.return();
          }
        } finally {
          if (_didIteratorError7) {
            throw _iteratorError7;
          }
        }
      }

      return _foundList;
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "executeCallback", function (_ref6) {
      var type = _ref6.type,
          payload = _ref6.payload;

      switch (type) {
        case 'insertAsset':
          _this.insertAsset(payload);

          break;

        case 'openFile':
          _this.openFile(payload);

          break;

        case 'runApp':
          _this.props.runApp();

          break;
      } // pending 状態のインストールを実行


      var next = _this._pendingInstallModule.shift();

      if (next) {
        _this.installAssetModules.apply(_assertThisInitialized(_assertThisInitialized(_this)), next);
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "_pendingAssetsToInstall", []);

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleInstallMessage", function (event) {
      var name = event.data.value;
      var asset = _this.props.asset; // module が存在するなら先に install

      var mod = asset.assetPackage.module[name];

      if (mod) {
        _this._pendingAssetsToInstall.push(name); // ここでは pending list に入れるだけ


        _this.installAssetsFromMessage(); // この関数でインストールする

      } else {// そもそもアセットの名前を間違えているかも知れない
        }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "installAssetsFromMessage", debounce(function () {
      // install message を一定時間 debounce して, 一度にインストール
      var length = _this._pendingAssetsToInstall.length;
      if (length <= 0) return; // ない

      var assetNames = uniq(flatten(_this._pendingAssetsToInstall.splice(0, length) // pending list から削除
      .map(function (assetName) {
        return _this.getDependencies(assetName);
      }) // 依存アセットもここで同時にインストール
      )); // インストール後に runApp

      _this.installAssetModules(assetNames, {
        type: 'runApp'
      });
    }.bind(_assertThisInitialized(_assertThisInitialized(_this))), 16));

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "installAssetsFromCodeMirror", function (cm) {
      if (!cm) return;
      var code = cm.getValue();
      if (!code) return;

      var assetNames = _this.getDependenciesFromCode(code);

      _this.installAssetModules(assetNames);
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleInsertAsset", function (_ref7, scopeName) {
      var insertCode = _ref7.insertCode;

      var line = _this.getLineFromScopeName(scopeName); // 依存アセットもここで同時にインストール


      var dependencies = _this.getDependenciesFromCode(insertCode); // インストール後に insertAsset


      _this.installAssetModules(dependencies, {
        type: 'insertAsset',
        payload: {
          insertCode: insertCode,
          line: line
        }
      });
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleOpenFile", function (_ref8) {
      var name = _ref8.name,
          filePath = _ref8.filePath,
          iconUrl = _ref8.iconUrl;
      var asset = _this.props.asset; // module が存在するなら先に install

      var mod = asset.assetPackage.module[name];

      if (mod) {
        // インストール後に openFile
        _this.installAssetModules([name], {
          type: 'openFile',
          payload: {
            filePath: filePath,
            label: name,
            iconUrl: iconUrl
          }
        });
      } else {
        // 開けるかどうか試す
        _this.openFile({
          filePath: filePath,
          label: name,
          iconUrl: iconUrl
        });
      }
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleAssetLinkClick", function (_ref9) {
      var name = _ref9.name,
          iconUrl = _ref9.iconUrl;

      // もしそのアセットがインストールされていなければ、インストールしてから開く
      _this.handleOpenFile({
        name: name,
        filePath: "".concat(pathToInstall, "/").concat(name, ".js"),
        iconUrl: iconUrl
      });

      _this.handleCloseLinkPopover();
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleBackButtonClick", function () {
      _this.openFile({
        filePath: _this.props.filePathToBack
      });
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleMoreButtonClick", function () {
      _this.setState({
        show: true,
        showAllScopes: true,
        defaultScope: '',
        activeCategoryIndex: 0
      });
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleToggle", function () {
      _this.setState(function (prevState) {
        return {
          showAllVariations: !prevState.showAllVariations
        };
      });
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleOpenLinkPopover", function (event) {
      _this.setState({
        linkPopoverTarget: event.target
      });
    });

    _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleCloseLinkPopover", function () {
      _this.setState({
        linkPopoverTarget: null
      });
    });

    return _this;
  }

  _createClass(AssetPane, [{
    key: "componentDidMount",
    value: function componentDidMount() {
      var cm = this.props.codemirror;
      cm.on('change', this.handleUpdateWidget);
      cm.on('swapDoc', this.handleUpdateWidget);
      cm.on('update', this.handleRenderWidget);
      cm.on('beforeChange', this.handleIndexReplacement);
      cm.on('change', this.handleIndentLine);
      cm.on('swapDoc', this.updateAssetLink);
      this.handleUpdateWidget(cm);
      this.handleRenderWidget(cm);
      this.updateAssetLink(cm);
      this.props.globalEvent.on('message.install', this.handleInstallMessage);
      this.installAssetsFromCodeMirror(cm);
    }
  }, {
    key: "componentWillUnmount",
    value: function componentWillUnmount() {
      this.props.globalEvent.off('message.install', this.handleInstallMessage);
    }
  }, {
    key: "componentDidUpdate",
    value: function componentDidUpdate(prevProps) {
      var _this2 = this;

      var _this$props2 = this.props,
          files = _this$props2.files,
          label = _this$props2.label;
      var _this$state = this.state,
          installingFileNames = _this$state.installingFileNames,
          callback = _this$state.callback; // オートインストールの完了待ち

      if (installingFileNames && prevProps.files !== this.props.files) {
        var all = files.map(function (file) {
          return file.name;
        });

        if (installingFileNames.every(function (filePath) {
          return includes(all, filePath);
        })) {
          // 全てのファイルが含まれているので, 待ち状態を初期化してコールバックを実行
          this.setState({
            installingFileNames: null,
            callback: {
              type: '',
              payload: null
            }
          }, function () {
            return _this2.executeCallback(callback);
          });
        }
      } // previousLabel: ラベルが変わったとき, 前回の label を保持


      if (label !== prevProps.label) {
        var wasInHome = prevProps.filePath === prevProps.filePathToBack;
        this.setState({
          previousLabel: wasInHome ? '' : prevProps.label
        });
      }
    }
  }, {
    key: "getLineFromScopeName",

    /**
     * Widget が今何行目にあるのかは分からないため,
     * 与えられた scopeName を頼りにソースコードから探す
     * @returns scopeName が含まれる行番号
     */
    value: function getLineFromScopeName(scopeName) {
      var _iteratorNormalCompletion8 = true;
      var _didIteratorError8 = false;
      var _iteratorError8 = undefined;

      try {
        for (var _iterator8 = this.props.codemirror.getValue().split('\n').entries()[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) {
          var _step8$value = _slicedToArray(_step8.value, 2),
              line = _step8$value[0],
              text = _step8$value[1];

          var tokens = assetRegExp.exec(text);

          if (tokens) {
            var _tokens = _slicedToArray(tokens, 4),
                _label = _tokens[3];

            if (includes(_label, scopeName)) {
              return line;
            }
          }
        }
      } catch (err) {
        _didIteratorError8 = true;
        _iteratorError8 = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion8 && _iterator8.return != null) {
            _iterator8.return();
          }
        } finally {
          if (_didIteratorError8) {
            throw _iteratorError8;
          }
        }
      }
    }
  }, {
    key: "renderAssetButtons",
    value: function renderAssetButtons(assetButtons) {
      var _this3 = this;

      assetButtons = uniqBy(assetButtons, 'name'); // key を name にするので被らないようにする

      var keyPrefix = this._availableScopes.join(' ') + ' '; // bugfix: 置けるスコープが変わったら, AssetButton の state をリフレッシュする

      var showAllVariations = this.state.showAllVariations;

      if (showAllVariations) {
        // 全てのバリエーションを並べる
        return assetButtons.map(function (assetButton) {
          return assetButton.variations ? React.createElement(Fragment, {
            key: assetButton.name + '-container'
          }, _this3.renderAssetButtons(assetButton.variations)) : React.createElement(AssetButton, {
            key: keyPrefix + assetButton.name,
            name: assetButton.name,
            description: assetButton.description,
            iconUrl: assetButton.iconUrl,
            insertCode: assetButton.insertCode,
            moduleCode: assetButton.moduleCode,
            filePath: assetButton.filePath,
            scopes: assetButton.scopes,
            insertAsset: _this3.handleInsertAsset,
            openFile: _this3.handleOpenFile,
            localization: _this3.props.localization,
            globalEvent: _this3.props.globalEvent,
            isAvailableScope: _this3.isAvailableScope,
            defaultScope: _this3.state.defaultScope
          });
        });
      } else {
        // クリックでバリエーションを展開する
        return assetButtons.map(function (assetButton) {
          return React.createElement(AssetButton, {
            key: keyPrefix + assetButton.name,
            name: assetButton.name,
            description: assetButton.description,
            iconUrl: assetButton.iconUrl,
            insertCode: assetButton.insertCode,
            moduleCode: assetButton.moduleCode,
            filePath: assetButton.filePath,
            variations: assetButton.variations,
            scopes: assetButton.scopes,
            insertAsset: _this3.handleInsertAsset,
            openFile: _this3.handleOpenFile,
            localization: _this3.props.localization,
            globalEvent: _this3.props.globalEvent,
            isAvailableScope: _this3.isAvailableScope,
            defaultScope: _this3.state.defaultScope
          });
        });
      }
    }
  }, {
    key: "render",
    value: function render() {
      var _this4 = this;

      var dcn = getCn(this.props);
      var _this$props3 = this.props,
          localization = _this$props3.localization,
          filePath = _this$props3.filePath,
          filePathToBack = _this$props3.filePathToBack;
      var _this$state2 = this.state,
          linkPopoverTarget = _this$state2.linkPopoverTarget,
          show = _this$state2.show,
          activeCategoryIndex = _this$state2.activeCategoryIndex,
          scopeIndexes = _this$state2.scopeIndexes,
          showAllScopes = _this$state2.showAllScopes,
          assetNamesOfLinks = _this$state2.assetNamesOfLinks,
          previousLabel = _this$state2.previousLabel;
      var _this$props$asset$ass = this.props.asset.assetPackage,
          scopes = _this$props$asset$ass.scopes,
          categories = _this$props$asset$ass.categories,
          buttons = _this$props$asset$ass.buttons;
      var showingScopes = scopes.filter(function (_, i) {
        return includes(scopeIndexes, i);
      });

      var _showingButtons = buttons.filter(function (b) {
        return b.category === activeCategoryIndex;
      });

      var showingButtons = showAllScopes ? _showingButtons.filter(function (b) {
        return b.scopes === null || b.scopes.some(_this4.isAvailableScopeIndex);
      }) // スコープによらず, 今置くことのできる全てのアセットボタンを表示する
      : _showingButtons.filter(function (b) {
        return b.scopes === null || intersection(b.scopes, scopeIndexes).length;
      }); // スコープが被っているものに絞る (scopes === null || は互換性保持のため)

      var showBackButton = filePath !== filePathToBack;
      var showLinkAssets = assetNamesOfLinks.length > 0 || showBackButton; // アセットがあれば表示 (=> 古いキットでは出てこない) || アセットがなくても, Home にいなければ表示 (=> もどるボタンは常に使える)
      // アセットリンクの表示限界個数を求める

      var calcMaxLength = function calcMaxLength(width) {
        if (width === undefined) return 0;
        var moreButtonWidth = 36 + 6 * 2;
        var num = Math.floor((width - moreButtonWidth) / assetLinkWidth // 全体 width / リンク１個分の width
        ) - 1; // 直前のアセットへのリンクの分を引く

        return Math.max(0, num);
      };

      return React.createElement(React.Fragment, null, React.createElement(Collapse, {
        in: showLinkAssets,
        classes: cn.assetLinkContainerClasses,
        mountOnEnter: true,
        unmountOnExit: true
      }, showBackButton ? React.createElement(Tooltip, {
        title: this.props.localization.editorCard.stopEditing(this.props.label)
      }, React.createElement(Button, {
        variant: "contained",
        color: "primary",
        className: cn.assetLinkButton,
        onClick: this.handleBackButtonClick
      }, React.createElement(Home, {
        fontSize: "small"
      }))) : null, previousLabel ? React.createElement(AssetLink, {
        key: previousLabel,
        name: previousLabel,
        className: classes(cn.assetLinkButton, dcn.previousLinkButton),
        onClick: this.handleAssetLinkClick,
        localization: this.props.localization
      }) : null, React.createElement(ReactResizeDetector, {
        handleWidth: true,
        refreshMode: "throttle",
        refreshRate: 500
      }, function (_ref10) {
        var width = _ref10.width;
        return React.createElement("div", {
          style: {
            flex: 1
          }
        }, without(assetNamesOfLinks, previousLabel).slice(0, calcMaxLength(width)) // 表示限界を計算
        .map(function (assetName) {
          return React.createElement(AssetLink, {
            key: assetName,
            name: assetName,
            className: cn.assetLinkButton,
            onClick: _this4.handleAssetLinkClick,
            localization: _this4.props.localization
          });
        }), React.createElement(IconButton, {
          className: cn.moreButton,
          onClick: _this4.handleOpenLinkPopover
        }, React.createElement(MoreHoriz, null)));
      }), React.createElement(Button, {
        variant: "contained",
        color: "primary",
        className: dcn.addButton,
        onClick: this.handleMoreButtonClick
      }, React.createElement(Add, {
        fontSize: "small"
      }), localization.editorCard.add)), React.createElement(Popover, {
        open: Boolean(linkPopoverTarget),
        anchorEl: linkPopoverTarget,
        onClose: this.handleCloseLinkPopover,
        classes: cn.popoverClasses,
        anchorOrigin: {
          vertical: 'bottom',
          horizontal: 'center'
        },
        transformOrigin: {
          vertical: 'top',
          horizontal: 'center'
        }
      }, assetNamesOfLinks.map(function (assetName) {
        return React.createElement(AssetLink, {
          key: assetName,
          name: assetName,
          className: cn.assetLinkButton,
          onClick: _this4.handleAssetLinkClick,
          localization: _this4.props.localization
        });
      })), React.createElement("div", {
        className: classes(dcn.root, show ? cn.in : cn.out)
      }, categories.length ? React.createElement("div", {
        className: dcn.categoryWrapper
      }, categories.map(function (cat, i) {
        return React.createElement("div", {
          key: i,
          className: classes(dcn.category, i === activeCategoryIndex && dcn.active),
          onClick: function onClick() {
            return _this4.setState({
              activeCategoryIndex: i
            });
          }
        }, React.createElement("span", null, cat.name), React.createElement("img", {
          src: cat.iconUrl,
          alt: ""
        }));
      })) : null, showAllScopes ? null : React.createElement("div", {
        className: dcn.scopeWrapper
      }, React.createElement("span", {
        className: dcn.scope
      }, '+ ' + showingScopes.map(function (scope) {
        return scope.name;
      }).join(' ')), React.createElement("span", null, localization.editorCard.selectedScope)), React.createElement(IconButton, {
        "aria-label": "Close",
        className: dcn.closer,
        onClick: this.handleClose
      }, React.createElement(Close, {
        fontSize: "large"
      })), React.createElement("div", {
        className: dcn.scroller
      }, React.createElement("div", {
        className: cn.wrapper
      }, this.renderAssetButtons(showingButtons))), React.createElement(IconButton, {
        "aria-label": "Show or hide all variations",
        className: dcn.toggle,
        onClick: this.handleToggle
      }, this.state.showAllVariations ? React.createElement(ColorLens, {
        fontSize: "large"
      }) : React.createElement(ColorLensOutlined, {
        fontSize: "large"
      }))));
    }
  }]);

  return AssetPane;
}(PureComponent), _defineProperty(_class2, "propTypes", {
  label: PropTypes.string.isRequired,
  codemirror: PropTypes.object.isRequired,
  theme: PropTypes.object.isRequired,
  runApp: PropTypes.func.isRequired,
  localization: PropTypes.object.isRequired,
  globalEvent: PropTypes.object.isRequired,
  filePath: PropTypes.string.isRequired,
  filePathToBack: PropTypes.string.isRequired,
  isExpandingEditorCard: PropTypes.bool.isRequired,
  saveFileIfNeeded: PropTypes.func.isRequired,
  // Injected by withAsset
  asset: PropTypes.object.isRequired,
  // Injected by withFiles (for JSX)
  files: PropTypes.array.isRequired,
  putFile: PropTypes.func.isRequired
}), _temp)) || _class) || _class) || _class);
export { AssetPane as default };