"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.filterRowsByPivotSet = filterRowsByPivotSet;
exports.makeRow = makeRow;
exports.prepareRows = prepareRows;

var _data = require("../data");

var _utils = require("../utils");

var _isPlainObject = require("../../../lib/isPlainObject");

var _aggregate = require("../aggregate");

function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }

function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }

function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }

function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

function makeRow() {
  var _row$name;

  var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
      row = _ref.row,
      _ref$hideNamespacePre = _ref.hideNamespacePrefix,
      hideNamespacePrefix = _ref$hideNamespacePre === void 0 ? true : _ref$hideNamespacePre;

  return _objectSpread(_objectSpread({}, row), {}, {
    name: (0, _data.GetName)(row),
    sourceName: (_row$name = row === null || row === void 0 ? void 0 : row.name) !== null && _row$name !== void 0 ? _row$name : "",
    sortKey: hideNamespacePrefix ? (0, _utils.removeNamespacePrefix)((0, _data.GetName)(row), row) : (0, _data.GetName)(row)
  });
}

function filterRowsByPivotSet(rows, pivotSet) {
  return Array.from(pivotSet).reduce(function (accPivots, pivot) {
    var filteredRows = rows.reduce(function (acc, row) {
      if (row[pivot] != null) {
        acc[acc.length] = row[pivot];
      }

      return acc;
    }, []);

    if (filteredRows.length > 0) {
      accPivots[pivot] = (0, _aggregate.aggregate)(pivot, filteredRows);
    }

    return accPivots;
  }, {});
}

function prepareRows(_ref2) {
  var tableData = _ref2.tableData,
      _ref2$hideNamespacePr = _ref2.hideNamespacePrefix,
      hideNamespacePrefix = _ref2$hideNamespacePr === void 0 ? true : _ref2$hideNamespacePr,
      _ref2$pivotBy = _ref2.pivotBy,
      pivotBy = _ref2$pivotBy === void 0 ? null : _ref2$pivotBy,
      _ref2$pivotLookup = _ref2.pivotLookup,
      pivotLookup = _ref2$pivotLookup === void 0 ? null : _ref2$pivotLookup;

  if (pivotBy == null || pivotBy === "none") {
    var values = tableData === null || tableData === void 0 ? void 0 : tableData.reduce(function (acc, row, i) {
      acc.rows[i] = makeRow({
        row: row,
        hideNamespacePrefix: hideNamespacePrefix
      });
      return acc;
    }, {
      meta: {
        pivoted: false,
        pivotSet: new Set(),
        pivotBy: pivotBy
      },
      rows: []
    });
    return values;
  }

  if (pivotBy != null && pivotBy !== "none") {
    var _values = tableData.reduce(function (acc, row) {
      var length = acc.rows.length;
      var hasPivot = row[pivotBy] != null && row[pivotBy] !== "";
      var pivotValue = row[pivotBy];
      var isAggregate = row.isAggregate != null && row.isAggregate === true;
      var pivotValueIsObject = (0, _isPlainObject.isPlainObject)(pivotValue);

      if (isAggregate) {
        acc.meta.pivotSet.add("piv0t-aggregate");
        var subRows = (row === null || row === void 0 ? void 0 : row.subRows) != null ? prepareRows({
          tableData: row.subRows,
          hideNamespacePrefix: hideNamespacePrefix,
          pivotBy: pivotBy,
          pivotLookup: pivotLookup
        }) : [];

        if (subRows.rows.length === 0) {
          return acc;
        }

        subRows.meta.pivotSet.forEach(function (value) {
          acc.meta.pivotSet.add(value);
        });

        var newRow = _objectSpread(_objectSpread({}, row), {}, {
          subRows: subRows.rows
        });

        var aggregateFilters = filterRowsByPivotSet(subRows.rows, acc.meta.pivotSet);
        acc.rows[length] = _objectSpread({
          valueLookup: "piv0t-aggregate",
          pivoted: true,
          "piv0t-aggregate": makeRow({
            row: newRow,
            hideNamespacePrefix: hideNamespacePrefix
          })
        }, aggregateFilters);
      }

      if (hasPivot && pivotValueIsObject === false) {
        acc.meta.pivotSet.add("piv0t-".concat(pivotValue));
        acc.rows[length] = _defineProperty({
          valueLookup: "piv0t-".concat(pivotValue),
          pivoted: true
        }, "piv0t-".concat(pivotValue), makeRow({
          row: row,
          hideNamespacePrefix: hideNamespacePrefix
        }));
      }

      if (hasPivot && pivotValueIsObject) {
        var _length = acc.rows.length;
        var pivotObjectIsEmpty = Object.keys(pivotValue).length === 0;

        if (pivotObjectIsEmpty === false) {
          var keyObject = Object.entries(pivotValue).reduce(function (keyObjectAcc, _ref3) {
            var _ref4 = _slicedToArray(_ref3, 2),
                k = _ref4[0],
                v = _ref4[1];

            if (k === pivotLookup) {
              acc.meta.pivotSet.add("piv0t-".concat(v));
              keyObjectAcc["piv0t-".concat(v)] = makeRow({
                row: row,
                hideNamespacePrefix: hideNamespacePrefix
              });
            }

            return keyObjectAcc;
          }, {});

          if (Object.keys(keyObject).length === 0) {
            return acc;
          }

          acc.rows[_length] = _objectSpread({
            // It doesn't matter what the lookup is since they're identical
            valueLookup: Object.keys(keyObject)[0],
            pivoted: true
          }, keyObject);
        }
      }

      if (hasPivot === false && isAggregate === false) {
        acc.meta.pivotSet.add("piv0t-other");
        acc.rows[length] = {
          valueLookup: "piv0t-other",
          pivoted: true,
          "piv0t-other": makeRow({
            row: row,
            hideNamespacePrefix: hideNamespacePrefix
          })
        };
      }

      return acc;
    }, {
      meta: {
        pivoted: true,
        pivotSet: new Set(["piv0t-aggregate"]),
        pivotBy: pivotBy
      },
      rows: []
    });

    var pivotSet = _values.meta.pivotSet;

    if (pivotSet.has("piv0t-other")) {
      // Set iteration is by order of insertion, so this forces other to end.
      // By starting with "piv0t-aggregate" above, we force it to the start.
      pivotSet.delete("piv0t-other");
      pivotSet.add("piv0t-other");
    }

    return _values;
  }

  return {
    meta: {
      pivoted: true,
      pivotSet: new Set(),
      pivotBy: pivotBy
    },
    rows: []
  };
}