var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
    return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (g && (g = 0, op[0] && (_ = 0)), _) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var __read = (this && this.__read) || function (o, n) {
    var m = typeof Symbol === "function" && o[Symbol.iterator];
    if (!m) return o;
    var i = m.call(o), r, ar = [], e;
    try {
        while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
    }
    catch (error) { e = { error: error }; }
    finally {
        try {
            if (r && !r.done && (m = i["return"])) m.call(i);
        }
        finally { if (e) throw e.error; }
    }
    return ar;
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
var __values = (this && this.__values) || function(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
import { AcDbArc, AcDbCircle, AcDbHatch, AcDbHatchPatternType, AcDbHatchStyle, AcDbLine, AcDbPolyline, AcGeCircArc2d, AcGeLine2d, AcGeLoop2d } from '@mlightcad/data-model';
import { AcApDocManager } from '../app';
import { AcEdCommand, AcEdOpenMode, AcEdPromptDoubleOptions, AcEdPromptEntityOptions, AcEdPromptKeywordOptions, AcEdPromptPointOptions, AcEdPromptSelectionOptions, AcEdPromptStatus, AcEdPromptStringOptions } from '../editor';
import { AcApI18n } from '../i18n';
/**
 * Command-line HATCH command (no dialog), inspired by AutoCAD flow.
 *
 * Current scope:
 * - Build hatch boundaries from selected objects.
 * - Support command-line option branches (pattern/scale/angle/style/associative).
 * - No island-detection refinement beyond loop construction.
 */
var AcApHatchCmd = /** @class */ (function (_super) {
    __extends(AcApHatchCmd, _super);
    /**
     * Creates one HATCH command instance and marks it as write-mode only.
     */
    function AcApHatchCmd() {
        var _this = _super.call(this) || this;
        _this.mode = AcEdOpenMode.Write;
        return _this;
    }
    /**
     * Normalizes pattern name input.
     *
     * @param value Raw user-entered pattern name.
     * @returns Trimmed name, or `ANSI31` when input is empty.
     */
    AcApHatchCmd.prototype.normalizePatternName = function (value) {
        var name = value.trim();
        return name.length > 0 ? name : 'ANSI31';
    };
    /**
     * Converts hatch style enum to command keyword string.
     *
     * @param style Hatch style enum value.
     * @returns Command keyword name used by keyword prompts.
     */
    AcApHatchCmd.prototype.styleToKeyword = function (style) {
        switch (style) {
            case AcDbHatchStyle.Outer:
                return 'Outer';
            case AcDbHatchStyle.Ignore:
                return 'Ignore';
            case AcDbHatchStyle.Normal:
            default:
                return 'Normal';
        }
    };
    /**
     * Converts command keyword string to hatch style enum.
     *
     * @param keyword Keyword returned by prompt API.
     * @returns Matching hatch style enum, defaulting to `Normal`.
     */
    AcApHatchCmd.prototype.keywordToStyle = function (keyword) {
        switch (keyword) {
            case 'Outer':
                return AcDbHatchStyle.Outer;
            case 'Ignore':
                return AcDbHatchStyle.Ignore;
            case 'Normal':
            default:
                return AcDbHatchStyle.Normal;
        }
    };
    /**
     * Converts a closed polyline entity into a boundary-edge sequence.
     *
     * The function keeps arc segments by reading per-vertex bulge values.
     * If runtime bulge data is unavailable, vertices fall back to straight edges.
     *
     * @param entity Input polyline entity.
     * @returns Ordered boundary edges or empty array if not hatchable.
     */
    AcApHatchCmd.prototype.buildEdgesFromPolyline = function (entity) {
        var _a, _b;
        if (!entity.closed || entity.numberOfVertices < 2)
            return [];
        // Runtime polyline geometry keeps bulge data; typed API does not expose it.
        var runtimeVertices = (_a = entity._geo) === null || _a === void 0 ? void 0 : _a.vertices;
        var vertices = runtimeVertices && runtimeVertices.length > 1
            ? runtimeVertices.map(function (v) { return ({ x: v.x, y: v.y, bulge: v.bulge }); })
            : Array.from({ length: entity.numberOfVertices }, function (_, i) {
                var p = entity.getPoint2dAt(i);
                return { x: p.x, y: p.y, bulge: 0 };
            });
        if (vertices.length < 2)
            return [];
        var edges = [];
        for (var i = 0; i < vertices.length; i++) {
            var start = vertices[i];
            var end = vertices[(i + 1) % vertices.length];
            var bulge = (_b = start.bulge) !== null && _b !== void 0 ? _b : 0;
            if (Math.abs(bulge) > 1e-12) {
                edges.push(new AcGeCircArc2d(start, end, bulge));
            }
            else {
                edges.push(new AcGeLine2d(start, end));
            }
        }
        return edges;
    };
    /**
     * Converts a supported boundary entity into one or more boundary edges.
     *
     * Supported entities:
     * - `AcDbPolyline` (closed)
     * - `AcDbCircle`
     * - `AcDbArc` (closed only)
     * - `AcDbLine`
     *
     * @param entity Input entity from model space.
     * @returns Edge list consumable by loop builder.
     */
    AcApHatchCmd.prototype.buildEdgesFromEntity = function (entity) {
        if (entity instanceof AcDbPolyline) {
            return this.buildEdgesFromPolyline(entity);
        }
        if (entity instanceof AcDbCircle) {
            var center = entity.center;
            return [
                new AcGeCircArc2d({ x: center.x, y: center.y }, entity.radius, 0, Math.PI * 2, false)
            ];
        }
        if (entity instanceof AcDbArc) {
            if (!entity.closed)
                return [];
            var center = entity.center;
            return [
                new AcGeCircArc2d({ x: center.x, y: center.y }, entity.radius, entity.startAngle, entity.endAngle, false)
            ];
        }
        if (entity instanceof AcDbLine) {
            return [new AcGeLine2d(entity.startPoint, entity.endPoint)];
        }
        return [];
    };
    /**
     * Builds closed loops from explicit object ids.
     *
     * @param context Active command context.
     * @param ids Object ids selected by the user.
     * @returns Closed loops ready for hatch creation.
     */
    AcApHatchCmd.prototype.collectLoopsFromIds = function (context, ids) {
        var _this = this;
        var modelSpace = context.doc.database.tables.blockTable.modelSpace;
        var edges = [];
        ids.forEach(function (id) {
            var entity = modelSpace.getIdAt(id);
            if (!entity)
                return;
            edges.push.apply(edges, __spreadArray([], __read(_this.buildEdgesFromEntity(entity)), false));
        });
        return this.buildLoopsFromEdges(edges);
    };
    /**
     * Scans model space and builds closed loops from all supported boundaries.
     *
     * This is used by pick-points mode so a seed point can be resolved against
     * all potential loops in the drawing.
     *
     * @param context Active command context.
     * @returns Closed loops derived from all hatchable entities.
     */
    AcApHatchCmd.prototype.collectLoopsFromAllBoundaries = function (context) {
        var e_1, _a;
        var modelSpace = context.doc.database.tables.blockTable.modelSpace;
        var edges = [];
        try {
            for (var _b = __values(modelSpace.newIterator()), _c = _b.next(); !_c.done; _c = _b.next()) {
                var entity = _c.value;
                edges.push.apply(edges, __spreadArray([], __read(this.buildEdgesFromEntity(entity)), false));
            }
        }
        catch (e_1_1) { e_1 = { error: e_1_1 }; }
        finally {
            try {
                if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
            }
            finally { if (e_1) throw e_1.error; }
        }
        return this.buildLoopsFromEdges(edges);
    };
    /**
     * Builds best-effort closed loops from boundary edges.
     *
     * The loop solver is retried with increasing tolerance values and the best
     * (largest) closed-loop result set is returned.
     *
     * @param edges Input boundary edge set.
     * @returns Closed loops produced by the best tolerance attempt.
     */
    AcApHatchCmd.prototype.buildLoopsFromEdges = function (edges) {
        var e_2, _a;
        if (edges.length === 0)
            return [];
        // Try from strict to loose tolerance, and keep the best closed-loop result.
        var tolerances = [1e-6, 1e-5, 1e-4, 1e-3];
        var best = [];
        try {
            for (var tolerances_1 = __values(tolerances), tolerances_1_1 = tolerances_1.next(); !tolerances_1_1.done; tolerances_1_1 = tolerances_1.next()) {
                var tolerance = tolerances_1_1.value;
                var loops = AcGeLoop2d.buildFromEdges(edges, tolerance).filter(function (loop) { return loop.closed && loop.numberOfEdges > 0; });
                if (loops.length > best.length) {
                    best = loops;
                }
            }
        }
        catch (e_2_1) { e_2 = { error: e_2_1 }; }
        finally {
            try {
                if (tolerances_1_1 && !tolerances_1_1.done && (_a = tolerances_1.return)) _a.call(tolerances_1);
            }
            finally { if (e_2) throw e_2.error; }
        }
        return best;
    };
    /**
     * Calculates polygon signed area using the shoelace formula.
     *
     * @param points Polygon vertices.
     * @returns Signed area; positive/negative sign depends on winding direction.
     */
    AcApHatchCmd.prototype.signedArea = function (points) {
        if (points.length < 3)
            return 0;
        var sum = 0;
        for (var i = 0, j = points.length - 1; i < points.length; j = i++) {
            var p1 = points[j];
            var p2 = points[i];
            sum += p1.x * p2.y - p2.x * p1.y;
        }
        return sum * 0.5;
    };
    /**
     * Tests whether one point lies on a finite segment within a tolerance.
     *
     * @param px Test point X.
     * @param py Test point Y.
     * @param ax Segment start X.
     * @param ay Segment start Y.
     * @param bx Segment end X.
     * @param by Segment end Y.
     * @param tolerance Distance tolerance.
     * @returns `true` if point is on segment; otherwise `false`.
     */
    AcApHatchCmd.prototype.isPointOnSegment = function (px, py, ax, ay, bx, by, tolerance) {
        if (tolerance === void 0) { tolerance = 1e-8; }
        var abx = bx - ax;
        var aby = by - ay;
        var apx = px - ax;
        var apy = py - ay;
        var cross = Math.abs(abx * apy - aby * apx);
        if (cross > tolerance)
            return false;
        var dot = apx * abx + apy * aby;
        if (dot < -tolerance)
            return false;
        var len2 = abx * abx + aby * aby;
        if (dot - len2 > tolerance)
            return false;
        return true;
    };
    /**
     * Determines whether a point is inside (or on boundary of) a polygon.
     *
     * Boundary points are treated as inside to keep seed-point behavior stable
     * near loop edges.
     *
     * @param point Test point.
     * @param polygon Polygon vertices.
     * @returns `true` when inside or on boundary.
     */
    AcApHatchCmd.prototype.isPointInPolygon = function (point, polygon) {
        if (polygon.length < 3)
            return false;
        for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
            var a = polygon[j];
            var b = polygon[i];
            if (this.isPointOnSegment(point.x, point.y, a.x, a.y, b.x, b.y)) {
                return true;
            }
        }
        var inside = false;
        for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
            var xi = polygon[i].x;
            var yi = polygon[i].y;
            var xj = polygon[j].x;
            var yj = polygon[j].y;
            var intersects = yi > point.y !== yj > point.y &&
                point.x < ((xj - xi) * (point.y - yi)) / (yj - yi + Number.EPSILON) + xi;
            if (intersects)
                inside = !inside;
        }
        return inside;
    };
    /**
     * Builds loop metadata and parent/child containment relationships.
     *
     * @param loops Candidate closed loops.
     * @returns Loop info array with area and hierarchy metadata.
     */
    AcApHatchCmd.prototype.buildLoopInfos = function (loops) {
        var _this = this;
        var infos = [];
        loops.forEach(function (loop) {
            var points = loop.getPoints(128).map(function (p) { return ({ x: p.x, y: p.y }); });
            if (points.length < 3)
                return;
            infos.push({
                loop: loop,
                points: points,
                area: Math.abs(_this.signedArea(points)),
                parent: null,
                children: []
            });
        });
        for (var i = 0; i < infos.length; i++) {
            var sample = infos[i].points[0];
            var parentIndex = null;
            var parentArea = Number.POSITIVE_INFINITY;
            for (var j = 0; j < infos.length; j++) {
                if (i === j)
                    continue;
                if (infos[j].area <= infos[i].area)
                    continue;
                if (!this.isPointInPolygon(sample, infos[j].points))
                    continue;
                if (infos[j].area < parentArea) {
                    parentArea = infos[j].area;
                    parentIndex = j;
                }
            }
            infos[i].parent = parentIndex;
            if (parentIndex != null) {
                infos[parentIndex].children.push(i);
            }
        }
        return infos;
    };
    /**
     * Resolves which loops should be used for one pick-point seed.
     *
     * Strategy:
     * - Find the smallest containing loop as target.
     * - Include direct children as holes unless style is `Ignore`.
     *
     * @param point Seed point selected by user.
     * @param loops Candidate loops.
     * @returns Ordered loop set to append into one hatch entity.
     */
    AcApHatchCmd.prototype.resolveLoopsForPickPoint = function (point, loops) {
        var _this = this;
        var infos = this.buildLoopInfos(loops);
        if (!infos.length)
            return [];
        var containing = infos
            .map(function (info, index) {
            return _this.isPointInPolygon(point, info.points) ? index : -1;
        })
            .filter(function (index) { return index >= 0; });
        if (!containing.length)
            return [];
        containing.sort(function (a, b) { return infos[a].area - infos[b].area; });
        var target = containing[0];
        var selected = new Set([target]);
        // Pick-points mode should hatch the region connected to the picked seed.
        // Use target loop as outer boundary and its direct children as holes.
        if (AcApHatchCmd._lastSettings.style !== AcDbHatchStyle.Ignore) {
            infos[target].children.forEach(function (child) { return selected.add(child); });
        }
        return __spreadArray([], __read(selected), false).map(function (index) { return infos[index].loop; });
    };
    /**
     * Creates and appends one hatch entity from computed loops.
     *
     * @param context Active command context.
     * @param loops Boundary loops to be added to the hatch.
     * @returns `true` when hatch entity was created; otherwise `false`.
     */
    AcApHatchCmd.prototype.appendHatch = function (context, loops) {
        if (!loops.length)
            return false;
        var hatch = new AcDbHatch();
        var settings = AcApHatchCmd._lastSettings;
        hatch.patternName = settings.patternName;
        hatch.patternType = AcDbHatchPatternType.Predefined;
        hatch.patternScale = settings.patternScale;
        hatch.patternAngle = (settings.patternAngleDeg * Math.PI) / 180;
        hatch.hatchStyle = settings.style;
        hatch.isSolidFill = settings.patternName.toUpperCase() === 'SOLID';
        loops.forEach(function (loop) { return hatch.add(loop); });
        context.doc.database.tables.blockTable.modelSpace.appendEntity(hatch);
        return true;
    };
    /**
     * Prompts for pattern name and updates persisted command settings.
     *
     * @returns Promise resolved when prompt flow completes.
     */
    AcApHatchCmd.prototype.promptPatternName = function () {
        return __awaiter(this, void 0, void 0, function () {
            var strOptions, result;
            var _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        strOptions = new AcEdPromptStringOptions(AcApI18n.t('jig.hatch.patternName'));
                        strOptions.allowEmpty = false;
                        strOptions.defaultValue = AcApHatchCmd._lastSettings.patternName;
                        strOptions.useDefaultValue = true;
                        return [4 /*yield*/, AcApDocManager.instance.editor.getString(strOptions)];
                    case 1:
                        result = _b.sent();
                        if (result.status !== AcEdPromptStatus.OK)
                            return [2 /*return*/];
                        AcApHatchCmd._lastSettings.patternName = this.normalizePatternName((_a = result.stringResult) !== null && _a !== void 0 ? _a : strOptions.defaultValue);
                        return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Prompts for pattern scale and updates persisted command settings.
     *
     * @returns Promise resolved when prompt flow completes.
     */
    AcApHatchCmd.prototype.promptPatternScale = function () {
        return __awaiter(this, void 0, void 0, function () {
            var options, result, value;
            var _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        options = new AcEdPromptDoubleOptions(AcApI18n.t('jig.hatch.scale'));
                        options.allowNone = true;
                        options.allowNegative = false;
                        options.allowZero = false;
                        options.defaultValue = AcApHatchCmd._lastSettings.patternScale;
                        options.useDefaultValue = true;
                        return [4 /*yield*/, AcApDocManager.instance.editor.getDouble(options)];
                    case 1:
                        result = _b.sent();
                        if (result.status !== AcEdPromptStatus.OK)
                            return [2 /*return*/];
                        value = (_a = result.value) !== null && _a !== void 0 ? _a : options.defaultValue;
                        if (value > 0) {
                            AcApHatchCmd._lastSettings.patternScale = value;
                        }
                        return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Prompts for pattern angle (degrees) and updates persisted settings.
     *
     * @returns Promise resolved when prompt flow completes.
     */
    AcApHatchCmd.prototype.promptPatternAngle = function () {
        return __awaiter(this, void 0, void 0, function () {
            var options, result;
            var _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        options = new AcEdPromptDoubleOptions(AcApI18n.t('jig.hatch.angle'));
                        options.allowNone = true;
                        options.allowNegative = true;
                        options.allowZero = true;
                        options.defaultValue = AcApHatchCmd._lastSettings.patternAngleDeg;
                        options.useDefaultValue = true;
                        return [4 /*yield*/, AcApDocManager.instance.editor.getDouble(options)];
                    case 1:
                        result = _b.sent();
                        if (result.status !== AcEdPromptStatus.OK)
                            return [2 /*return*/];
                        AcApHatchCmd._lastSettings.patternAngleDeg =
                            (_a = result.value) !== null && _a !== void 0 ? _a : options.defaultValue;
                        return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Prompts for hatch style (`Normal` / `Outer` / `Ignore`).
     *
     * @returns Promise resolved when prompt flow completes.
     */
    AcApHatchCmd.prototype.promptStyle = function () {
        return __awaiter(this, void 0, void 0, function () {
            var current, options, result;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        current = this.styleToKeyword(AcApHatchCmd._lastSettings.style);
                        options = new AcEdPromptKeywordOptions("".concat(AcApI18n.t('jig.hatch.style'), " <").concat(current, ">"));
                        options.allowNone = true;
                        options.keywords.add(AcApI18n.t('jig.hatch.keywords.normal.display'), AcApI18n.t('jig.hatch.keywords.normal.global'), AcApI18n.t('jig.hatch.keywords.normal.local'));
                        options.keywords.add(AcApI18n.t('jig.hatch.keywords.outer.display'), AcApI18n.t('jig.hatch.keywords.outer.global'), AcApI18n.t('jig.hatch.keywords.outer.local'));
                        options.keywords.add(AcApI18n.t('jig.hatch.keywords.ignore.display'), AcApI18n.t('jig.hatch.keywords.ignore.global'), AcApI18n.t('jig.hatch.keywords.ignore.local'));
                        return [4 /*yield*/, AcApDocManager.instance.editor.getKeywords(options)];
                    case 1:
                        result = _a.sent();
                        if (result.status === AcEdPromptStatus.Keyword && result.stringResult) {
                            AcApHatchCmd._lastSettings.style = this.keywordToStyle(result.stringResult);
                        }
                        return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Prompts for associative mode switch (`Yes` / `No`).
     *
     * @returns Promise resolved when prompt flow completes.
     */
    AcApHatchCmd.prototype.promptAssociative = function () {
        return __awaiter(this, void 0, void 0, function () {
            var current, options, result;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        current = AcApHatchCmd._lastSettings.associative ? 'Yes' : 'No';
                        options = new AcEdPromptKeywordOptions("".concat(AcApI18n.t('jig.hatch.associative'), " <").concat(current, ">"));
                        options.allowNone = true;
                        options.keywords.add(AcApI18n.t('jig.hatch.keywords.yes.display'), AcApI18n.t('jig.hatch.keywords.yes.global'), AcApI18n.t('jig.hatch.keywords.yes.local'));
                        options.keywords.add(AcApI18n.t('jig.hatch.keywords.no.display'), AcApI18n.t('jig.hatch.keywords.no.global'), AcApI18n.t('jig.hatch.keywords.no.local'));
                        return [4 /*yield*/, AcApDocManager.instance.editor.getKeywords(options)];
                    case 1:
                        result = _a.sent();
                        if (result.status === AcEdPromptStatus.Keyword) {
                            AcApHatchCmd._lastSettings.associative = result.stringResult === 'Yes';
                        }
                        return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Executes object-selection branch of HATCH.
     *
     * @param context Active command context.
     * @returns `true` if a hatch was created from selected objects.
     */
    AcApHatchCmd.prototype.doSelectObjects = function (context) {
        return __awaiter(this, void 0, void 0, function () {
            var options, result, loops;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        options = new AcEdPromptSelectionOptions(AcApI18n.t('jig.hatch.select'));
                        return [4 /*yield*/, AcApDocManager.instance.editor.getSelection(options)];
                    case 1:
                        result = _a.sent();
                        if (result.status !== AcEdPromptStatus.OK || !result.value)
                            return [2 /*return*/, false];
                        loops = this.collectLoopsFromIds(context, result.value.ids);
                        if (!loops.length)
                            return [2 /*return*/, false];
                        return [2 /*return*/, this.appendHatch(context, loops)];
                }
            });
        });
    };
    /**
     * Executes pick-points branch of HATCH.
     *
     * The user can place multiple seed points. Each accepted point attempts
     * one hatch creation, and pressing Enter terminates this branch.
     *
     * @param context Active command context.
     * @returns `true` if at least one hatch was created.
     */
    AcApHatchCmd.prototype.doPickPoints = function (context) {
        return __awaiter(this, void 0, void 0, function () {
            var sourceLoops, created, pointOptions, pointResult, loops;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        sourceLoops = this.collectLoopsFromAllBoundaries(context);
                        if (!sourceLoops.length)
                            return [2 /*return*/, false];
                        created = false;
                        _a.label = 1;
                    case 1:
                        if (!true) return [3 /*break*/, 3];
                        pointOptions = new AcEdPromptPointOptions(AcApI18n.t('jig.hatch.pickPoint'));
                        pointOptions.allowNone = true;
                        return [4 /*yield*/, AcApDocManager.instance.editor.getPoint(pointOptions)];
                    case 2:
                        pointResult = _a.sent();
                        if (pointResult.status !== AcEdPromptStatus.OK || !pointResult.value)
                            return [3 /*break*/, 3];
                        loops = this.resolveLoopsForPickPoint(pointResult.value, sourceLoops);
                        if (!loops.length)
                            return [3 /*break*/, 1];
                        if (this.appendHatch(context, loops)) {
                            created = true;
                        }
                        return [3 /*break*/, 1];
                    case 3: return [2 /*return*/, created];
                }
            });
        });
    };
    /**
     * Runs the interactive command-line HATCH workflow.
     *
     * Main loop behavior:
     * - Direct entity pick: hatch from picked boundary object.
     * - Keyword branches: pick-points, select-objects, or option editing.
     * - Enter/Cancel: exits command.
     *
     * @param context Active command context.
     * @returns Promise resolved when command ends.
     */
    AcApHatchCmd.prototype.execute = function (context) {
        return __awaiter(this, void 0, void 0, function () {
            var running, options, result, loops, keyword;
            var _a;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        running = true;
                        _b.label = 1;
                    case 1:
                        if (!running) return [3 /*break*/, 18];
                        options = new AcEdPromptEntityOptions(AcApI18n.t('jig.hatch.prompt'));
                        options.allowNone = true;
                        options.setRejectMessage(AcApI18n.t('jig.hatch.invalidBoundary'));
                        options.addAllowedClass('Polyline');
                        options.addAllowedClass('Circle');
                        options.addAllowedClass('Arc');
                        options.addAllowedClass('Line');
                        options.keywords.add(AcApI18n.t('jig.hatch.keywords.pick.display'), AcApI18n.t('jig.hatch.keywords.pick.global'), AcApI18n.t('jig.hatch.keywords.pick.local'));
                        options.keywords.add(AcApI18n.t('jig.hatch.keywords.select.display'), AcApI18n.t('jig.hatch.keywords.select.global'), AcApI18n.t('jig.hatch.keywords.select.local'));
                        options.keywords.add(AcApI18n.t('jig.hatch.keywords.pattern.display'), AcApI18n.t('jig.hatch.keywords.pattern.global'), AcApI18n.t('jig.hatch.keywords.pattern.local'));
                        options.keywords.add(AcApI18n.t('jig.hatch.keywords.scale.display'), AcApI18n.t('jig.hatch.keywords.scale.global'), AcApI18n.t('jig.hatch.keywords.scale.local'));
                        options.keywords.add(AcApI18n.t('jig.hatch.keywords.angle.display'), AcApI18n.t('jig.hatch.keywords.angle.global'), AcApI18n.t('jig.hatch.keywords.angle.local'));
                        options.keywords.add(AcApI18n.t('jig.hatch.keywords.style.display'), AcApI18n.t('jig.hatch.keywords.style.global'), AcApI18n.t('jig.hatch.keywords.style.local'));
                        options.keywords.add(AcApI18n.t('jig.hatch.keywords.associative.display'), AcApI18n.t('jig.hatch.keywords.associative.global'), AcApI18n.t('jig.hatch.keywords.associative.local'));
                        return [4 /*yield*/, AcApDocManager.instance.editor.getEntity(options)];
                    case 2:
                        result = _b.sent();
                        if (result.status === AcEdPromptStatus.OK && result.objectId) {
                            loops = this.collectLoopsFromIds(context, [result.objectId]);
                            if (!loops.length) {
                                return [3 /*break*/, 1];
                            }
                            this.appendHatch(context, loops);
                            return [3 /*break*/, 1];
                        }
                        if (!(result.status === AcEdPromptStatus.Keyword)) return [3 /*break*/, 17];
                        keyword = (_a = result.stringResult) !== null && _a !== void 0 ? _a : '';
                        if (!(keyword === 'PickPoints')) return [3 /*break*/, 4];
                        return [4 /*yield*/, this.doPickPoints(context)];
                    case 3:
                        _b.sent();
                        return [3 /*break*/, 16];
                    case 4:
                        if (!(keyword === 'SelectObjects')) return [3 /*break*/, 6];
                        return [4 /*yield*/, this.doSelectObjects(context)];
                    case 5:
                        _b.sent();
                        return [3 /*break*/, 16];
                    case 6:
                        if (!(keyword === 'Pattern')) return [3 /*break*/, 8];
                        return [4 /*yield*/, this.promptPatternName()];
                    case 7:
                        _b.sent();
                        return [3 /*break*/, 16];
                    case 8:
                        if (!(keyword === 'Scale')) return [3 /*break*/, 10];
                        return [4 /*yield*/, this.promptPatternScale()];
                    case 9:
                        _b.sent();
                        return [3 /*break*/, 16];
                    case 10:
                        if (!(keyword === 'Angle')) return [3 /*break*/, 12];
                        return [4 /*yield*/, this.promptPatternAngle()];
                    case 11:
                        _b.sent();
                        return [3 /*break*/, 16];
                    case 12:
                        if (!(keyword === 'HatchStyle')) return [3 /*break*/, 14];
                        return [4 /*yield*/, this.promptStyle()];
                    case 13:
                        _b.sent();
                        return [3 /*break*/, 16];
                    case 14:
                        if (!(keyword === 'AssociativeMode')) return [3 /*break*/, 16];
                        return [4 /*yield*/, this.promptAssociative()];
                    case 15:
                        _b.sent();
                        _b.label = 16;
                    case 16: return [3 /*break*/, 1];
                    case 17:
                        running = false;
                        return [3 /*break*/, 1];
                    case 18: return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Last-used command settings shared by all `AcApHatchCmd` instances.
     */
    AcApHatchCmd._lastSettings = {
        patternName: 'ANSI31',
        patternScale: 1,
        patternAngleDeg: 0,
        style: AcDbHatchStyle.Normal,
        associative: true
    };
    return AcApHatchCmd;
}(AcEdCommand));
export { AcApHatchCmd };
//# sourceMappingURL=AcApHatchCmd.js.map