'use strict';

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _createClass = 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); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _reactDom = require('react-dom');

var _reactDnd = require('react-dnd');

var _reactDndHtml5Backend = require('react-dnd-html5-backend');

var _bind = require('classnames/bind');

var _bind2 = _interopRequireDefault(_bind);

var _Badge = require('../Badge');

var _Badge2 = _interopRequireDefault(_Badge);

var _Toggle = require('../Toggle');

var _Toggle2 = _interopRequireDefault(_Toggle);

var _flow = require('lodash/flow');

var _flow2 = _interopRequireDefault(_flow);

var _style = require('./style.scss');

var _style2 = _interopRequireDefault(_style);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

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

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var sortableItemSource = {
  beginDrag: function beginDrag(props) {
    props.onDragStart();
    if (props.getDimensions) {
      props.getDimensions();
    }

    return {
      value: props.value,
      text: props.text,
      active: props.active,
      index: props.index
    };
  },
  endDrag: function endDrag(props) {
    props.onDragStop();
  }
};

var sortableItemTarget = {
  hover: function hover(props, monitor, component) {
    var dragIndex = monitor.getItem().index;
    var hoverIndex = props.index;

    // Don't replace items with themselves
    if (dragIndex === hoverIndex) {
      return;
    }

    // Determine rectangle on screen
    var hoverBoundingRect = (0, _reactDom.findDOMNode)(component).getBoundingClientRect();

    // Get vertical middle
    var hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;

    // Determine mouse position
    var clientOffset = monitor.getClientOffset();

    // Get pixels to the top
    var hoverClientY = (clientOffset ? clientOffset.y : 0) - hoverBoundingRect.top;

    // Only perform the move when the mouse has crossed half of the items height
    // When dragging downwards, only move when the cursor is below 50%
    // When dragging upwards, only move when the cursor is above 50%

    // Dragging downwards
    if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
      return;
    }

    // Dragging upwards
    if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
      return;
    }

    // Time to actually perform the action
    props.moveSortableItem(dragIndex, hoverIndex);

    // Note: we're mutating the monitor item here!
    // Generally it's better to avoid mutations,
    // but it's good here for the sake of performance
    // to avoid expensive index searches.
    monitor.getItem().index = hoverIndex;
  }
};

var SortableItem = function (_React$Component) {
  _inherits(SortableItem, _React$Component);

  function SortableItem() {
    var _Object$getPrototypeO;

    var _temp, _this, _ret;

    _classCallCheck(this, SortableItem);

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

    return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_Object$getPrototypeO = Object.getPrototypeOf(SortableItem)).call.apply(_Object$getPrototypeO, [this].concat(args))), _this), _this.state = {
      count: _this.props.count
    }, _this.componentWillReceiveProps = function (nextProps) {
      if (nextProps.count !== _this.state.count) {
        _this.setState({ count: nextProps.count });
      }
    }, _this.toggleSortableItem = function () {
      _this.props.toggleSortableItem(_this.props.index);
    }, _this.render = function () {
      var cx = _bind2.default.bind(_style2.default);
      var _this$props = _this.props;
      var text = _this$props.text;
      var index = _this$props.index;
      var active = _this$props.active;
      var isDragging = _this$props.isDragging;
      var connectDragSource = _this$props.connectDragSource;
      var connectDropTarget = _this$props.connectDropTarget;
      var canDrop = _this$props.canDrop;

      var opacity = isDragging ? 0 : 1;
      var badgeOpacity = _this.state.count > 1 ? 1 - 0.6 / (_this.state.count - 1) * index : 1;
      var sortableItemClasses = cx(_style2.default['sortable-item'], canDrop ? 'dragging' : '', !active ? 'inactive' : '');

      return connectDropTarget(_react2.default.createElement(
        'div',
        { style: { opacity: opacity }, className: sortableItemClasses },
        _react2.default.createElement(
          'div',
          { style: { opacity: badgeOpacity } },
          _react2.default.createElement(_Badge2.default, { text: index + 1, theme: 'sky', optClass: _style2.default['sortable-item-badge'] })
        ),
        _react2.default.createElement(
          'span',
          null,
          text
        ),
        _react2.default.createElement(
          'div',
          { className: _style2.default.actions },
          _react2.default.createElement(_Toggle2.default, { value: active, optClass: _style2.default.toggle, changeCallback: _this.toggleSortableItem }),
          connectDragSource(_react2.default.createElement(
            'div',
            { className: _style2.default.handle },
            _react2.default.createElement('span', null),
            _react2.default.createElement('span', null),
            _react2.default.createElement('span', null),
            _react2.default.createElement('span', null)
          ))
        )
      ));
    }, _temp), _possibleConstructorReturn(_this, _ret);
  }

  _createClass(SortableItem, [{
    key: 'componentDidMount',
    value: function componentDidMount() {
      // Use empty image as a drag preview so browsers don't draw it
      // and we can draw whatever we want on the custom drag layer instead.
      this.props.connectDragPreview((0, _reactDndHtml5Backend.getEmptyImage)(), {
        // IE fallback: specify that we'd rather screenshot the node
        // when it already knows it's being dragged so we can hide it with CSS.
        captureDraggingState: true
      });
    }
  }]);

  return SortableItem;
}(_react2.default.Component);

SortableItem.propTypes = {
  /**
   * Binds to react-dnd connectDragSource method.
   */
  connectDragSource: _react2.default.PropTypes.func,
  /**
   * Binds to react-dnd connectDropTarget method.
   */
  connectDropTarget: _react2.default.PropTypes.func,
  /**
   * Binds to react-dnd connectDragPreview method.
   */
  connectDragPreview: _react2.default.PropTypes.func,
  /**
   * Index of the item in the list.
   */
  index: _react2.default.PropTypes.number,
  /**
   * Whether the item is being dragged.
   */
  isDragging: _react2.default.PropTypes.bool,
  /**
   * The value of the item.
   */
  value: _react2.default.PropTypes.any,
  /**
   * The text to display inside the item.
   */
  text: _react2.default.PropTypes.string,
  /**
   * Whether the item is active.
   */
  active: _react2.default.PropTypes.bool,
  /**
   * A callback that gets triggered when the item is moved.
   */
  moveSortableItem: _react2.default.PropTypes.func,
  /**
   * A callback that gets triggered when the item is toggled.
   */
  toggleSortableItem: _react2.default.PropTypes.func,
  /**
   * The total number of items in the list.
   */
  count: _react2.default.PropTypes.number
};
SortableItem.defaultProps = {
  active: false
};
exports.default = (0, _flow2.default)((0, _reactDnd.DragSource)('item', sortableItemSource, function (connect, monitor) {
  return {
    connectDragSource: connect.dragSource(),
    connectDragPreview: connect.dragPreview(),
    isDragging: monitor.isDragging()
  };
}), (0, _reactDnd.DropTarget)('item', sortableItemTarget, function (connect, monitor) {
  return {
    connectDropTarget: connect.dropTarget(),
    canDrop: monitor.canDrop()
  };
}))(SortableItem);