import { _u } from './utils/_u';
import { getWrapper } from './getWrapper';
/**
 * This module provides a function, getTween,
 * that smoothly transitions a given target node through a series of keyframes.
 * The keyframes are defined by an array of KeyFrameOptions,
 * ts = TimeStamp, is set as percent of duration. 0 - 1.
 * autoWrap: if true, the transform will copied to the wrapper node and reset on the target node.
 * @example
 * ```ts
 
// Basic usage
let spr: HNode = getPrefab({ id: 'sphere_01', p: [0, 0, 15], r: [0, 0, 90] });
spr = getTween(
  spr,
  [
    { ts: 0.25, p: [0, 2, 0] },
    { ts: 1, p: [0, 0, 0] },
  ],
  { loopBehaviour: 'RESTART', duration: 4 }
);

// Advanced usage
const kf: KeyFrameOptions[] = [
  { ts: 0, s: [1, 1, 1], easing: 'EASE_OUT_ELASTIC' },
  { ts: 0.25, p: [0, 2, 0] },
  { ts: 0.5, p: [2, 4, 0] },
  { ts: 0.5, r: [0, 90, 180] },
  { ts: 0.75, p: [2, 0, 0] },
  { ts: 0.5, s: [2.5, 3, 2.0] },
  { ts: 0.8, r: [0, 90, 0] },
  { ts: 1, p: [0, 0, 0] },
  { ts: 1, s: [1, 1, 1] },
];
let spr: HNode = getPrefab({ id: 'sphere_01', p: [0, 4, 15], r: [0, 0, 10] });
spr = getTween(spr, kf, { loopBehaviour: 'RESTART', duration: 4 });
addTo(world, spr);
 * ```
 */
export const getTween = (target, kfs, options) => {
    const { duration = 2, progress = 0, speedMultiplier = 1, loopBehaviour = 'REVERSE', autoWrap = true, p = undefined, r = undefined, s = undefined, } = options || {};
    const keyframes = [];
    const getChanel = (key) => {
        const count = 0;
        if (key === 'p')
            return 0 + count;
        if (key === 'r')
            return 1 + count;
        if (key === 's')
            return 2 + count;
    };
    const fixStartAndEnd = (targetTimeline, key) => {
        // Sort it
        _u.sortByKey(targetTimeline, 'ts');
        // Add a keyFrame at timestamp 0 if none
        const fistKf = _u.filterArray(targetTimeline, 'ts', 0);
        if (fistKf.length === 0) {
            const toPush = { ts: 0 };
            toPush[key] = key !== 's' ? [0, 0, 0] : [1, 1, 1];
            targetTimeline.push(toPush);
        }
        // Add a keyFrame at timestamp 1 if none
        const lastKf = _u.filterArray(targetTimeline, 'ts', 1);
        const latestKf = targetTimeline[targetTimeline.length - 1];
        if (lastKf.length === 0) {
            // Clone latest defined keyframe
            const toPush = _u.clone(latestKf);
            toPush.ts = 1;
            targetTimeline.push(toPush);
        }
        _u.sortByKey(targetTimeline, 'ts');
        for (let index = 0; index < targetTimeline.length; index++) {
            const kfData = targetTimeline[index];
            const transform = {};
            if (key === 'p')
                transform.pos = kfData[key];
            if (key === 'r')
                transform.rot = kfData[key];
            if (key === 's')
                transform.scale = kfData[key];
            const kfObj = {
                keyframe: {
                    easing: kfData.easing || 'EASE_IN_OUT_QUAD',
                    timeline: getChanel(key),
                    timestamp: kfData.ts * duration,
                },
                transform,
                keyframeTransformMask: {
                    positionX: key === 'p' ? true : false,
                    positionY: key === 'p' ? true : false,
                    positionZ: key === 'p' ? true : false,
                    rotation: key === 'r' ? true : false,
                    scaleX: key === 's' ? true : false,
                    scaleY: key === 's' ? true : false,
                    scaleZ: key === 's' ? true : false,
                },
            };
            keyframes.push(kfObj);
        }
    };
    const timelineP = [];
    const timelineR = [];
    const timelineS = [];
    if (kfs) {
        for (let index = 0; index < kfs.length; index++) {
            const kf = kfs[index];
            if (kf.p)
                timelineP.push({ ts: kf.ts, p: kf.p, easing: kf.easing || 'EASE_IN_OUT_QUAD' });
            if (kf.r)
                timelineR.push({ ts: kf.ts, r: kf.r, easing: kf.easing || 'EASE_IN_OUT_QUAD' });
            if (kf.s)
                timelineS.push({ ts: kf.ts, s: kf.s, easing: kf.easing || 'EASE_IN_OUT_QUAD' });
        }
        fixStartAndEnd(timelineP, 'p');
        fixStartAndEnd(timelineR, 'r');
        fixStartAndEnd(timelineS, 's');
    }
    let wrapper = getWrapper(target, { p, r, s, autoWrap });
    target.keyframeAnimated = {
        speedMultiplier,
        loopBehaviour,
        startTimestamp: progress * duration,
    };
    target.children?.push(...keyframes);
    return wrapper;
};
//# sourceMappingURL=getTween.js.map