'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 _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

var _react = require('react');

var _react2 = _interopRequireDefault(_react);

var _propTypes = require('prop-types');

var _propTypes2 = _interopRequireDefault(_propTypes);

var _orderBy = require('lodash/orderBy');

var _orderBy2 = _interopRequireDefault(_orderBy);

var _chunk = require('lodash/chunk');

var _chunk2 = _interopRequireDefault(_chunk);

var _TableRow = require('./TableRow');

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

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

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; }

function sortChildren(_ref) {
  var children = _ref.children,
      sort = _ref.sort,
      order = _ref.order;

  if (sort instanceof Array) {
    return (0, _orderBy2.default)(children, function (item) {
      return item.props.value[sort[0]];
    }, order);
  }
  return children;
}

function filterChildren(_ref2) {
  var children = _ref2.children,
      _ref2$filterOptions = _ref2.filterOptions,
      filter = _ref2$filterOptions.filter,
      filterValues = _ref2$filterOptions.filterValues;

  var result = children && children.filter(function (item) {
    return filterValues.includes(item.props.value[filter]);
  });
  return result.length ? result : children;
}

function createFilteredRows(_ref3) {
  var children = _ref3.children,
      isRowSelected = _ref3.isRowSelected,
      props = _ref3.props,
      sort = _ref3.sort,
      order = _ref3.order,
      filterOptions = _ref3.filterOptions;

  var resultChildren = _react.Children.toArray(children);

  var filteredChildren = filterOptions && filterOptions.filter ? filterChildren({ children: resultChildren, filterOptions: filterOptions }) : resultChildren;
  var sortedChildren = sortChildren({ children: filteredChildren, sort: sort, order: order });

  resultChildren = filteredChildren.reduce(function (arrayChildren, child, index) {
    var resultChild = (0, _TableRow.createRow)({ child: child, isRowSelected: isRowSelected, index: index, props: props, rowNumber: sortedChildren.indexOf(child) });

    if (resultChild) {
      var value = resultChild.props.value;

      arrayChildren.push(_extends({}, value, { child: resultChild, index: index }));
    }

    return arrayChildren;
  }, []) || [];
  if (sort instanceof Array) {
    resultChildren = (0, _orderBy2.default)(resultChildren, sort, order);
  }
  return resultChildren.map(function (_ref4) {
    var child = _ref4.child;
    return child;
  });
}

function getNewSelectedRows(_ref5) {
  var children = _ref5.children,
      selectedChildren = _ref5.selectedChildren,
      sort = _ref5.sort,
      order = _ref5.order;

  var sortedChildren = sortChildren({ children: children, sort: sort, order: order });
  return sortedChildren.reduce(function (acc, child, index) {
    if (selectedChildren.indexOf(child.props.index) > -1) {
      acc.push(index);
    }
    return acc;
  }, []);
}

function isValueInRange(value, range) {
  return !!range && (range.start <= value && value <= range.end || range.end <= value && value <= range.start);
}

function genRangeOfValues(start, offset) {
  var off = offset;
  var values = [];
  var dir = offset > 0 ? -1 : 1; // This forces offset to approach 0 from either direction.
  while (off !== 0) {
    values.push(start + off);
    off += dir;
  }

  return values;
}

function flattenRanges(selectedRows) {
  return selectedRows.reduce(function (rows, selection) {
    if ((typeof selection === 'undefined' ? 'undefined' : _typeof(selection)) === 'object') {
      var values = genRangeOfValues(selection.end, selection.start - selection.end);
      values.push(selection.end);
      values.forEach(function (selectionRow) {
        if (rows.indexOf(selectionRow) === -1) {
          rows.push(selectionRow);
        }
      });
    } else if (rows.indexOf(selection) === -1) {
      rows.push(selection);
    }
    return rows;
  }, []).sort();
}

function calculateSelectedRows(props) {
  // Determine what rows are 'pre-selected'.
  var preSelectedRows = [];
  var selectable = props.selectable,
      multiSelectable = props.multiSelectable,
      children = props.children;

  if (selectable) {
    var index = 0;
    _react.Children.forEach(children, function (child) {
      if ((0, _react.isValidElement)(child)) {
        if (child.props.selected && (preSelectedRows.length === 0 || multiSelectable)) {
          preSelectedRows.push(index);
        }
        index += 1;
      }
    });
  }

  return preSelectedRows;
}

var TableBody = function (_PureComponent) {
  _inherits(TableBody, _PureComponent);

  function TableBody() {
    var _ref6;

    var _temp, _this, _ret;

    _classCallCheck(this, TableBody);

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

    return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref6 = TableBody.__proto__ || Object.getPrototypeOf(TableBody)).call.apply(_ref6, [this].concat(args))), _this), _this.state = {
      selectedRows: [],
      children: []
    }, _this.onCellClick = function (event, rowNumber, columnNumber) {
      event.stopPropagation();
      if (_this.props.onCellClick) {
        _this.props.onCellClick(rowNumber, _this.getColumnId(columnNumber), event);
      }
    }, _this.onRowClick = function (event, rowNumber) {
      var selectable = _this.props.selectable;


      if (selectable) {
        // Prevent text selection while selecting rows.
        _this.processRowSelection(event, rowNumber);
      }
    }, _this.getColumnId = function (columnNumber) {
      return _this.props.displayRowCheckbox ? columnNumber - 1 : columnNumber;
    }, _this.buildPaginatedChildren = function (resultChildren, paginate, pageCount, pageSelected, handlePageChange, setPageCount) {
      var chunkedChildren = (0, _chunk2.default)(resultChildren, paginate);
      if (chunkedChildren.length !== pageCount) {
        handlePageChange({ selected: 0 });
      }
      setPageCount(chunkedChildren.length);
      return chunkedChildren[pageSelected];
    }, _this.isIndexInSelection = function (rowNumber, rows) {
      var selectedRows = rows || _this.state.selectedRows;
      var selectedRow = selectedRows.find(function (selection) {
        if ((typeof selection === 'undefined' ? 'undefined' : _typeof(selection)) === 'object') {
          return isValueInRange(rowNumber, selection);
        }
        return selection === rowNumber;
      });
      return typeof selectedRow !== 'undefined';
    }, _temp), _possibleConstructorReturn(_this, _ret);
  }

  _createClass(TableBody, [{
    key: 'componentWillMount',
    value: function componentWillMount() {
      var selectedRows = calculateSelectedRows(this.props);
      this.setState({
        selectedRows: selectedRows,
        selectedChildren: selectedRows,
        children: this.buildChildren(selectedRows)
      });
    }
  }, {
    key: 'componentWillReceiveProps',
    value: function componentWillReceiveProps(nextProps) {
      var reCalculateSelection = nextProps.reCalculateSelection,
          sort = nextProps.sort,
          order = nextProps.order;
      var children = this.state.children;


      if (reCalculateSelection) {
        var selectedChildren = calculateSelectedRows(nextProps);
        this.setState({
          selectedChildren: selectedChildren,
          children: this.buildChildren(selectedChildren, nextProps)
        });
      } else {
        this.setState({
          children: this.buildChildren(this.state.selectedChildren, nextProps)
        });
      }
      if (sort !== this.props.sort || order !== this.props.order) {
        this.setState({
          selectedRows: getNewSelectedRows({ children: children, selectedChildren: this.state.selectedChildren, sort: sort, order: order })
        });
      }
    }
  }, {
    key: 'onChange',
    value: function onChange(selectedRows) {
      var _props = this.props,
          onChange = _props.onChange,
          multiSelectable = _props.multiSelectable;
      var children = this.state.children;

      var values = children.filter(function (_ref7) {
        var rowNumber = _ref7.props.rowNumber;
        return selectedRows.indexOf(rowNumber) !== -1;
      }).map(function (_ref8) {
        var value = _ref8.props.value;
        return value;
      });
      onChange(multiSelectable ? values : values[0]);
    }
  }, {
    key: 'buildChildren',
    value: function buildChildren(selectedChildren, props) {
      var _ref9 = props || this.props,
          children = _ref9.children,
          displayRowCheckbox = _ref9.displayRowCheckbox,
          sort = _ref9.sort,
          order = _ref9.order,
          multiSelectable = _ref9.multiSelectable,
          selectable = _ref9.selectable,
          filterOptions = _ref9.filterOptions,
          paginate = _ref9.paginate,
          pageSelected = _ref9.pageSelected,
          setPageCount = _ref9.setPageCount,
          pageCount = _ref9.pageCount,
          handlePageChange = _ref9.handlePageChange;

      var safePaginate = Math.abs(parseInt(paginate, 10));
      var resultChildren = children ? createFilteredRows({
        children: children,
        sort: sort,
        order: order,
        filterOptions: filterOptions,
        isRowSelected: function isRowSelected(currentIndex) {
          return selectedChildren && selectedChildren.indexOf(currentIndex) > -1;
        },
        props: {
          multiSelectable: multiSelectable,
          displayRowCheckbox: displayRowCheckbox,
          onCellClick: this.onCellClick,
          onRowClick: this.onRowClick,
          selectable: selectable
        }
      }) : null;
      return paginate ? this.buildPaginatedChildren(resultChildren, safePaginate, pageCount, pageSelected, handlePageChange, setPageCount) : resultChildren;
    }
  }, {
    key: 'processRowSelection',
    value: function processRowSelection(event, rowNumber) {
      var _this2 = this;

      var selectedRows = this.state.selectedRows ? [].concat(_toConsumableArray(this.state.selectedRows)) : [];
      // let { selectedRows: [...selectedRows] } = this.state;
      var _props2 = this.props,
          multiSelectable = _props2.multiSelectable,
          onChange = _props2.onChange;


      if (event.shiftKey && multiSelectable && selectedRows.length) {
        var lastIndex = selectedRows.length - 1;
        var lastSelection = selectedRows[lastIndex];

        if ((typeof lastSelection === 'undefined' ? 'undefined' : _typeof(lastSelection)) === 'object') {
          lastSelection.end = rowNumber;
        } else {
          selectedRows.splice(lastIndex, 1, { start: lastSelection, end: rowNumber });
        }
      } else if (multiSelectable && (event.ctrlKey && !event.metaKey || event.metaKey && !event.ctrlKey || event.shiftKey)) {
        selectedRows = flattenRanges(selectedRows);
        var selectedIndexRow = selectedRows.indexOf(rowNumber);
        if (selectedIndexRow !== -1) {
          selectedRows.splice(selectedIndexRow, 1);
        } else {
          selectedRows.push(rowNumber);
        }
      } else {
        selectedRows = selectedRows.length === 1 && selectedRows[0] === rowNumber ? [] : [rowNumber];
      }
      var selectedChildren = this.state.children.reduce(function (acc, child, i) {
        if (_this2.isIndexInSelection(i, selectedRows)) {
          acc.push(child.props.index);
        }
        return acc;
      }, []);
      this.setState({
        selectedRows: selectedRows,
        selectedChildren: selectedChildren,
        children: this.buildChildren(selectedChildren)
      });
      if (onChange) {
        this.onChange(flattenRanges(selectedRows));
      }
    }
  }, {
    key: 'render',
    value: function render() {
      var children = this.state.children;

      return _react2.default.createElement(
        'tbody',
        { className: 'flive_table_table-body' },
        children
      );
    }
  }]);

  return TableBody;
}(_react.PureComponent);

TableBody.componentName = 'TableBody';
TableBody.propTypes = {
  /**
   * Children passed to table body.
   */
  children: _propTypes2.default.node, // eslint-disable-line react/no-unused-prop-types
  /**
   * Controls the display of the row checkbox.
   */
  displayRowCheckbox: _propTypes2.default.bool,
  /**
   * @ignore
   * Callback function for when a cell is clicked.
   */
  onCellClick: _propTypes2.default.func,
  /**
   * @ignore
   * Called when a row is selected. selectedRows is an
   * array of all row selections. IF all rows have been selected,
   * the string "all" will be returned instead to indicate that
   * all rows have been selected.
   */
  onChange: _propTypes2.default.func,
  /**
   * @ignore
   * If true, multiple table rows can be selected.
   * CTRL/CMD+Click and SHIFT+Click are valid actions.
   */
  multiSelectable: _propTypes2.default.bool,
  /**
   * @ignore
   * If true, table rows can be selected. If multiple
   * row selection is desired, enable multiSelectable.
   */
  selectable: _propTypes2.default.bool,
  sort: _propTypes2.default.array, // eslint-disable-line react/no-unused-prop-types
  order: _propTypes2.default.string, // eslint-disable-line react/no-unused-prop-types
  /**
   * @ignore
   * if true on 'componentWillReceiveProps' children will be calculate
   */
  reCalculateSelection: _propTypes2.default.bool
};
TableBody.defaultProps = {
  children: undefined,
  displayRowCheckbox: false,
  reCalculateSelection: true,
  multiSelectable: false,
  onCellClick: null,
  onChange: null,
  selectable: true,
  sort: null,
  order: 'asc'
};
exports.default = TableBody;
module.exports = exports['default'];