"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.assignNodeProperties = assignNodeProperties;
exports.elementsReducer = void 0;
var _reduxActions = require("redux-actions");
var _objectPathImmutable = _interopRequireDefault(require("object-path-immutable"));
var _lodash = require("lodash");
var actions = _interopRequireWildcard(require("../actions/elements"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0; you may not use this file except in compliance with the Elastic License
 * 2.0.
 */

const {
  assign,
  push,
  del,
  set
} = _objectPathImmutable.default;
const getLocation = type => type === 'group' ? 'groups' : 'elements';
const firstOccurrence = (element, index, array) => array.indexOf(element) === index;
const getLocationFromIds = (workpadState, pageId, nodeId) => {
  const page = workpadState.pages.find(p => p.id === pageId);
  const groups = page == null ? [] : page.groups || [];
  return groups.find(e => e.id === nodeId) ? 'groups' : 'elements';
};
function getPageIndexById(workpadState, pageId) {
  return (0, _lodash.get)(workpadState, 'pages', []).findIndex(page => page.id === pageId);
}
function getNodeIndexById(page, nodeId, location) {
  return page[location].findIndex(node => node.id === nodeId);
}
function assignNodeProperties(workpadState, pageId, nodeId, props) {
  const pageIndex = getPageIndexById(workpadState, pageId);
  const location = getLocationFromIds(workpadState, pageId, nodeId);
  const nodesPath = `pages.${pageIndex}.${location}`;
  const nodeIndex = (0, _lodash.get)(workpadState, nodesPath, []).findIndex(node => node.id === nodeId);
  if (pageIndex === -1 || nodeIndex === -1) {
    return workpadState;
  }
  return assign(workpadState, `${nodesPath}.${nodeIndex}`, props);
}
function moveNodeLayer(workpadState, pageId, nodeId, movement, location) {
  const pageIndex = getPageIndexById(workpadState, pageId);
  const nodeIndex = getNodeIndexById(workpadState.pages[pageIndex], nodeId, location);
  const nodes = (0, _lodash.get)(workpadState, ['pages', pageIndex, location]);
  const from = nodeIndex;
  const to = function () {
    if (movement < Infinity && movement > -Infinity) {
      return nodeIndex + movement;
    }
    if (movement === Infinity) {
      return nodes.length - 1;
    }
    if (movement === -Infinity) {
      return 0;
    }
    throw new Error('Invalid element layer movement');
  }();
  if (to > nodes.length - 1 || to < 0) {
    return workpadState;
  }

  // Common
  const newNodes = nodes.slice(0);
  newNodes.splice(to, 0, newNodes.splice(from, 1)[0]);
  return set(workpadState, `pages.${pageIndex}.${location}`, newNodes);
}
const trimPosition = ({
  left,
  top,
  width,
  height,
  angle,
  parent
}) => ({
  left,
  top,
  width,
  height,
  angle,
  parent
});
const trimElement = ({
  id,
  position,
  expression,
  filter
}) => ({
  id,
  position: trimPosition(position),
  ...(position.type !== 'group' && {
    expression
  }),
  ...(filter !== void 0 && {
    filter
  })
});
const getPageWithElementId = (workpad, elementId) => {
  const matchingPage = workpad.pages.find(page => page.elements.map(element => element.id).includes(elementId));
  if (matchingPage) {
    return matchingPage.id;
  }
  return undefined;
};
const elementsReducer = (0, _reduxActions.handleActions)({
  // TODO: This takes the entire element, which is not necessary, it could just take the id.
  [actions.setExpression]: (workpadState, {
    payload
  }) => {
    const {
      expression,
      pageId,
      elementId
    } = payload;
    return assignNodeProperties(workpadState, pageId, elementId, {
      expression
    });
  },
  [actions.setFilter]: (workpadState, {
    payload
  }) => {
    const {
      filter,
      elementId
    } = payload;
    const pageId = getPageWithElementId(workpadState, elementId);
    return assignNodeProperties(workpadState, pageId, elementId, {
      filter
    });
  },
  [actions.setMultiplePositions]: (workpadState, {
    payload
  }) => payload.repositionedElements.reduce((previousWorkpadState, {
    position,
    pageId,
    elementId
  }) => assignNodeProperties(previousWorkpadState, pageId, elementId, {
    position: trimPosition(position)
  }), workpadState),
  [actions.elementLayer]: (workpadState, {
    payload: {
      pageId,
      elementId,
      movement
    }
  }) => {
    const location = getLocationFromIds(workpadState, pageId, elementId);
    return moveNodeLayer(workpadState, pageId, elementId, movement, location);
  },
  [actions.addElement]: (workpadState, {
    payload: {
      pageId,
      element
    }
  }) => {
    const pageIndex = getPageIndexById(workpadState, pageId);
    if (pageIndex < 0) {
      return workpadState;
    }
    if (
    // don't add a group that is already persisted
    workpadState.pages[pageIndex][getLocation(element.position.type)].find(e => e.id === element.id)) {
      return workpadState;
    }
    return push(workpadState, `pages.${pageIndex}.${getLocation(element.position.type)}`, trimElement(element));
  },
  [actions.insertNodes]: (workpadState, {
    payload: {
      pageId,
      elements
    }
  }) => {
    const pageIndex = getPageIndexById(workpadState, pageId);
    if (pageIndex < 0) {
      return workpadState;
    }
    return elements.reduce((state, element) => push(state, `pages.${pageIndex}.${getLocation(element.position.type)}`, trimElement(element)), workpadState);
  },
  [actions.removeElements]: (workpadState, {
    payload: {
      pageId,
      elementIds
    }
  }) => {
    const pageIndex = getPageIndexById(workpadState, pageId);
    if (pageIndex < 0) {
      return workpadState;
    }
    const nodeIndices = elementIds.filter(firstOccurrence).map(nodeId => {
      const location = getLocationFromIds(workpadState, pageId, nodeId);
      return {
        location,
        index: getNodeIndexById(workpadState.pages[pageIndex], nodeId, location)
      };
    }).sort((a, b) => b.index - a.index); // deleting from end toward beginning, otherwise indices will become off - todo fuse loops!

    return nodeIndices.reduce((state, {
      location,
      index
    }) => {
      return del(state, `pages.${pageIndex}.${location}.${index}`);
    }, workpadState);
  }
}, {});
exports.elementsReducer = elementsReducer;