"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PolyFillType = exports.ClipType = exports.removeOverlap = exports.combine = exports.combineStack = void 0;
const ClipperLib = require("clipper-lib");
const slice_arc_1 = require("../shared/slice-arc");
const intersections_1 = require("./intersections");
const rebuild_1 = require("./rebuild");
const to_poly_1 = require("./to-poly");
function combineStack(ops, resolution = 256) {
    return combineStackImpl([...ops], resolution);
}
exports.combineStack = combineStack;
function combine(op, s1, s2, rule1, rule2, RESOLUTION = 256) {
    return combineStackImpl([
        { type: "operand", shape: s1, fillType: rule1 },
        { type: "operand", shape: s2, fillType: rule2 },
        { type: "operator", operator: op }
    ], RESOLUTION);
}
exports.combine = combine;
function combineStackImpl(ops, resolution = 256) {
    for (let i = 0; i < ops.length; i++) {
        const op = ops[i];
        if (op.type !== "operand")
            continue;
        const rectifiedArcs = ToBez3Slices(op.shape);
        ops[i] = {
            type: "operand_rectified",
            fillType: op.fillType,
            shape_rectified: rectifiedArcs,
            intersectionTs: (0, intersections_1.findSelfIntersections)(rectifiedArcs)
        };
    }
    for (let i = 0; i < ops.length; i++) {
        const opI = ops[i];
        if (opI.type !== "operand_rectified")
            continue;
        for (let j = i; j < ops.length; j++) {
            const opJ = ops[j];
            if (opJ.type !== "operand_rectified")
                continue;
            (0, intersections_1.findCrossIntersections)(opI.shape_rectified, opJ.shape_rectified, opI.intersectionTs, opJ.intersectionTs, i === j);
        }
    }
    const segHash = new to_poly_1.SegHashStore();
    for (let i = 0; i < ops.length; i++) {
        const op = ops[i];
        if (op.type !== "operand_rectified")
            continue;
        ops[i] = {
            type: "operand_poly",
            shape_poly: (0, to_poly_1.toPoly)(op.shape_rectified, i + 1, op.intersectionTs, segHash, resolution),
            fillType: op.fillType
        };
    }
    let stack = [];
    const cpr = new ClipperLib.Clipper(ClipperLib.Clipper.ioReverseSolution | ClipperLib.Clipper.ioStrictlySimple);
    for (const op of ops) {
        if (op.type === "operand_poly") {
            stack.push({ operand: op.shape_poly, fillType: op.fillType });
        }
        else if (op.type === "operator") {
            const x2 = stack.pop();
            const x1 = stack.pop();
            cpr.Clear();
            cpr.AddPaths(x1.operand, ClipperLib.PolyType.ptSubject, ClipperLib.EndType.etClosedPolygon);
            cpr.AddPaths(x2.operand, ClipperLib.PolyType.ptClip, ClipperLib.EndType.etClosedPolygon);
            const solutionPaths = ClipperLib.Paths();
            cpr.Execute(op.operator || 0, solutionPaths, x1.fillType, x2.fillType);
            stack.push({ operand: solutionPaths, fillType: ClipperLib.PolyFillType.pftNonZero });
        }
    }
    const result = stack.pop();
    return (0, rebuild_1.rebuildShape)(result.operand, segHash, resolution);
}
function removeOverlapImpl(s1, rule, resolution = 256) {
    if (!s1.length)
        return s1;
    const i1 = (0, intersections_1.findSelfIntersections)(s1);
    (0, intersections_1.findCrossIntersections)(s1, s1, i1, i1, true);
    const segHash = new to_poly_1.SegHashStore();
    const p1 = (0, to_poly_1.toPoly)(s1, 1, i1, segHash, resolution);
    const solution_paths = ClipperLib.Clipper.SimplifyPolygons(p1, rule);
    for (const path of solution_paths)
        path.reverse();
    return (0, rebuild_1.rebuildShape)(solution_paths, segHash, resolution);
}
function ToBez3Slices(shape) {
    let result = [];
    for (let contour of shape) {
        const resultContour = [];
        for (let j = 0; j < contour.length; j++) {
            resultContour.push(new slice_arc_1.Bez3Slice(contour[j].a, contour[j].b, contour[j].c, contour[j].d));
        }
        result.push(resultContour);
    }
    return result;
}
function removeOverlap(s1, rule, RESOLUTION = 256) {
    return removeOverlapImpl(ToBez3Slices(s1), rule, RESOLUTION);
}
exports.removeOverlap = removeOverlap;
var clipper_lib_1 = require("clipper-lib");
Object.defineProperty(exports, "ClipType", { enumerable: true, get: function () { return clipper_lib_1.ClipType; } });
Object.defineProperty(exports, "PolyFillType", { enumerable: true, get: function () { return clipper_lib_1.PolyFillType; } });
