import Transition from '../transitions/transition';

const noop = () => {};

export const TRANSITION_EVENTS = {
  BREAK: 1,
  SNAP_TO_END: 2,
  IGNORE: 3
};

const DEFAULT_EASING = t => t;

const DEFAULT_INTERRUPTION = TRANSITION_EVENTS.BREAK;
export default class TransitionManager {
  constructor(opts) {
    this.getControllerState = void 0;
    this.props = void 0;
    this.propsInTransition = void 0;
    this.transition = void 0;
    this.onViewStateChange = void 0;
    this.onStateChange = void 0;

    this._onTransitionUpdate = transition => {
      const {
        time,
        settings: {
          interpolator,
          startProps,
          endProps,
          duration,
          easing
        }
      } = transition;
      const t = easing(time / duration);
      const viewport = interpolator.interpolateProps(startProps, endProps, t);
      this.propsInTransition = this.getControllerState({ ...this.props,
        ...viewport
      }).getViewportProps();
      this.onViewStateChange({
        viewState: this.propsInTransition,
        oldViewState: this.props
      });
    };

    this.getControllerState = opts.getControllerState;
    this.propsInTransition = null;
    this.transition = new Transition(opts.timeline);
    this.onViewStateChange = opts.onViewStateChange || noop;
    this.onStateChange = opts.onStateChange || noop;
  }

  finalize() {
    this.transition.cancel();
  }

  getViewportInTransition() {
    return this.propsInTransition;
  }

  processViewStateChange(nextProps) {
    let transitionTriggered = false;
    const currentProps = this.props;
    this.props = nextProps;

    if (!currentProps || this._shouldIgnoreViewportChange(currentProps, nextProps)) {
      return false;
    }

    if (this._isTransitionEnabled(nextProps)) {
      let startProps = currentProps;

      if (this.transition.inProgress) {
        const {
          interruption,
          endProps
        } = this.transition.settings;
        startProps = { ...currentProps,
          ...(interruption === TRANSITION_EVENTS.SNAP_TO_END ? endProps : this.propsInTransition || currentProps)
        };
      }

      this._triggerTransition(startProps, nextProps);

      transitionTriggered = true;
    } else {
      this.transition.cancel();
    }

    return transitionTriggered;
  }

  updateTransition() {
    this.transition.update();
  }

  _isTransitionEnabled(props) {
    const {
      transitionDuration,
      transitionInterpolator
    } = props;
    return (transitionDuration > 0 || transitionDuration === 'auto') && Boolean(transitionInterpolator);
  }

  _isUpdateDueToCurrentTransition(props) {
    if (this.transition.inProgress && this.propsInTransition) {
      return this.transition.settings.interpolator.arePropsEqual(props, this.propsInTransition);
    }

    return false;
  }

  _shouldIgnoreViewportChange(currentProps, nextProps) {
    if (this.transition.inProgress) {
      const transitionSettings = this.transition.settings;
      return transitionSettings.interruption === TRANSITION_EVENTS.IGNORE || this._isUpdateDueToCurrentTransition(nextProps);
    }

    if (this._isTransitionEnabled(nextProps)) {
      return nextProps.transitionInterpolator.arePropsEqual(currentProps, nextProps);
    }

    return true;
  }

  _triggerTransition(startProps, endProps) {
    const startViewstate = this.getControllerState(startProps);
    const endViewStateProps = this.getControllerState(endProps).shortestPathFrom(startViewstate);
    const transitionInterpolator = endProps.transitionInterpolator;
    const duration = transitionInterpolator.getDuration ? transitionInterpolator.getDuration(startProps, endProps) : endProps.transitionDuration;

    if (duration === 0) {
      return;
    }

    const initialProps = transitionInterpolator.initializeProps(startProps, endViewStateProps);
    this.propsInTransition = {};
    const transitionSettings = {
      duration,
      easing: endProps.transitionEasing || DEFAULT_EASING,
      interpolator: transitionInterpolator,
      interruption: endProps.transitionInterruption || DEFAULT_INTERRUPTION,
      startProps: initialProps.start,
      endProps: initialProps.end,
      onStart: endProps.onTransitionStart,
      onUpdate: this._onTransitionUpdate,
      onInterrupt: this._onTransitionEnd(endProps.onTransitionInterrupt),
      onEnd: this._onTransitionEnd(endProps.onTransitionEnd)
    };
    this.transition.start(transitionSettings);
    this.onStateChange({
      inTransition: true
    });
    this.updateTransition();
  }

  _onTransitionEnd(callback) {
    return transition => {
      this.propsInTransition = null;
      this.onStateChange({
        inTransition: false,
        isZooming: false,
        isPanning: false,
        isRotating: false
      });
      callback === null || callback === void 0 ? void 0 : callback(transition);
    };
  }

}
//# sourceMappingURL=transition-manager.js.map