"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const syncTime = require("./dist-es-frameloop-sync-time.cjs");
const KeyframesResolver = require("./dist-es-render-utils-KeyframesResolver.cjs");
const canAnimate = require("./dist-es-animation-animators-utils-can-animate.cjs");
const getFinalKeyframe = require("./dist-es-animation-animators-waapi-utils-get-final-keyframe.cjs");
const MAX_RESOLVE_DELAY = 40;
class BaseAnimation {
  constructor({ autoplay = true, delay = 0, type = "keyframes", repeat = 0, repeatDelay = 0, repeatType = "loop", ...options }) {
    this.isStopped = false;
    this.hasAttemptedResolve = false;
    this.createdAt = syncTime.time.now();
    this.options = {
      autoplay,
      delay,
      type,
      repeat,
      repeatDelay,
      repeatType,
      ...options
    };
    this.updateFinishedPromise();
  }
  /**
   * This method uses the createdAt and resolvedAt to calculate the
   * animation startTime. *Ideally*, we would use the createdAt time as t=0
   * as the following frame would then be the first frame of the animation in
   * progress, which would feel snappier.
   *
   * However, if there's a delay (main thread work) between the creation of
   * the animation and the first commited frame, we prefer to use resolvedAt
   * to avoid a sudden jump into the animation.
   */
  calcStartTime() {
    if (!this.resolvedAt)
      return this.createdAt;
    return this.resolvedAt - this.createdAt > MAX_RESOLVE_DELAY ? this.resolvedAt : this.createdAt;
  }
  /**
   * A getter for resolved data. If keyframes are not yet resolved, accessing
   * this.resolved will synchronously flush all pending keyframe resolvers.
   * This is a deoptimisation, but at its worst still batches read/writes.
   */
  get resolved() {
    if (!this._resolved && !this.hasAttemptedResolve) {
      KeyframesResolver.flushKeyframeResolvers();
    }
    return this._resolved;
  }
  /**
   * A method to be called when the keyframes resolver completes. This method
   * will check if its possible to run the animation and, if not, skip it.
   * Otherwise, it will call initPlayback on the implementing class.
   */
  onKeyframesResolved(keyframes, finalKeyframe) {
    this.resolvedAt = syncTime.time.now();
    this.hasAttemptedResolve = true;
    const { name, type, velocity, delay, onComplete, onUpdate, isGenerator } = this.options;
    if (!isGenerator && !canAnimate.canAnimate(keyframes, name, type, velocity)) {
      if (!delay) {
        onUpdate && onUpdate(getFinalKeyframe.getFinalKeyframe(keyframes, this.options, finalKeyframe));
        onComplete && onComplete();
        this.resolveFinishedPromise();
        return;
      } else {
        this.options.duration = 0;
      }
    }
    const resolvedAnimation = this.initPlayback(keyframes, finalKeyframe);
    if (resolvedAnimation === false)
      return;
    this._resolved = {
      keyframes,
      finalKeyframe,
      ...resolvedAnimation
    };
    this.onPostResolved();
  }
  onPostResolved() {
  }
  /**
   * Allows the returned animation to be awaited or promise-chained. Currently
   * resolves when the animation finishes at all but in a future update could/should
   * reject if its cancels.
   */
  then(resolve, reject) {
    return this.currentFinishedPromise.then(resolve, reject);
  }
  flatten() {
    this.options.type = "keyframes";
    this.options.ease = "linear";
  }
  updateFinishedPromise() {
    this.currentFinishedPromise = new Promise((resolve) => {
      this.resolveFinishedPromise = resolve;
    });
  }
}
exports.BaseAnimation = BaseAnimation;
//# sourceMappingURL=dist-es-animation-animators-BaseAnimation.cjs.map
