"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertShapeToBez3 = convertShapeToBez3;
exports.convertContourToBez3 = convertContourToBez3;
const derivable_1 = require("../../derivable");
const fn_1 = require("../../fn");
const point_1 = require("../../point/point");
const slice_arc_1 = require("../shared/slice-arc");
function convertShapeToBez3(shape, err) {
    const ans = [];
    for (const contour of shape)
        ans.push(convertContourToBez3(contour, err));
    return ans;
}
function convertContourToBez3(contour, err) {
    const sink = new ContourConversionSink();
    for (let j = 0; j < contour.length; j++) {
        convertArcToBez3(contour[j], err, sink);
    }
    sink.close();
    return sink.result;
}
class ContourConversionSink {
    constructor() {
        this.segments = [];
    }
    get result() {
        return this.segments;
    }
    add(result) {
        if (this.segments.length > 0) {
            this.connectEndsIfNecessary(this.segments[this.segments.length - 1], result);
        }
        this.segments.push(result);
    }
    close() {
        if (this.segments.length > 0) {
            this.connectEndsIfNecessary(this.segments[this.segments.length - 1], this.segments[0]);
        }
    }
    connectEndsIfNecessary(prev, next) {
        if (!point_1.Point2.areClose(prev.d, next.a, 1e-6)) {
            this.segments.push(slice_arc_1.Bez3Slice.fromStraightSegment(new derivable_1.Arcs.StraightSegment(prev.d, next.a)));
        }
    }
}
function convertArcToBez3(arc, err, sink) {
    if (arc instanceof derivable_1.Arcs.Bez3) {
        sink.add(new slice_arc_1.Bez3Slice(arc.a, arc.b, arc.c, arc.d));
    }
    else if (arc instanceof derivable_1.Arcs.CombinedArc) {
        for (const seg of arc.segments) {
            convertArcToBez3(seg, err, sink);
        }
    }
    else {
        convertArcToBez3Impl(arc, err, sink, 0, 1, 0, 8);
    }
}
const PROBE_STOPS = 4;
function convertArcToBez3Impl(arc, err, sink, t0, t1, depth, maxDepth) {
    const testArc = slice_arc_1.Bez3Slice.fromArcSlice(arc, t0, t1);
    if (depth >= maxDepth) {
        sink.add(testArc);
        return;
    }
    let needsSubdivide = false;
    for (let t = 1; t < PROBE_STOPS; t++) {
        const zTest = testArc.eval(t / PROBE_STOPS);
        const zArc = arc.eval((0, fn_1.mix)(t0, t1, t / PROBE_STOPS));
        if (!point_1.Point2.areClose(zTest, zArc, err)) {
            needsSubdivide = true;
            break;
        }
    }
    if (!needsSubdivide) {
        sink.add(testArc);
    }
    else {
        const tMid = (0, fn_1.mix)(t0, t1, 1 / 2);
        convertArcToBez3Impl(arc, err, sink, t0, tMid, depth + 1, maxDepth);
        convertArcToBez3Impl(arc, err, sink, tMid, t1, depth + 1, maxDepth);
    }
}
