// DXF G196 teaching extension: command generation; O9196 supplies motion.
// Copy this function above processDrillKey in your customized postprocessor.
// Install package/env/slib-dxf-custom.nc before running generated G196.
// Existing parts[1..10] are preserved; new parts[11..13] are D, I and Q.
function buildCustomBore(key, outerArray) {
    var parts = key.split(":");
    if (parts.length < 14) throw new Error("G196: missing D/I/Q settings");
    function numberAt(index, name) {
        if (!parts[index] || !parts[index].trim()) {
            throw new Error("G196: missing " + name);
        }
        var value = Number(parts[index]);
        if (!isFinite(value)) throw new Error("G196: invalid " + name);
        return value;
    }
    var z = numberAt(5, "Z"), r = numberAt(6, "R");
    var f = numberAt(10, "F"), d = numberAt(11, "D");
    var toolDiameter = numberAt(12, "I"), q = numberAt(13, "Q");
    if (!(d > toolDiameter && toolDiameter > 0 && q > 0 && f > 0 && r > 0 && z < 0)) {
        throw new Error("G196: require D>I>0, Q>0, F>0, R>0 and Z<0");
    }
    var result = "";
    for (var i = 0; i < outerArray.length; i++) {
        for (var j = 0; j < outerArray[i].length; j++) {
            var point = outerArray[i][j];
            if (typeof point.x !== "number" || typeof point.y !== "number" ||
                    !isFinite(point.x) || !isFinite(point.y)) {
                throw new Error("G196: invalid hole center");
            }
            result += "G80\nG90G17G21G94G40G15\n";
            result += "G196X" + point.x.toFixed(3) + "Y" + point.y.toFixed(3) +
                      "Z" + z.toFixed(3) + "R" + r.toFixed(3) +
                      "D" + d.toFixed(3) + "I" + toolDiameter.toFixed(3) +
                      "Q" + q.toFixed(3) + "F" + f.toFixed(3) + "\nG80\n";
        }
    }
    return result;
}
