import _Object$getOwnPropertyDescriptor from "@babel/runtime-corejs2/core-js/object/get-own-property-descriptor";
import _Array$from from "@babel/runtime-corejs2/core-js/array/from";
import _regeneratorRuntime from "@babel/runtime-corejs2/regenerator";
import "regenerator-runtime/runtime";
import _asyncToGenerator from "@babel/runtime-corejs2/helpers/asyncToGenerator";
import _Set from "@babel/runtime-corejs2/core-js/set";
import _inheritsLoose from "../../inheritsLoose";
import _defineProperty from "@babel/runtime-corejs2/helpers/defineProperty";
import _applyDecoratedDescriptor from "@babel/runtime-corejs2/helpers/applyDecoratedDescriptor";

var _dec, _class, _init, _class2, _temp;

import Intact from 'intact-angular';
import template from './index.vdt';
import '../../styles/kpc.css';
import './index.css';
import Node from './node';
import { debounce } from '../utils';
import { BEFORE, AFTER, INNER, RANGE } from './constants';
var Tree = (_dec = Intact.template(), (_class = (_temp = _class2 =
/*#__PURE__*/
function (_Intact) {
  _inheritsLoose(Tree, _Intact);

  function Tree() {
    return _Intact.apply(this, arguments) || this;
  }

  var _proto = Tree.prototype;

  _proto.defaults = function defaults() {
    return {
      data: undefined,
      expandedKeys: undefined,
      checkbox: false,
      checkedKeys: undefined,
      load: undefined,
      filter: undefined,
      selectedKeys: undefined,
      multiple: false,
      draggable: false,
      allowDrag: undefined,
      allowDrop: undefined,
      uncorrelated: false
    };
  };

  _proto._init = function _init() {
    var _this = this;

    this.checkedKeys = new _Set();
    this.expandedKeys = new _Set();
    this.selectedKeys = new _Set();
    this.root = Node.createNode({}, null, this);
    this.on('$receive:checkedKeys', function () {
      _this.checkedKeys = new _Set(_this.get('checkedKeys'));

      _this._mappingKeys();
    });
    this.on('$receive:data', this._mappingKeys);
    this.on('$receive:expandedKeys', function () {
      _this.expandedKeys = new _Set(_this.get('expandedKeys'));
    });
    this.on('$receive:filter', this._mappingKeys);
    this.on('$receive:selectedKeys', function () {
      _this.selectedKeys = new _Set(_this.get('selectedKeys'));
    });
    this.on('$receive:uncorrelated', this._mappingKeys);
    this._handleDragOver = debounce(this._handleDragOver, 100);
  };

  _proto._mappingKeys = function _mappingKeys() {
    var needRecheckNodes = [];
    this.root.children = Node.createNodes(this.get('data'), this.root, this, needRecheckNodes);
    needRecheckNodes.forEach(function (node) {
      return node.updateUpward();
    });
  };

  _proto._toggleExpand =
  /*#__PURE__*/
  function () {
    var _toggleExpand2 = _asyncToGenerator(
    /*#__PURE__*/
    _regeneratorRuntime.mark(function _callee(node, expanded, e) {
      var _this$get, load, children;

      return _regeneratorRuntime.wrap(function _callee$(_context) {
        while (1) {
          switch (_context.prev = _context.next) {
            case 0:
              if (!node.data.disabled) {
                _context.next = 2;
                break;
              }

              return _context.abrupt("return");

            case 2:
              _this$get = this.get(), load = _this$get.load;

              if (!(load && !expanded && !node.loaded)) {
                _context.next = 11;
                break;
              }

              node.loaded = false;
              this.update();
              _context.next = 8;
              return load(node);

            case 8:
              children = _context.sent;
              node.loaded = true;

              if (children) {
                node.append(children);
              }

            case 11:
              if (expanded) {
                this.shrink(node.key);
              } else {
                this.expand(node.key);
              }

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

    function _toggleExpand(_x, _x2, _x3) {
      return _toggleExpand2.apply(this, arguments);
    }

    return _toggleExpand;
  }();

  _proto._toggleCheck = function _toggleCheck(node, e) {
    e.preventDefault();
    e.stopPropagation();
    node.updateDownward(!node.checked);
    node.updateUpward();
    this.set('checkedKeys', _Array$from(this.checkedKeys));
  };

  _proto.toggleSelect = function toggleSelect(key) {
    var selectedKeys = this.selectedKeys;
    var multiple = this.get('multiple');

    if (selectedKeys.has(key)) {
      selectedKeys.delete(key);
    } else {
      if (!multiple) {
        selectedKeys.clear();
      }

      selectedKeys.add(key);
    }

    this.set('selectedKeys', _Array$from(selectedKeys));
  };

  _proto._updateCheckedKeys = function _updateCheckedKeys(node) {
    var checkedKeys = this.checkedKeys;

    if (node.checked) {
      checkedKeys.add(node.key);
    } else {
      checkedKeys.delete(node.key);
    }
  };

  _proto.expand = function expand(key, update) {
    if (update === void 0) {
      update = true;
    }

    if (key === this.root.key) return;
    var expandedKeys = this.expandedKeys;
    expandedKeys.add(key); // babel can not spread Set by `...` syntax in loose mode
    // use Array.from instead of

    this.set('expandedKeys', _Array$from(expandedKeys), {
      update: update
    });
  };

  _proto.shrink = function shrink(key, update) {
    if (update === void 0) {
      update = true;
    }

    if (key === this.root.key) return;
    var expandedKeys = this.expandedKeys;
    expandedKeys.delete(key);
    this.set('expandedKeys', _Array$from(expandedKeys), {
      update: update
    });
  };

  _proto.getCheckedData = function getCheckedData(leafOnly) {
    var data = [];

    var loop = function loop(children) {
      for (var i = 0; i < children.length; i++) {
        var node = children[i];

        if (node.checked && (!leafOnly || !node.children)) {
          data.push(node.data);
        }

        if (node.children) {
          loop(node.children);
        }
      }
    };

    loop(this.root.children);
    return data;
  };

  _proto.getSelectedData = function getSelectedData() {
    var data = [];
    var selectedKeys = this.selectedKeys;
    var size = selectedKeys.size;
    if (!size) return data;
    var count = 0;

    var loop = function loop(children) {
      for (var i = 0; i < children.length; i++) {
        var node = children[i];

        if (selectedKeys.has(node.key)) {
          data.push(node.data);
          count++;
        }

        if (count === size) return;

        if (node.children) {
          loop(node.children);
        }
      }
    };

    loop(this.root.children);
    return data;
  };

  _proto._onClick = function _onClick(node, e) {
    this.toggleSelect(node.key);
    this.trigger('click:node', node, e);
  };

  _proto._onRightClick = function _onRightClick(node, e) {
    this.trigger('rightclick:node', node, e);
  };

  _proto._beforeUpdate = function _beforeUpdate(lastVNode, nextVNode) {
    // if there is filter method, we should re-mapping the data
    // to check the filter status
    if (!this.get('filter')) return;
    if (!lastVNode || !nextVNode) return;
    var lastProps = lastVNode.props;
    var nextProps = nextVNode.props; // these props will re-mapping in $receive callback

    if ( // lastProps.data !== nextProps.data ||
    // lastProps.checkedKeys !== nextProps.checkedKeys ||
    lastProps.filter !== nextProps.filter || lastProps.expandedKeys !== nextProps.expandedKeys || lastProps.uncorrelated !== nextProps.uncorrelated) return;

    this._mappingKeys();
  };

  _proto._onDragStart = function _onDragStart(event) {
    event.stopPropagation();
    var node = this._draggingNode;

    var _this$get2 = this.get(),
        allowDrag = _this$get2.allowDrag;

    if (node.data.disabled || allowDrag && !allowDrag(node)) {
      this.trigger('denydrag', node);
      return event.preventDefault();
    } // this.shrink(node.key, false);


    this.set({
      '_draggingNode': node
    });

    try {
      // ie throw error
      // firefox-need-it
      event.dataTransfer.setData('text/plain', '');
    } catch (error) {// empty
    }

    event.dataTransfer.setDragImage(this._draggingDOM, 0, 0);
  };

  _proto._onMouseDown = function _onMouseDown(node, event) {
    // dragend is not dispatched if the source node was moved or remove
    // during the drag session
    // https://bugzilla.mozilla.org/show_bug.cgi?id=460801
    // we can not use mouseup instead, because the event does not trigger
    this._draggingNode = node;
    this._draggingDOM = event.currentTarget;
  };

  _proto._onDragOver = function _onDragOver(node, event) {
    event.preventDefault(); // if the mouse does not move, do nothing

    var clientX = event.clientX,
        clientY = event.clientY;
    var _clientX = this._clientX,
        _clientY = this._clientY;
    if (clientX === _clientX && clientY === _clientY) return;
    this._clientX = clientX;
    this._clientY = clientY;

    this._handleDragOver(node, event);
  };

  _proto._handleDragOver = function _handleDragOver(node, event) {
    var draggingNode = this.get('_draggingNode'); // maybe it is end

    if (!draggingNode) return;
    var parentNode = node;

    do {
      if (parentNode.key === draggingNode.key) {
        return;
      }
    } while (parentNode = parentNode.parent);

    var _node = this._node,
        _mode = this._mode;

    var mode = this._calcInsertMode(event);

    if (_mode !== mode || _node !== node) {
      this._mode = mode;
      this._node = node; // if this node does not allow drop, prevent to insert the dragging node inner it

      if (mode === INNER) {
        var _this$get3 = this.get(),
            allowDrop = _this$get3.allowDrop;

        if (node.data.disabled || allowDrop && !allowDrop(node)) {
          return this.trigger('denydrop', node);
        }
      }

      this._lastValidNode = node;
      draggingNode.remove(true);

      this._insertNode(node, draggingNode, mode);
    }
  };

  _proto._calcInsertMode = function _calcInsertMode(event) {
    var clientY = event.clientY,
        currentTarget = event.currentTarget;

    var _currentTarget$getBou = currentTarget.getBoundingClientRect(),
        top = _currentTarget$getBou.top,
        bottom = _currentTarget$getBou.bottom,
        height = _currentTarget$getBou.height;

    var des = height * RANGE;
    if (clientY <= top + des) return BEFORE;else if (clientY >= bottom - des) return AFTER;
    return INNER;
  };

  _proto._insertNode = function _insertNode(node, draggingNode, mode) {
    switch (mode) {
      case BEFORE:
        draggingNode.insertBefore(node);
        break;

      case AFTER:
        draggingNode.insertAfter(node);
        break;

      default:
        draggingNode.appendTo(node);
        break;
    }
  };

  _proto._onDragEnd = function _onDragEnd() {
    var _this$get4 = this.get(),
        _draggingNode = _this$get4._draggingNode;

    if (this._lastValidNode) {
      this.trigger('dragend', {
        tree: this.root,
        srcNode: _draggingNode,
        toNode: this._lastValidNode,
        mode: this._mode
      });
    }

    this._draggingDOM = null;
    this._draggingNode = null;
    this._node = null;
    this._mode = null;
    this._lastValidNode = null;
    this.set('_draggingNode', undefined);
  };

  return Tree;
}(Intact), _defineProperty(_class2, "template", template), _defineProperty(_class2, "blocks", ['label']), _defineProperty(_class2, "propTypes", {
  data: Array,
  expandedKeys: Array,
  checkedKeys: Array,
  checkbox: Boolean,
  load: Function,
  filter: Function,
  selectedKeys: Array,
  multiple: Boolean,
  draggable: Boolean,
  allowDrag: Function,
  allowDrop: Function,
  uncorrelated: Boolean
}), _defineProperty(_class2, "events", {
  'rightclick:node': true,
  'click:node': true,
  'denydrag': true,
  'denydrop': true,
  'dragend': true
}), _temp), (_applyDecoratedDescriptor(_class, "template", [_dec], (_init = _Object$getOwnPropertyDescriptor(_class, "template"), _init = _init ? _init.value : undefined, {
  enumerable: true,
  configurable: true,
  writable: true,
  initializer: function initializer() {
    return _init;
  }
}), _class)), _class));
export { Tree as default };
export { Tree };