"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Animator = void 0;
const sdk_1 = require("@cntrl-site/sdk");
const color_1 = require("@cntrl-site/color");
const binSearchInsertAt_1 = require("../binSearchInsertAt");
const rangeMap_1 = require("../rangeMap");
const compare = (lhs, rhs) => lhs.position - rhs.position;
const insertBin = (0, binSearchInsertAt_1.createInsert)(binSearchInsertAt_1.binSearchInsertAt, compare);
class Animator {
    static pushKeyframeToMap(keyframe, map) {
        insertBin(map[keyframe.type], keyframe);
    }
    constructor(keyframes) {
        this.keyframes = keyframes;
        this.keyframesMap = createKeyframesMap();
        this.fillKeyframesMap();
    }
    getDimensions(values, pos) {
        const keyframes = this.keyframesMap[sdk_1.KeyframeType.Dimensions];
        if (!keyframes || !keyframes.length)
            return values;
        if (keyframes.length === 1) {
            const [keyframe] = keyframes;
            return {
                width: keyframe.value.width,
                height: keyframe.value.height
            };
        }
        const { start, end } = this.getStartEnd(pos, keyframes);
        return {
            width: (0, rangeMap_1.rangeMap)(pos, start.position, end.position, start.value.width, end.value.width, true),
            height: (0, rangeMap_1.rangeMap)(pos, start.position, end.position, start.value.height, end.value.height, true)
        };
    }
    getPositions(values, pos) {
        const keyframes = this.keyframesMap[sdk_1.KeyframeType.Position];
        if (!keyframes || !keyframes.length)
            return values;
        if (keyframes.length === 1) {
            const [keyframe] = keyframes;
            return {
                left: keyframe.value.left,
                top: keyframe.value.top
            };
        }
        const { start, end } = this.getStartEnd(pos, keyframes);
        return {
            left: (0, rangeMap_1.rangeMap)(pos, start.position, end.position, start.value.left, end.value.left, true),
            top: (0, rangeMap_1.rangeMap)(pos, start.position, end.position, start.value.top, end.value.top, true)
        };
    }
    getColor(values, pos) {
        const keyframes = this.keyframesMap[sdk_1.KeyframeType.Color];
        if (!keyframes || !keyframes.length)
            return values;
        if (keyframes.length === 1) {
            const [keyframe] = keyframes;
            return {
                color: keyframe.value.color
            };
        }
        const { start, end } = this.getStartEnd(pos, keyframes);
        return {
            color: this.getRangeColor(start, end, pos)
        };
    }
    getBorderColor(values, pos) {
        const keyframes = this.keyframesMap[sdk_1.KeyframeType.BorderColor];
        if (!keyframes || !keyframes.length)
            return values;
        if (keyframes.length === 1) {
            const [keyframe] = keyframes;
            return {
                color: keyframe.value.color
            };
        }
        const { start, end } = this.getStartEnd(pos, keyframes);
        return {
            color: this.getRangeColor(start, end, pos)
        };
    }
    getRadius(values, pos) {
        const keyframes = this.keyframesMap[sdk_1.KeyframeType.BorderRadius];
        if (!keyframes || !keyframes.length)
            return values;
        if (keyframes.length === 1) {
            const [keyframe] = keyframes;
            return {
                radius: keyframe.value.radius
            };
        }
        const { start, end } = this.getStartEnd(pos, keyframes);
        return {
            radius: (0, rangeMap_1.rangeMap)(pos, start.position, end.position, start.value.radius, end.value.radius, true)
        };
    }
    getBorderWidth(values, pos) {
        const keyframes = this.keyframesMap[sdk_1.KeyframeType.BorderWidth];
        if (!keyframes || !keyframes.length)
            return values;
        if (keyframes.length === 1) {
            const [keyframe] = keyframes;
            return {
                borderWidth: keyframe.value.borderWidth
            };
        }
        const { start, end } = this.getStartEnd(pos, keyframes);
        return {
            borderWidth: (0, rangeMap_1.rangeMap)(pos, start.position, end.position, start.value.borderWidth, end.value.borderWidth, true)
        };
    }
    getRotation(values, pos) {
        const keyframes = this.keyframesMap[sdk_1.KeyframeType.Rotation];
        if (!keyframes || !keyframes.length)
            return values;
        if (keyframes.length === 1) {
            const [keyframe] = keyframes;
            return {
                angle: keyframe.value.angle
            };
        }
        const { start, end } = this.getStartEnd(pos, keyframes);
        return {
            angle: (0, rangeMap_1.rangeMap)(pos, start.position, end.position, start.value.angle, end.value.angle, true)
        };
    }
    getOpacity(values, pos) {
        const keyframes = this.keyframesMap[sdk_1.KeyframeType.Opacity];
        if (!keyframes || !keyframes.length)
            return values;
        if (keyframes.length === 1) {
            const [keyframe] = keyframes;
            return {
                opacity: keyframe.value.opacity
            };
        }
        const { start, end } = this.getStartEnd(pos, keyframes);
        return {
            opacity: (0, rangeMap_1.rangeMap)(pos, start.position, end.position, start.value.opacity, end.value.opacity, true)
        };
    }
    getScale(values, pos) {
        const keyframes = this.keyframesMap[sdk_1.KeyframeType.Scale];
        if (!keyframes || !keyframes.length)
            return values;
        if (keyframes.length === 1) {
            const [keyframe] = keyframes;
            return {
                scale: keyframe.value.scale
            };
        }
        const { start, end } = this.getStartEnd(pos, keyframes);
        return {
            scale: (0, rangeMap_1.rangeMap)(pos, start.position, end.position, start.value.scale, end.value.scale, true)
        };
    }
    getBlur(values, pos) {
        const keyframes = this.keyframesMap[sdk_1.KeyframeType.Blur];
        if (!keyframes || !keyframes.length)
            return values;
        if (keyframes.length === 1) {
            const [keyframe] = keyframes;
            return {
                blur: keyframe.value.blur
            };
        }
        const { start, end } = this.getStartEnd(pos, keyframes);
        return {
            blur: (0, rangeMap_1.rangeMap)(pos, start.position, end.position, start.value.blur, end.value.blur, true)
        };
    }
    getBackdropBlur(values, pos) {
        const keyframes = this.keyframesMap[sdk_1.KeyframeType.BackdropBlur];
        if (!keyframes || !keyframes.length)
            return values;
        if (keyframes.length === 1) {
            const [keyframe] = keyframes;
            return {
                backdropBlur: keyframe.value.backdropBlur
            };
        }
        const { start, end } = this.getStartEnd(pos, keyframes);
        return {
            backdropBlur: (0, rangeMap_1.rangeMap)(pos, start.position, end.position, start.value.backdropBlur, end.value.backdropBlur, true)
        };
    }
    getTextColor(values, pos) {
        const keyframes = this.keyframesMap[sdk_1.KeyframeType.TextColor];
        if (!keyframes || !keyframes.length)
            return values;
        if (keyframes.length === 1) {
            const [keyframe] = keyframes;
            return {
                color: keyframe.value.color
            };
        }
        const { start, end } = this.getStartEnd(pos, keyframes);
        return {
            color: this.getRangeColor(start, end, pos)
        };
    }
    getLetterSpacing(values, pos) {
        const keyframes = this.keyframesMap[sdk_1.KeyframeType.LetterSpacing];
        if (!keyframes || !keyframes.length)
            return values;
        if (keyframes.length === 1) {
            const [keyframe] = keyframes;
            return {
                letterSpacing: keyframe.value.letterSpacing
            };
        }
        const { start, end } = this.getStartEnd(pos, keyframes);
        return {
            letterSpacing: (0, rangeMap_1.rangeMap)(pos, start.position, end.position, start.value.letterSpacing, end.value.letterSpacing, true)
        };
    }
    getWordSpacing(values, pos) {
        const keyframes = this.keyframesMap[sdk_1.KeyframeType.WordSpacing];
        if (!keyframes || !keyframes.length)
            return values;
        if (keyframes.length === 1) {
            const [keyframe] = keyframes;
            return {
                wordSpacing: keyframe.value.wordSpacing
            };
        }
        const { start, end } = this.getStartEnd(pos, keyframes);
        return {
            wordSpacing: (0, rangeMap_1.rangeMap)(pos, start.position, end.position, start.value.wordSpacing, end.value.wordSpacing, true)
        };
    }
    getStartEnd(position, keyframes) {
        const index = (0, binSearchInsertAt_1.binSearchInsertAt)(keyframes, { position }, compare);
        const end = index === keyframes.length ? index - 1 : index;
        const start = end === 0 ? end : end - 1;
        return { start: keyframes[start], end: keyframes[end] };
    }
    fillKeyframesMap() {
        this.keyframesMap = createKeyframesMap();
        for (const keyframe of this.keyframes) {
            Animator.pushKeyframeToMap(keyframe, this.keyframesMap);
        }
    }
    getRangeColor(start, end, position) {
        const rangeAmount = (0, rangeMap_1.rangeMap)(position, start.position, end.position, 0, 1, true);
        const startColor = color_1.CntrlColor.parse(start.value.color);
        const endColor = color_1.CntrlColor.parse(end.value.color);
        const mixedColor = startColor.mix(endColor, rangeAmount);
        return mixedColor.fmt('oklch');
    }
}
exports.Animator = Animator;
function createKeyframesMap() {
    return {
        [sdk_1.KeyframeType.Dimensions]: [],
        [sdk_1.KeyframeType.Position]: [],
        [sdk_1.KeyframeType.BorderWidth]: [],
        [sdk_1.KeyframeType.BorderRadius]: [],
        [sdk_1.KeyframeType.Color]: [],
        [sdk_1.KeyframeType.Rotation]: [],
        [sdk_1.KeyframeType.BorderColor]: [],
        [sdk_1.KeyframeType.Opacity]: [],
        [sdk_1.KeyframeType.Scale]: [],
        [sdk_1.KeyframeType.Blur]: [],
        [sdk_1.KeyframeType.BackdropBlur]: [],
        [sdk_1.KeyframeType.LetterSpacing]: [],
        [sdk_1.KeyframeType.WordSpacing]: [],
        [sdk_1.KeyframeType.TextColor]: []
    };
}
