import { assert } from "../../../core/assert.js";

/**
 * Represents animation of a meaningful multi-variate thing, such as 3d vector or single scalar
 */
export class AnimationTrack {
    /**
     * Human-readable label
     * @type {string}
     */
    name = ""

    /**
     * What property are we animating?
     * @type {string[]}
     */
    path = []

    /**
     *
     * @type {AnimationCurve[]}
     */
    curves = []

    /**
     * Special designator to help with interpolation
     * For example, quaternion tracks will require sampled value to be normalized
     * Based on this value, different bindings will be used
     * @type {string}
     */
    type = ""

    /**
     *
     * @returns {number}
     */
    get start_time() {

        const curves = this.curves;
        const curve_count = curves.length;

        if (curve_count <= 0) {
            return 0;
        }

        let r = Infinity;
        for (let i = 0; i < curve_count; i++) {
            const curve = curves[i];
            const s = curve.start_time;

            if (r > s) {
                r = s;
            }

        }

        return r;
    }

    /**
     *
     * @returns {number}
     */
    get end_time() {

        const curves = this.curves;
        const curve_count = curves.length;

        if (curve_count <= 0) {
            return 0;
        }

        let r = -Infinity;
        for (let i = 0; i < curve_count; i++) {
            const curve = curves[i];
            const s = curve.end_time;

            if (r < s) {
                r = s;
            }

        }

        return r;
    }

    /**
     * Time duration of the longest curve, in seconds
     * @return {number}
     */
    get duration() {
        return this.end_time - this.start_time;
    }

    /**
     *
     * @return {number}
     */
    get curve_count() {
        return this.curves.length;
    }

    /**
     *
     * @param {number[]|Float32Array|Float64Array} output
     * @param {number} output_offset
     * @param {number} time
     */
    sample(output, output_offset, time) {
        assert.isArrayLike(output, 'output');
        assert.isNonNegativeInteger(output_offset, 'output_offset');

        const curves = this.curves;
        const curve_count = curves.length;

        assert.greaterThanOrEqual(output.length, output_offset + curve_count, 'output overflow');

        for (let i = 0; i < curve_count; i++) {
            const curve = curves[i];

            output[output_offset + i] = curve.evaluate(time)
        }
    }

    /**
     *
     * @param {AnimationCurve[]} curves
     * @param {string} [name]
     * @return {AnimationTrack}
     */
    static from(curves = [], name = "") {
        assert.isString(name, 'name');
        assert.isArray(curves, 'curves');

        const r = new AnimationTrack();

        r.curves = curves;
        r.name = name;

        return r;
    }
}

/**
 * @readonly
 * @type {boolean}
 */
AnimationTrack.prototype.isAnimationTrack = true;