// Normalize path to include only M, L, C, and Z commands
export function normalize(segments) {
    const out = [];
    let lastType = '';
    let cx = 0, cy = 0;
    let subx = 0, suby = 0;
    let lcx = 0, lcy = 0;
    for (const { key, data } of segments) {
        switch (key) {
            case 'M':
                out.push({ key: 'M', data: [...data] });
                [cx, cy] = data;
                [subx, suby] = data;
                break;
            case 'C':
                out.push({ key: 'C', data: [...data] });
                cx = data[4];
                cy = data[5];
                lcx = data[2];
                lcy = data[3];
                break;
            case 'L':
                out.push({ key: 'L', data: [...data] });
                [cx, cy] = data;
                break;
            case 'H':
                cx = data[0];
                out.push({ key: 'L', data: [cx, cy] });
                break;
            case 'V':
                cy = data[0];
                out.push({ key: 'L', data: [cx, cy] });
                break;
            case 'S': {
                let cx1 = 0, cy1 = 0;
                if (lastType === 'C' || lastType === 'S') {
                    cx1 = cx + (cx - lcx);
                    cy1 = cy + (cy - lcy);
                }
                else {
                    cx1 = cx;
                    cy1 = cy;
                }
                out.push({ key: 'C', data: [cx1, cy1, ...data] });
                lcx = data[0];
                lcy = data[1];
                cx = data[2];
                cy = data[3];
                break;
            }
            case 'T': {
                const [x, y] = data;
                let x1 = 0, y1 = 0;
                if (lastType === 'Q' || lastType === 'T') {
                    x1 = cx + (cx - lcx);
                    y1 = cy + (cy - lcy);
                }
                else {
                    x1 = cx;
                    y1 = cy;
                }
                const cx1 = cx + 2 * (x1 - cx) / 3;
                const cy1 = cy + 2 * (y1 - cy) / 3;
                const cx2 = x + 2 * (x1 - x) / 3;
                const cy2 = y + 2 * (y1 - y) / 3;
                out.push({ key: 'C', data: [cx1, cy1, cx2, cy2, x, y] });
                lcx = x1;
                lcy = y1;
                cx = x;
                cy = y;
                break;
            }
            case 'Q': {
                const [x1, y1, x, y] = data;
                const cx1 = cx + 2 * (x1 - cx) / 3;
                const cy1 = cy + 2 * (y1 - cy) / 3;
                const cx2 = x + 2 * (x1 - x) / 3;
                const cy2 = y + 2 * (y1 - y) / 3;
                out.push({ key: 'C', data: [cx1, cy1, cx2, cy2, x, y] });
                lcx = x1;
                lcy = y1;
                cx = x;
                cy = y;
                break;
            }
            case 'A': {
                const r1 = Math.abs(data[0]);
                const r2 = Math.abs(data[1]);
                const angle = data[2];
                const largeArcFlag = data[3];
                const sweepFlag = data[4];
                const x = data[5];
                const y = data[6];
                if (r1 === 0 || r2 === 0) {
                    out.push({ key: 'C', data: [cx, cy, x, y, x, y] });
                    cx = x;
                    cy = y;
                }
                else {
                    if (cx !== x || cy !== y) {
                        const curves = arcToCubicCurves(cx, cy, x, y, r1, r2, angle, largeArcFlag, sweepFlag);
                        curves.forEach(function (curve) {
                            out.push({ key: 'C', data: curve });
                        });
                        cx = x;
                        cy = y;
                    }
                }
                break;
            }
            case 'Z':
                out.push({ key: 'Z', data: [] });
                cx = subx;
                cy = suby;
                break;
        }
        lastType = key;
    }
    return out;
}
function degToRad(degrees) {
    return (Math.PI * degrees) / 180;
}
function rotate(x, y, angleRad) {
    const X = x * Math.cos(angleRad) - y * Math.sin(angleRad);
    const Y = x * Math.sin(angleRad) + y * Math.cos(angleRad);
    return [X, Y];
}
function arcToCubicCurves(x1, y1, x2, y2, r1, r2, angle, largeArcFlag, sweepFlag, recursive) {
    const angleRad = degToRad(angle);
    let params = [];
    let f1 = 0, f2 = 0, cx = 0, cy = 0;
    if (recursive) {
        [f1, f2, cx, cy] = recursive;
    }
    else {
        [x1, y1] = rotate(x1, y1, -angleRad);
        [x2, y2] = rotate(x2, y2, -angleRad);
        const x = (x1 - x2) / 2;
        const y = (y1 - y2) / 2;
        let h = (x * x) / (r1 * r1) + (y * y) / (r2 * r2);
        if (h > 1) {
            h = Math.sqrt(h);
            r1 = h * r1;
            r2 = h * r2;
        }
        const sign = (largeArcFlag === sweepFlag) ? -1 : 1;
        const r1Pow = r1 * r1;
        const r2Pow = r2 * r2;
        const left = r1Pow * r2Pow - r1Pow * y * y - r2Pow * x * x;
        const right = r1Pow * y * y + r2Pow * x * x;
        const k = sign * Math.sqrt(Math.abs(left / right));
        cx = k * r1 * y / r2 + (x1 + x2) / 2;
        cy = k * -r2 * x / r1 + (y1 + y2) / 2;
        f1 = Math.asin(parseFloat(((y1 - cy) / r2).toFixed(9)));
        f2 = Math.asin(parseFloat(((y2 - cy) / r2).toFixed(9)));
        if (x1 < cx) {
            f1 = Math.PI - f1;
        }
        if (x2 < cx) {
            f2 = Math.PI - f2;
        }
        if (f1 < 0) {
            f1 = Math.PI * 2 + f1;
        }
        if (f2 < 0) {
            f2 = Math.PI * 2 + f2;
        }
        if (sweepFlag && f1 > f2) {
            f1 = f1 - Math.PI * 2;
        }
        if (!sweepFlag && f2 > f1) {
            f2 = f2 - Math.PI * 2;
        }
    }
    let df = f2 - f1;
    if (Math.abs(df) > (Math.PI * 120 / 180)) {
        const f2old = f2;
        const x2old = x2;
        const y2old = y2;
        if (sweepFlag && f2 > f1) {
            f2 = f1 + (Math.PI * 120 / 180) * (1);
        }
        else {
            f2 = f1 + (Math.PI * 120 / 180) * (-1);
        }
        x2 = cx + r1 * Math.cos(f2);
        y2 = cy + r2 * Math.sin(f2);
        params = arcToCubicCurves(x2, y2, x2old, y2old, r1, r2, angle, 0, sweepFlag, [f2, f2old, cx, cy]);
    }
    df = f2 - f1;
    const c1 = Math.cos(f1);
    const s1 = Math.sin(f1);
    const c2 = Math.cos(f2);
    const s2 = Math.sin(f2);
    const t = Math.tan(df / 4);
    const hx = 4 / 3 * r1 * t;
    const hy = 4 / 3 * r2 * t;
    const m1 = [x1, y1];
    const m2 = [x1 + hx * s1, y1 - hy * c1];
    const m3 = [x2 + hx * s2, y2 - hy * c2];
    const m4 = [x2, y2];
    m2[0] = 2 * m1[0] - m2[0];
    m2[1] = 2 * m1[1] - m2[1];
    if (recursive) {
        return [m2, m3, m4].concat(params);
    }
    else {
        params = [m2, m3, m4].concat(params);
        const curves = [];
        for (let i = 0; i < params.length; i += 3) {
            const r1 = rotate(params[i][0], params[i][1], angleRad);
            const r2 = rotate(params[i + 1][0], params[i + 1][1], angleRad);
            const r3 = rotate(params[i + 2][0], params[i + 2][1], angleRad);
            curves.push([r1[0], r1[1], r2[0], r2[1], r3[0], r3[1]]);
        }
        return curves;
    }
}
