'use strict';

var _toConsumableArray = require('@babel/runtime/helpers/toConsumableArray');
var _defineProperty = require('@babel/runtime/helpers/defineProperty');
var cloneDeep = require('../../../node_modules/lodash-es/cloneDeep.js');
require('core-js/modules/es.array.concat.js');
require('core-js/modules/es.symbol.js');
require('core-js/modules/es.array.filter.js');
require('core-js/modules/es.array.find.js');
require('core-js/modules/es.array.includes.js');
require('core-js/modules/es.array.map.js');
require('core-js/modules/es.number.is-nan.js');
require('core-js/modules/es.object.get-own-property-descriptor.js');
require('core-js/modules/es.object.get-own-property-descriptors.js');
require('core-js/modules/es.object.keys.js');
require('core-js/modules/es.object.to-string.js');
require('core-js/modules/es.object.values.js');
require('core-js/modules/es.regexp.to-string.js');
require('core-js/modules/es.string.ends-with.js');
require('core-js/modules/es.string.includes.js');
require('core-js/modules/web.dom-collections.for-each.js');
var warning = require('warning');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

var _toConsumableArray__default = /*#__PURE__*/_interopDefault(_toConsumableArray);
var _defineProperty__default = /*#__PURE__*/_interopDefault(_defineProperty);
var warning__default = /*#__PURE__*/_interopDefault(warning);

function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty__default.default(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }

/**
 * Utility functions related to the measurement and calculation
 * of a table's column widths.
 */

// This width must be able to fit the elipsis of a truncated text + sort arrows + combobox dropdown (for filter)
var MIN_COLUMN_WIDTH = 120;
// This width can be used when adding a new column without a width.
var DEFAULT_COLUMN_WIDTH = 150;
var isColumnVisible = function isColumnVisible(ordering, columnId) {
  var orderedColumn = ordering.find(function (orderedCol) {
    return orderedCol.columnId === columnId;
  });
  return orderedColumn && !orderedColumn.isHidden;
};
function getTotalWidth(cols) {
  return cols.reduce(function (width, col) {
    return width + col.width;
  }, 0);
}
function createWidthsMap(ordering, columnWidths, adjustedCols) {
  var newColumnWidths = {};
  ordering.forEach(function (orderedColumn) {
    var current = Array.isArray(columnWidths) ? columnWidths.find(function (col) {
      return col.id === orderedColumn.columnId;
    }) : columnWidths[orderedColumn.columnId];
    newColumnWidths[orderedColumn.columnId] = {
      width: current !== null && current !== void 0 && current.width ? current.width.toString().includes('%') ? current.width : parseInt(current.width, 10) : undefined,
      id: orderedColumn.columnId
    };
  });
  adjustedCols.forEach(function (col) {
    newColumnWidths[col.id].width = col.width;
  });
  return newColumnWidths;
}
function getVisibleColumns(currentColumnWidths, ordering, excludeIDs) {
  return Object.values(currentColumnWidths).filter(function (col) {
    return col.width !== undefined && !excludeIDs.includes(col.id) && isColumnVisible(ordering, col.id);
  });
}
var getOriginalWidthOfColumn = function getOriginalWidthOfColumn(origColumns, colId) {
  var orginalWidth = origColumns.find(function (col) {
    return col.id === colId;
  }).width;
  return orginalWidth ? parseInt(orginalWidth, 10) : undefined;
};
function getExistingColumnWidth(currentColumnWidths, origColumns, colId) {
  var _currentColumnWidths$;
  var currentColumnWidth = (_currentColumnWidths$ = currentColumnWidths[colId]) === null || _currentColumnWidths$ === void 0 ? void 0 : _currentColumnWidths$.width;

  // If the column to show was hidden on init it will not have a current width
  // since it has not been rendered and measured. Then we try to get the original width.
  return currentColumnWidth || getOriginalWidthOfColumn(origColumns, colId);
}
function getAverageVisibleColumnWidth(visibleColumns) {
  var totalCurrentWidth = getTotalWidth(visibleColumns);
  return totalCurrentWidth / visibleColumns.length;
}
function shrinkColumns(shrinkableColumns, widthOfColumnToShow) {
  var availableWidth = getTotalWidth(shrinkableColumns);
  var shrunkenColumns = shrinkableColumns.map(function (col) {
    var preferredNewWidth = (availableWidth - widthOfColumnToShow) / shrinkableColumns.length;
    var newWidth = preferredNewWidth >= MIN_COLUMN_WIDTH ? preferredNewWidth : MIN_COLUMN_WIDTH;
    return {
      id: col.id,
      width: Math.round(newWidth)
    };
  });
  return shrunkenColumns;
}
function adjustColumnsBelowMinWidth(measuredWidth) {
  return measuredWidth.map(function (widthObj) {
    return widthObj.width < MIN_COLUMN_WIDTH ? _objectSpread(_objectSpread({}, widthObj), {}, {
      width: DEFAULT_COLUMN_WIDTH
    }) : widthObj;
  });
}

/**
 * Warns the developer in DEV mode if a column width is of incorrect format.
 * @param {array} columns The table column props
 */
var checkColumnWidthFormat = function checkColumnWidthFormat(columns) {
  columns.forEach(function (col) {
    if (col.hasOwnProperty('width') && col.width !== undefined) {
      if (typeof col.width !== 'string' || !col.width.endsWith('px') || Number.isNaN(parseInt(col.width, 10))) {
        warning__default.default(!("development" !== "production"), "Column width should be a string containing the width and the pixel unit\n          e.g. '100px' or have the value undefined.") ;
      }
    }
  });
};

/**
 * Returns an array of the IDs of all columns that exists in the
 * currentColumnWidths map but not in the ordering prop.
 * @param {array} ordering the table ordering prop that specifies the order and visibility of columns
 * @param {object} currentColumnWidths map of the current column IDs and widths
 */
var getIDsOfRemovedColumns = function getIDsOfRemovedColumns(ordering, currentColumnWidths) {
  return Object.values(currentColumnWidths).filter(function (currCol) {
    return !ordering.find(function (orderCol) {
      return orderCol.columnId === currCol.id;
    });
  }).map(function (col) {
    return col.id;
  });
};

/**
 * Returns an array of the IDs of all columns that exists in the
 * ordering prop but not in the currentColumnWidths map.
 * @param {array} ordering the table ordering prop that specifies the order and visibility of columns
 * @param {object} currentColumnWidths map of the current column IDs and widths
 */
var getIDsOfAddedVisibleColumns = function getIDsOfAddedVisibleColumns(ordering, currentColumnWidths) {
  return ordering.filter(function (col) {
    return !col.isHidden;
  }).filter(function (col) {
    return !currentColumnWidths.hasOwnProperty(col.columnId);
  }).map(function (col) {
    return col.columnId;
  });
};

/**
 * Returns true if there are visible columns
 * @param {array} ordering the table ordering prop that specifies the order and visibility of columns
 */
var hasVisibleColumns = function hasVisibleColumns(ordering) {
  return ordering.some(function (col) {
    return !col.isHidden;
  });
};

/**
 * Returns true if all visible columns have a width.
 * @param {array} ordering the table ordering prop that specifies the order and visibility of columns
 * @param {array} columns The table column props
 */
var visibleColumnsHaveWidth = function visibleColumnsHaveWidth(ordering, columns) {
  return columns.filter(function (col) {
    return isColumnVisible(ordering, col.id);
  }).every(function (col) {
    return col.hasOwnProperty('width') && col.width !== undefined;
  });
};
var addDefaultWidthToNewVisibleColumns = function addDefaultWidthToNewVisibleColumns(ordering, columns, currentColumnWidths) {
  if (!visibleColumnsHaveWidth(ordering, columns)) {
    var addedVisibleColumnIDs = getIDsOfAddedVisibleColumns(ordering, currentColumnWidths);
    return columns.map(function (column) {
      var isNewVisibleColumn = addedVisibleColumnIDs.includes(column.id);
      return _objectSpread(_objectSpread({}, column), {}, {
        width: isNewVisibleColumn && column.width === undefined ? "".concat(DEFAULT_COLUMN_WIDTH, "px") : column.width
      });
    });
  }
  return columns;
};
function addCurrentlyRenderedWidths(columns, currentColumnWidths) {
  return columns.map(function (col) {
    var _currentColumnWidths$2;
    var renderedWidth = (_currentColumnWidths$2 = currentColumnWidths[col.id]) === null || _currentColumnWidths$2 === void 0 ? void 0 : _currentColumnWidths$2.width;
    var width = col.width === undefined && renderedWidth !== undefined ? "".concat(renderedWidth, "px") : col.width;
    return _objectSpread(_objectSpread({}, col), {}, {
      width: width
    });
  });
}
var addMissingColumnWidths = function addMissingColumnWidths(_ref) {
  var ordering = _ref.ordering,
    columns = _ref.columns,
    currentColumnWidths = _ref.currentColumnWidths;
  var modifiedColumns = addDefaultWidthToNewVisibleColumns(ordering, columns, currentColumnWidths);
  return addCurrentlyRenderedWidths(modifiedColumns, currentColumnWidths);
};

/**
 * Returns the new column widths map when one or more columns are shown or added.
 * @param {object} currentColumnWidths map of the current column IDs and widths
 * @param {array} ordering the table ordering prop that specifies the order and visibility of columns
 * @param {array} colToShowIDs array of IDs of the columns to be shown/added
 * @param {array} columns The table column props
 */
var calculateWidthOnShow = function calculateWidthOnShow(currentColumnWidths, ordering, colToShowIDs, columns) {
  var visibleColumns = getVisibleColumns(currentColumnWidths, ordering, colToShowIDs);
  var newWidthColumns = [];
  var newColumnsToShow = colToShowIDs.map(function (colToShowId) {
    var existingWidth = getExistingColumnWidth(currentColumnWidths, columns, colToShowId);
    var widthOfColumnToShow = existingWidth || getAverageVisibleColumnWidth(visibleColumns) || MIN_COLUMN_WIDTH;
    var newColumnToShow = {
      id: colToShowId,
      width: Math.round(widthOfColumnToShow)
    };
    if (!existingWidth) {
      newWidthColumns.push(newColumnToShow);
    }
    return newColumnToShow;
  });
  var totalWidthNeeded = newColumnsToShow.reduce(function (acc, col) {
    return acc + col.width;
  }, 0);
  var shrinkableColumns = [].concat(_toConsumableArray__default.default(newColumnsToShow), _toConsumableArray__default.default(visibleColumns)).filter(function (col) {
    return col.width > MIN_COLUMN_WIDTH;
  });
  var adjustedCols = [].concat(newWidthColumns, _toConsumableArray__default.default(shrinkColumns(shrinkableColumns, totalWidthNeeded)));
  return createWidthsMap(ordering, currentColumnWidths, adjustedCols);
};

/**
 * Calculates the new column widths when one ore more columns are hidden or deleted.
 * @param {object} currentColumnWidths map of the current column IDs and widths
 * @param {array} ordering the table ordering prop that specifies the order and visibility of columns
 * @param {array} colToHideIDs Array with the IDs of one or more columns being hidden/deleted
 */
var calculateWidthOnHide = function calculateWidthOnHide(currentColumnWidths, ordering, colToHideIDs) {
  var columnsToHide = colToHideIDs.map(function (hideId) {
    var col = currentColumnWidths[hideId];
    return Number.isNaN(parseInt(col.width, 10)) ? {
      width: 0,
      id: hideId
    } : col;
  });
  var widthToDistribute = getTotalWidth(columnsToHide);
  var visibleCols = Object.values(currentColumnWidths).filter(function (col) {
    return isColumnVisible(ordering, col.id) && !colToHideIDs.includes(col.id);
  });
  var availableWidth = getTotalWidth(visibleCols);
  var adjustedCols = visibleCols.map(function (col) {
    var newWidth = col.width + col.width / availableWidth * widthToDistribute;
    return {
      id: col.id,
      width: Math.round(newWidth)
    };
  });
  return createWidthsMap(ordering, currentColumnWidths, adjustedCols);
};
function adjustLastColumnWidth(ordering, columns, measuredWidths) {
  // This function adjusts the last column width to the initial width if that one is larger.
  var visibleCols = ordering.filter(function (col) {
    return !col.isHidden;
  });

  // If there are no visible columns there is nothing to adjust
  if (!visibleCols.length) return measuredWidths;
  var lastIndex = visibleCols.length - 1;
  var lastColumn = columns.find(function (col) {
    return col.id === visibleCols[lastIndex].columnId;
  });
  var fixedWidth = lastColumn.width ? parseInt(lastColumn.width, 10) : 0;
  var measuredWidth = measuredWidths[lastIndex].width;
  var result = measuredWidths;
  if (measuredWidth < fixedWidth) {
    result = cloneDeep(measuredWidths);
    result[lastIndex].width = fixedWidth;
  }
  return result;
}

/**
 * When the browser layout engine sets the widths dynamically we need to to make
 * some adjustments to the last column width and also to column widths below
 * the allowed minimum.
 * @param {*} ordering
 * @param {*} columns
 * @param {*} measuredWidths
 */
var adjustInitialColumnWidths = function adjustInitialColumnWidths(ordering, columns, measuredWidths) {
  // If the table isn't wide enough for all columns that has a defined width
  // the browser will will shrink the last column instead of keeping its defined width.
  // We therefore eadjust the column width to the initial width if that one is larger.
  var adjustedWidths = adjustLastColumnWidth(ordering, columns, measuredWidths);

  // If the table-layout is fixed (prop useAutoTableLayoutForResize:false) and the
  // the table container isn't wide enough to fully render all column header texts the
  // browser will shrink the columns that don't have a defined width to make them all fit.
  // It is possible that the new widths are shrunk below our minimum width and in that case
  // we use the default width instead.
  return adjustColumnsBelowMinWidth(adjustedWidths);
};

/**
 * Creates a widths map based on current columns state + any changes in visibility or width
 * @param {array} ordering defining the order, via the index, and visiblity of columns
 * @param {object} currentColumnWidths map or object array of the current column IDs and widths
 * @param {array} adjustedCols contains objects with ID and modified width
 */
var createNewWidthsMap = function createNewWidthsMap(ordering, currentColumnWidths) {
  var adjustedCols = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
  return createWidthsMap(ordering, currentColumnWidths, adjustedCols);
};

/**
 * Calculates the new width of all columns when a column is toggled.
 * @param {object} currentColumnWidths map of the current column IDs and widths
 * @param {array} newOrdering defining the order, via the index, and visiblity of columns
 * @param {string} columnId the id of the column to be hidden/shown
 * @param {array} columns the orginal column definitions
 */
var calculateWidthsOnToggle = function calculateWidthsOnToggle(_ref2) {
  var currentColumnWidths = _ref2.currentColumnWidths,
    ordering = _ref2.newOrdering,
    columnId = _ref2.columnId,
    columns = _ref2.columns;
  var hideColumn = ordering.find(function (col) {
    return col.columnId === columnId;
  }).isHidden;
  return hideColumn ? calculateWidthOnHide(currentColumnWidths, ordering, [columnId]) : calculateWidthOnShow(currentColumnWidths, ordering, [columnId], columns);
};

exports.DEFAULT_COLUMN_WIDTH = DEFAULT_COLUMN_WIDTH;
exports.MIN_COLUMN_WIDTH = MIN_COLUMN_WIDTH;
exports.addDefaultWidthToNewVisibleColumns = addDefaultWidthToNewVisibleColumns;
exports.addMissingColumnWidths = addMissingColumnWidths;
exports.adjustInitialColumnWidths = adjustInitialColumnWidths;
exports.calculateWidthOnHide = calculateWidthOnHide;
exports.calculateWidthOnShow = calculateWidthOnShow;
exports.calculateWidthsOnToggle = calculateWidthsOnToggle;
exports.checkColumnWidthFormat = checkColumnWidthFormat;
exports.createNewWidthsMap = createNewWidthsMap;
exports.getIDsOfAddedVisibleColumns = getIDsOfAddedVisibleColumns;
exports.getIDsOfRemovedColumns = getIDsOfRemovedColumns;
exports.getOriginalWidthOfColumn = getOriginalWidthOfColumn;
exports.hasVisibleColumns = hasVisibleColumns;
exports.isColumnVisible = isColumnVisible;
exports.visibleColumnsHaveWidth = visibleColumnsHaveWidth;
