"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.useTimeSlider = exports.TimeSliderControlEmbeddable = exports.TimeSliderControlContext = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _lodash = _interopRequireDefault(require("lodash"));
var _operators = require("rxjs/operators");
var _momentTimezone = _interopRequireDefault(require("moment-timezone"));
var _public = require("@kbn/embeddable-plugin/public");
var _public2 = require("@kbn/kibana-react-plugin/public");
var _react = _interopRequireWildcard(require("react"));
var _reactDom = _interopRequireDefault(require("react-dom"));
var _2 = require("../..");
var _services = require("../../services");
var _components = require("../components");
var _time_slider_reducers = require("../time_slider_reducers");
var _time_utils = require("../time_utils");
var _time_slider_selectors = require("../time_slider_selectors");
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 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 TimeSliderControlContext = /*#__PURE__*/(0, _react.createContext)(null);
exports.TimeSliderControlContext = TimeSliderControlContext;
const useTimeSlider = () => {
  const timeSlider = (0, _react.useContext)(TimeSliderControlContext);
  if (timeSlider == null) {
    throw new Error('useTimeSlider must be used inside TimeSliderControlContext.');
  }
  return timeSlider;
};
exports.useTimeSlider = useTimeSlider;
class TimeSliderControlEmbeddable extends _public.Embeddable {
  // state management

  constructor(reduxToolsPackage, input, output, parent) {
    super(input, output, parent);
    (0, _defineProperty2.default)(this, "type", _2.TIME_SLIDER_CONTROL);
    (0, _defineProperty2.default)(this, "deferEmbeddedLoad", true);
    (0, _defineProperty2.default)(this, "inputSubscription", void 0);
    (0, _defineProperty2.default)(this, "node", void 0);
    (0, _defineProperty2.default)(this, "select", void 0);
    (0, _defineProperty2.default)(this, "getState", void 0);
    (0, _defineProperty2.default)(this, "dispatch", void 0);
    (0, _defineProperty2.default)(this, "onStateChange", void 0);
    (0, _defineProperty2.default)(this, "cleanupStateTools", void 0);
    (0, _defineProperty2.default)(this, "getTimezone", void 0);
    (0, _defineProperty2.default)(this, "timefilter", void 0);
    (0, _defineProperty2.default)(this, "prevTimeRange", void 0);
    (0, _defineProperty2.default)(this, "prevTimesliceAsPercentage", void 0);
    (0, _defineProperty2.default)(this, "waitForControlOutputConsumersToLoad$", void 0);
    (0, _defineProperty2.default)(this, "destroy", () => {
      super.destroy();
      this.cleanupStateTools();
      if (this.inputSubscription) {
        this.inputSubscription.unsubscribe();
      }
    });
    (0, _defineProperty2.default)(this, "debouncedPublishChange", _lodash.default.debounce(value => {
      this.dispatch.publishValue({
        value
      });
    }, 500));
    (0, _defineProperty2.default)(this, "onTimesliceChange", value => {
      const {
        timesliceStartAsPercentageOfTimeRange,
        timesliceEndAsPercentageOfTimeRange
      } = this.getTimeSliceAsPercentageOfTimeRange(value);
      this.dispatch.setValueAsPercentageOfTimeRange({
        timesliceStartAsPercentageOfTimeRange,
        timesliceEndAsPercentageOfTimeRange
      });
      this.dispatch.setValue({
        value
      });
      this.debouncedPublishChange(value);
    });
    (0, _defineProperty2.default)(this, "onRangeChange", range => {
      const timeRangeBounds = this.getState().componentState.timeRangeBounds;
      const timeRange = timeRangeBounds[_time_utils.TO_INDEX] - timeRangeBounds[_time_utils.FROM_INDEX];
      this.dispatch.setRange({
        range: range !== undefined && range < timeRange ? range : undefined
      });
    });
    (0, _defineProperty2.default)(this, "onNext", () => {
      const {
        value,
        range,
        ticks
      } = this.getState().componentState;
      const isAnchored = (0, _time_slider_selectors.getIsAnchored)(this.getState());
      const tickRange = ticks[1].value - ticks[0].value;
      const timeRangeBounds = (0, _time_slider_selectors.getRoundedTimeRangeBounds)(this.getState());
      if (isAnchored) {
        if (value === undefined || value[_time_utils.TO_INDEX] >= timeRangeBounds[_time_utils.TO_INDEX]) {
          this.onTimesliceChange([timeRangeBounds[_time_utils.FROM_INDEX], ticks[0].value]);
          return;
        }
        const nextTick = ticks.find(tick => {
          return tick.value > value[_time_utils.TO_INDEX];
        });
        this.onTimesliceChange([timeRangeBounds[_time_utils.FROM_INDEX], nextTick ? nextTick.value : timeRangeBounds[_time_utils.TO_INDEX]]);
        return;
      }
      if (value === undefined || value[_time_utils.TO_INDEX] >= timeRangeBounds[_time_utils.TO_INDEX]) {
        const from = timeRangeBounds[_time_utils.FROM_INDEX];
        if (range === undefined || range === tickRange) {
          const firstTickValue = ticks[0].value;
          const secondTickValue = ticks[1].value;
          const to = firstTickValue === from ? secondTickValue : firstTickValue;
          this.onTimesliceChange([from, to]);
          this.onRangeChange(tickRange);
        } else {
          const to = from + range;
          this.onTimesliceChange([from, Math.min(to, timeRangeBounds[_time_utils.TO_INDEX])]);
        }
        return;
      }
      const from = value[_time_utils.TO_INDEX];
      const safeRange = range === undefined ? tickRange : range;
      const to = from + safeRange;
      this.onTimesliceChange([from, Math.min(to, timeRangeBounds[_time_utils.TO_INDEX])]);
    });
    (0, _defineProperty2.default)(this, "onPrevious", () => {
      const {
        value,
        range,
        ticks
      } = this.getState().componentState;
      const isAnchored = (0, _time_slider_selectors.getIsAnchored)(this.getState());
      const tickRange = ticks[1].value - ticks[0].value;
      const timeRangeBounds = (0, _time_slider_selectors.getRoundedTimeRangeBounds)(this.getState());
      if (isAnchored) {
        const prevTick = value ? [...ticks].reverse().find(tick => {
          return tick.value < value[_time_utils.TO_INDEX];
        }) : ticks[ticks.length - 1];
        this.onTimesliceChange([timeRangeBounds[_time_utils.FROM_INDEX], prevTick ? prevTick.value : timeRangeBounds[_time_utils.TO_INDEX]]);
        return;
      }
      if (value === undefined || value[_time_utils.FROM_INDEX] <= timeRangeBounds[_time_utils.FROM_INDEX]) {
        const to = timeRangeBounds[_time_utils.TO_INDEX];
        if (range === undefined || range === tickRange) {
          const lastTickValue = ticks[ticks.length - 1].value;
          const secondToLastTickValue = ticks[ticks.length - 2].value;
          const from = lastTickValue === to ? secondToLastTickValue : lastTickValue;
          this.onTimesliceChange([from, to]);
          this.onRangeChange(tickRange);
        } else {
          const from = to - range;
          this.onTimesliceChange([Math.max(from, timeRangeBounds[_time_utils.FROM_INDEX]), to]);
        }
        return;
      }
      const to = value[_time_utils.FROM_INDEX];
      const safeRange = range === undefined ? tickRange : range;
      const from = to - safeRange;
      this.onTimesliceChange([Math.max(from, timeRangeBounds[_time_utils.FROM_INDEX]), to]);
    });
    (0, _defineProperty2.default)(this, "formatDate", epoch => {
      return _momentTimezone.default.tz(epoch, (0, _time_utils.getMomentTimezone)(this.getTimezone())).format(this.getState().componentState.format);
    });
    (0, _defineProperty2.default)(this, "render", node => {
      if (this.node) {
        _reactDom.default.unmountComponentAtNode(this.node);
      }
      this.node = node;
      _reactDom.default.render( /*#__PURE__*/_react.default.createElement(_public2.KibanaThemeProvider, {
        theme$: _services.pluginServices.getServices().theme.theme$
      }, /*#__PURE__*/_react.default.createElement(TimeSliderControlContext.Provider, {
        value: this
      }, /*#__PURE__*/_react.default.createElement(_components.TimeSlider, {
        formatDate: this.formatDate,
        onChange: value => {
          this.onTimesliceChange(value);
          const range = value ? value[_time_utils.TO_INDEX] - value[_time_utils.FROM_INDEX] : undefined;
          this.onRangeChange(range);
        }
      }))), node);
    });
    const {
      data: {
        timefilter
      },
      settings: {
        getDefaultTimeRange,
        getTimezone
      }
    } = _services.pluginServices.getServices();
    this.getTimezone = getTimezone;
    this.timefilter = timefilter;
    const _timeRangeBounds = this.timeRangeToBounds(input.timeRange ? input.timeRange : getDefaultTimeRange());
    const _ticks = (0, _time_utils.getTicks)(_timeRangeBounds[_time_utils.FROM_INDEX], _timeRangeBounds[_time_utils.TO_INDEX], this.getTimezone());
    const reduxEmbeddableTools = reduxToolsPackage.createReduxEmbeddableTools({
      embeddable: this,
      reducers: _time_slider_reducers.timeSliderReducers,
      initialComponentState: {
        isOpen: false,
        ...(0, _time_utils.getStepSize)(_ticks),
        ticks: _ticks,
        timeRangeBounds: _timeRangeBounds
      }
    });
    this.select = reduxEmbeddableTools.select;
    this.getState = reduxEmbeddableTools.getState;
    this.dispatch = reduxEmbeddableTools.dispatch;
    this.onStateChange = reduxEmbeddableTools.onStateChange;
    this.cleanupStateTools = reduxEmbeddableTools.cleanup;
    this.inputSubscription = this.getInput$().subscribe(() => this.onInputChange());
    this.waitForControlOutputConsumersToLoad$ = parent && 'anyControlOutputConsumerLoading$' in parent ? parent.anyControlOutputConsumerLoading$.pipe((0, _operators.debounceTime)(300), (0, _operators.first)(isAnyControlOutputConsumerLoading => {
      return !isAnyControlOutputConsumerLoading;
    }), (0, _operators.map)(() => {
      // Observable notifies subscriber when loading is finished
      // Return void to not expose internal implemenation details of observabale
      return;
    })) : undefined;
    this.prevTimesliceAsPercentage = {
      timesliceStartAsPercentageOfTimeRange: this.getInput().timesliceStartAsPercentageOfTimeRange,
      timesliceEndAsPercentageOfTimeRange: this.getInput().timesliceEndAsPercentageOfTimeRange
    };
    this.syncWithTimeRange();
  }
  onInputChange() {
    var _this$prevTimesliceAs;
    const input = this.getInput();
    const {
      timesliceStartAsPercentageOfTimeRange,
      timesliceEndAsPercentageOfTimeRange
    } = (_this$prevTimesliceAs = this.prevTimesliceAsPercentage) !== null && _this$prevTimesliceAs !== void 0 ? _this$prevTimesliceAs : {};
    if (timesliceStartAsPercentageOfTimeRange !== input.timesliceStartAsPercentageOfTimeRange || timesliceEndAsPercentageOfTimeRange !== input.timesliceEndAsPercentageOfTimeRange) {
      // Discarding edit mode changes results in replacing edited input with original input
      // Re-sync with time range when edited input timeslice changes are discarded
      if (!input.timesliceStartAsPercentageOfTimeRange && !input.timesliceEndAsPercentageOfTimeRange) {
        // If no selections have been saved into the timeslider, then both `timesliceStartAsPercentageOfTimeRange`
        // and `timesliceEndAsPercentageOfTimeRange` will be undefined - so, need to reset component state to match
        this.dispatch.publishValue({
          value: undefined
        });
        this.dispatch.setValue({
          value: undefined
        });
      } else {
        // Otherwise, need to call `syncWithTimeRange` so that the component state value can be calculated and set
        this.syncWithTimeRange();
      }
    } else if (input.timeRange && !_lodash.default.isEqual(input.timeRange, this.prevTimeRange)) {
      const nextBounds = this.timeRangeToBounds(input.timeRange);
      const ticks = (0, _time_utils.getTicks)(nextBounds[_time_utils.FROM_INDEX], nextBounds[_time_utils.TO_INDEX], this.getTimezone());
      this.dispatch.setTimeRangeBounds({
        ...(0, _time_utils.getStepSize)(ticks),
        ticks,
        timeRangeBounds: nextBounds
      });
      this.syncWithTimeRange();
    }
  }
  syncWithTimeRange() {
    this.prevTimeRange = this.getInput().timeRange;
    const stepSize = this.getState().componentState.stepSize;
    const {
      timesliceStartAsPercentageOfTimeRange,
      timesliceEndAsPercentageOfTimeRange
    } = this.getState().explicitInput;
    if (timesliceStartAsPercentageOfTimeRange !== undefined && timesliceEndAsPercentageOfTimeRange !== undefined) {
      const timeRangeBounds = this.getState().componentState.timeRangeBounds;
      const timeRange = timeRangeBounds[_time_utils.TO_INDEX] - timeRangeBounds[_time_utils.FROM_INDEX];
      const from = timeRangeBounds[_time_utils.FROM_INDEX] + timesliceStartAsPercentageOfTimeRange * timeRange;
      const to = timeRangeBounds[_time_utils.FROM_INDEX] + timesliceEndAsPercentageOfTimeRange * timeRange;
      const value = [(0, _time_utils.roundDownToNextStepSizeFactor)(from, stepSize), (0, _time_utils.roundUpToNextStepSizeFactor)(to, stepSize)];
      this.dispatch.publishValue({
        value
      });
      this.dispatch.setValue({
        value
      });
      this.onRangeChange(value[_time_utils.TO_INDEX] - value[_time_utils.FROM_INDEX]);
    }
  }
  timeRangeToBounds(timeRange) {
    const timeRangeBounds = this.timefilter.calculateBounds(timeRange);
    return timeRangeBounds.min === undefined || timeRangeBounds.max === undefined ? [Date.now() - 1000 * 60 * 15, Date.now()] : [timeRangeBounds.min.valueOf(), timeRangeBounds.max.valueOf()];
  }
  reload() {
    return;
  }
  getTimeSliceAsPercentageOfTimeRange(value) {
    let timesliceStartAsPercentageOfTimeRange;
    let timesliceEndAsPercentageOfTimeRange;
    if (value) {
      const timeRangeBounds = this.getState().componentState.timeRangeBounds;
      const timeRange = timeRangeBounds[_time_utils.TO_INDEX] - timeRangeBounds[_time_utils.FROM_INDEX];
      timesliceStartAsPercentageOfTimeRange = (value[_time_utils.FROM_INDEX] - timeRangeBounds[_time_utils.FROM_INDEX]) / timeRange;
      timesliceEndAsPercentageOfTimeRange = (value[_time_utils.TO_INDEX] - timeRangeBounds[_time_utils.FROM_INDEX]) / timeRange;
    }
    this.prevTimesliceAsPercentage = {
      timesliceStartAsPercentageOfTimeRange,
      timesliceEndAsPercentageOfTimeRange
    };
    return {
      timesliceStartAsPercentageOfTimeRange,
      timesliceEndAsPercentageOfTimeRange
    };
  }
  clearSelections() {
    this.onTimesliceChange();
  }
  renderPrepend() {
    return /*#__PURE__*/_react.default.createElement(TimeSliderControlContext.Provider, {
      value: this
    }, /*#__PURE__*/_react.default.createElement(_components.TimeSliderPrepend, {
      onNext: this.onNext,
      onPrevious: this.onPrevious,
      waitForControlOutputConsumersToLoad$: this.waitForControlOutputConsumersToLoad$
    }));
  }
  isChained() {
    return false;
  }
}
exports.TimeSliderControlEmbeddable = TimeSliderControlEmbeddable;