"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.controlOrdersAreEqual = exports.cachedChildEmbeddableOrder = exports.ControlGroupChainingSystems = void 0;
var _lodash = require("lodash");
var _fastDeepEqual = _interopRequireDefault(require("fast-deep-equal"));
var _public = require("@kbn/embeddable-plugin/public");
/*
 * 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 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */

const getOrdersFromPanels = panels => {
  return Object.values(panels !== null && panels !== void 0 ? panels : {}).map(panel => ({
    id: panel.explicitInput.id,
    order: panel.order
  }));
};
const controlOrdersAreEqual = (panelsA, panelsB) => (0, _fastDeepEqual.default)(getOrdersFromPanels(panelsA), getOrdersFromPanels(panelsB));
exports.controlOrdersAreEqual = controlOrdersAreEqual;
const cachedChildEmbeddableOrder = (0, _lodash.memoize)(panels => {
  const IdsToOrder = {};
  const idsInOrder = [];
  Object.values(panels).sort((a, b) => a.order > b.order ? 1 : -1).forEach(panel => {
    IdsToOrder[panel.explicitInput.id] = panel.order;
    idsInOrder.push(panel.explicitInput.id);
  });
  const lastChildId = idsInOrder[idsInOrder.length - 1];
  return {
    IdsToOrder,
    idsInOrder,
    lastChildId
  };
}, panels => JSON.stringify(getOrdersFromPanels(panels)));
exports.cachedChildEmbeddableOrder = cachedChildEmbeddableOrder;
const ControlGroupChainingSystems = {
  HIERARCHICAL: {
    getContainerSettings: initialInput => ({
      childIdInitializeOrder: Object.values(initialInput.panels).sort((a, b) => a.order > b.order ? 1 : -1).map(panel => panel.explicitInput.id),
      initializeSequentially: true
    }),
    getPrecedingFilters: ({
      id,
      childOrder,
      getChild
    }) => {
      var _childOrder$IdsToOrde;
      let filters = [];
      let timeslice;
      const order = (_childOrder$IdsToOrde = childOrder.IdsToOrder) === null || _childOrder$IdsToOrde === void 0 ? void 0 : _childOrder$IdsToOrde[id];
      if (!order || order === 0) return {
        filters,
        timeslice
      };
      for (let i = 0; i < order; i++) {
        var _embeddableOutput$fil;
        const embeddable = getChild(childOrder.idsInOrder[i]);
        if (!embeddable || (0, _public.isErrorEmbeddable)(embeddable)) return {
          filters,
          timeslice
        };
        const embeddableOutput = embeddable.getOutput();
        if (embeddableOutput.timeslice) {
          timeslice = embeddableOutput.timeslice;
        }
        filters = [...filters, ...((_embeddableOutput$fil = embeddableOutput.filters) !== null && _embeddableOutput$fil !== void 0 ? _embeddableOutput$fil : [])];
      }
      return {
        filters,
        timeslice
      };
    },
    onChildChange: ({
      childOutputChangedId,
      childOrder,
      recalculateFilters$,
      getChild
    }) => {
      if (childOutputChangedId === childOrder.lastChildId) {
        // the last control's output has updated, recalculate filters
        recalculateFilters$.next(null);
        return;
      }

      // when output changes on a child which isn't the last
      let nextOrder = childOrder.IdsToOrder[childOutputChangedId] + 1;
      while (nextOrder < childOrder.idsInOrder.length) {
        var _nextControl$isChaine;
        const nextControl = getChild(childOrder.idsInOrder[nextOrder]);

        // make the next chained embeddable updateInputFromParent
        if (nextControl !== null && nextControl !== void 0 && (_nextControl$isChaine = nextControl.isChained) !== null && _nextControl$isChaine !== void 0 && _nextControl$isChaine.call(nextControl)) {
          setTimeout(() => nextControl.refreshInputFromParent(), 1 // run on next tick
          );

          return;
        }

        // recalculate filters when there are no chained controls to the right of the updated control
        if (nextControl.id === childOrder.lastChildId) {
          recalculateFilters$.next(null);
          return;
        }
        nextOrder += 1;
      }
    }
  },
  NONE: {
    getContainerSettings: () => undefined,
    getPrecedingFilters: () => undefined,
    onChildChange: ({
      recalculateFilters$
    }) => recalculateFilters$.next(null)
  }
};
exports.ControlGroupChainingSystems = ControlGroupChainingSystems;