"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Animation = exports.AnimationSpeed = void 0;
const common_1 = require("../../../../../utils/common");
const time_functions_1 = require("../../../../../utils/time_functions");
exports.AnimationSpeed = Object.freeze({
    extraFast: 90,
    fast: 150,
    normal: 250,
    slow: 350,
    extraSlow: 500,
});
class Animation {
    initial;
    target;
    previousTarget;
    current;
    snapValues;
    timeFunction;
    delay;
    duration;
    timeOffset;
    timingFn = time_functions_1.TimingFunctions.linear;
    constructor(value, options = {}) {
        this.initial = options?.initialValue ?? value;
        this.current = options?.initialValue ?? value;
        this.target = value;
        this.previousTarget = value;
        this.timeOffset = 0;
        this.delay = (typeof options?.delay === 'string' ? exports.AnimationSpeed[options.delay] : options?.delay) ?? 0;
        this.duration =
            typeof options?.duration === 'string'
                ? exports.AnimationSpeed[options.duration]
                : options?.duration ?? exports.AnimationSpeed.slow;
        this.timeFunction = options?.timeFunction ?? time_functions_1.TimeFunction.linear;
        this.snapValues = options?.snapValues ?? [];
        this.setTimingFn();
    }
    isDelayed(t) {
        if (this.timeOffset !== 0)
            return false;
        return t < this.delay;
    }
    isActive(t) {
        if (!(0, common_1.isFiniteNumber)(this.initial) || !(0, common_1.isFiniteNumber)(this.target) || this.initial === this.target) {
            return false;
        }
        return t - this.delay + this.timeOffset < this.duration;
    }
    setTarget(value) {
        if (this.snapValues.includes(value)) {
            this.current = value;
            this.clear();
        }
        else if (this.target !== value) {
            if (this.previousTarget) {
                this.initial = this.previousTarget;
                this.target = value;
                this.setTimingFn();
                this.timeOffset = this.invertTimingFn();
            }
            else {
                this.timeOffset = 0;
                this.initial = this.current;
                this.target = value;
                this.setTimingFn();
            }
        }
    }
    invertTimingFn() {
        const scaledValue = this.current - this.initial;
        const scalar = this.target - this.initial;
        const multiplier = scaledValue / scalar;
        const timeDelta = (0, common_1.clamp)(time_functions_1.TimingFunctions[this.timeFunction].inverse(multiplier), 0, 1);
        return timeDelta * this.duration + this.delay;
    }
    setTimingFn() {
        const scalar = this.target - this.initial;
        this.timingFn =
            scalar === 0
                ? () => this.initial
                : (t) => {
                    const multiplier = time_functions_1.TimingFunctions[this.timeFunction](t);
                    return this.initial + scalar * multiplier;
                };
    }
    valueAtTime(t) {
        if (this.isDelayed(t))
            return this.initial;
        const unitNormalizedTime = Math.max(0, Math.min(1, (t - this.delay + this.timeOffset) / this.duration));
        const value = this.timingFn(unitNormalizedTime);
        this.current = value;
        return value;
    }
    clear() {
        this.previousTarget = this.current === this.target ? null : this.target;
        this.initial = this.current;
        this.target = this.current;
        this.setTimingFn();
    }
}
exports.Animation = Animation;
//# sourceMappingURL=animation.js.map