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 { acdbHostApplicationServices, AcDbSystemVariables, AcDbSysVarManager, AcGeBox2d } from '@mlightcad/data-model';
import { AcApDocManager, AcApSettingManager } from '../../../app';
import { AcApI18n } from '../../../i18n';
import { AcEdSelectionSet } from '../AcEdSelectionSet';
import { AcEdAngleHandler, AcEdDistanceHandler, AcEdDoubleHandler, AcEdIntegerHandler, AcEdPointHandler, AcEdStringHandler } from '../handler';
import { AcEdKeywordHandler } from '../handler/AcEdKeywordHandler';
import { AcEdPromptBoxResult, AcEdPromptDoubleResult, AcEdPromptEntityResult, AcEdPromptIntegerResult, AcEdPromptKeywordOptions, AcEdPromptPointOptions, AcEdPromptPointResult, AcEdPromptResult, AcEdPromptSelectionResult, AcEdPromptStatus } from '../prompt';
import { AcEdCommandLine } from './AcEdCommandLine';
import { AcEdFloatingInput } from './AcEdFloatingInput';
import { AcEdFloatingMessage } from './AcEdFloatingMessage';
/**
 * Internal control-flow error used to propagate keyword picks out of
 * floating-input loops.
 *
 * This error is intentionally caught by prompt wrappers and converted into
 * `AcEdPromptStatus.Keyword` results.
 */
var AcEdKeywordInputError = /** @class */ (function (_super) {
    __extends(AcEdKeywordInputError, _super);
    /**
     * Creates a keyword control-flow error.
     *
     * @param keyword - Canonical keyword token to bubble to prompt callers.
     */
    function AcEdKeywordInputError(keyword) {
        var _this = _super.call(this, 'keyword') || this;
        _this.keyword = keyword;
        return _this;
    }
    return AcEdKeywordInputError;
}(Error));
/**
 * Internal control-flow error used to represent Enter/RightClick None input.
 */
var AcEdNoneInputError = /** @class */ (function (_super) {
    __extends(AcEdNoneInputError, _super);
    function AcEdNoneInputError() {
        return _super.call(this, 'none') || this;
    }
    return AcEdNoneInputError;
}(Error));
/**
 * A fully type-safe TypeScript class providing CAD-style interactive user input
 * using floating HTML input boxes and mouse events. Supports collecting points,
 * distances, angles, numbers, strings, and selecting a 2-point rectangular box
 * using an HTML overlay rectangle (suitable when the main canvas is a THREE.js
 * WebGL canvas).
 */
var AcEdInputManager = /** @class */ (function () {
    /**
     * Construct the manager and attach mousemove listener used for floating input
     * positioning and live preview updates.
     *
     * @param view - The view associated with the input manager
     */
    function AcEdInputManager(view) {
        /** Stores last confirmed point from getPoint() or getBox() */
        this.lastPoint = null;
        /** Buffered command-line style inputs (each item is one Enter-confirmed value). */
        this._scriptInputs = [];
        /** Current modifier key state during input sessions. */
        this._modifierState = {
            ctrlKey: false,
            shiftKey: false,
            altKey: false,
            metaKey: false
        };
        /** Toggle-style Ctrl flip state (press Ctrl once to flip arc direction). */
        this._ctrlArcFlip = false;
        /**
         * The flag to indicate whether it is currently in an “input acquisition” mode (e.g., point
         * selection, distance/angle prompt, string prompt, etc.),
         */
        this.active = false;
        /**
         * True only when the current input session explicitly expects entity selection
         * (getEntity/getSelection). Used to gate view-level selection behavior.
         */
        this.entitySelectionActive = false;
        this.view = view;
        this.injectCSS();
        // Newly added UI overlays (command line, previews) are container-local.
        // Ensure absolute-positioned children are anchored to this view only.
        var containerPosition = getComputedStyle(this.view.container).position;
        if (containerPosition === 'static') {
            this.view.container.style.position = 'relative';
        }
        var commandLine = new AcEdCommandLine(this.view.container);
        this._commandLine = commandLine;
        commandLine.visible = AcApSettingManager.instance.isShowCommandLine;
        AcApSettingManager.instance.events.modified.addEventListener(function () {
            commandLine.visible = AcApSettingManager.instance.isShowCommandLine;
        });
    }
    Object.defineProperty(AcEdInputManager.prototype, "isActive", {
        /**
         * The flag to indicate whether it is currently in an “input acquisition” mode (e.g., point
         * selection, distance/angle prompt, string prompt, etc.),
         */
        get: function () {
            return this.active;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(AcEdInputManager.prototype, "isEntitySelectionActive", {
        /**
         * Whether current input session allows entity selection in the view.
         */
        get: function () {
            return this.entitySelectionActive;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(AcEdInputManager.prototype, "modifiers", {
        /**
         * Current modifier key state (Ctrl/Shift/Alt/Meta) during input sessions.
         */
        get: function () {
            return this._modifierState;
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(AcEdInputManager.prototype, "toggles", {
        /**
         * Toggle-style input states (press once to flip, persists after keyup).
         */
        get: function () {
            return { ctrlArcFlip: this._ctrlArcFlip };
        },
        enumerable: false,
        configurable: true
    });
    /** Reset toggle-style inputs to their default state. */
    AcEdInputManager.prototype.resetToggles = function () {
        this._ctrlArcFlip = false;
    };
    /**
     * Queue scripted inputs for subsequent getXXX calls.
     * One array item equals one Enter-confirmed value.
     */
    AcEdInputManager.prototype.enqueueScriptInputs = function (inputs) {
        var _a;
        if (!inputs.length)
            return;
        (_a = this._scriptInputs).push.apply(_a, __spreadArray([], __read(inputs), false));
    };
    /** Clears any pending scripted inputs. */
    AcEdInputManager.prototype.clearScriptInputs = function () {
        this._scriptInputs.length = 0;
    };
    /**
     * Injects minimal CSS required for the floating input and preview rectangle.
     * Useful when you do not have a separate CSS file.
     */
    AcEdInputManager.prototype.injectCSS = function () {
        if (AcEdInputManager.stylesInjected)
            return;
        AcEdInputManager.stylesInjected = true;
        var style = document.createElement('style');
        style.textContent = "\n      .ml-jig-preview-rect {\n        position: absolute;\n        border: 1px dashed var(--line-color, var(--ml-ui-canvas-line, #0f0));\n        background: var(--ml-ui-canvas-fill-mix, var(--ml-ui-canvas-fill, rgba(64, 158, 255, 0.12)));\n        pointer-events: none;\n        z-index: 9999;\n      }\n      .ml-jig-preview-line {\n        position: absolute;\n        height: 1px;\n        background: var(--line-color, var(--ml-ui-canvas-line, #0f0));\n        transform-origin: 0 0;\n        pointer-events: none;\n        z-index: 9999;\n      }\n    ";
        document.head.appendChild(style);
    };
    /**
     * Format a number for display in input box.
     * Default: 3 decimal places for points/distance, 2 decimal places for angles.
     * @param value The numeric value
     * @param type Optional type: 'point' | 'distance' | 'angle'
     */
    AcEdInputManager.prototype.formatNumber = function (value, type) {
        switch (type) {
            case 'angle':
                return value.toFixed(2);
            case 'distance':
            case 'point':
            default:
                return value.toFixed(3);
        }
    };
    /**
     * Returns whether the supplied prompt defines any keywords.
     *
     * Keyword-aware prompts need extra command-line wiring so textual input can
     * be interpreted as keyword picks instead of free-form values. This helper
     * centralizes the check and gracefully handles prompts that expose no keyword
     * collection.
     *
     * @param options - Prompt options to inspect
     * @returns `true` when at least one keyword is registered on the prompt
     */
    AcEdInputManager.prototype.hasKeywords = function (options) {
        var _a, _b;
        var keywords = (_b = (_a = options.keywords) === null || _a === void 0 ? void 0 : _a.toArray()) !== null && _b !== void 0 ? _b : [];
        return keywords.length > 0;
    };
    /**
     * Builds a keyword-only prompt options object from a general prompt.
     *
     * Several input flows support optional keywords in parallel with their main
     * acquisition mode. Rather than duplicating keyword definitions manually, the
     * original prompt's keyword metadata is cloned into a dedicated
     * `AcEdPromptKeywordOptions` instance that can be passed to the command-line
     * keyword session.
     *
     * @typeParam T - Value type produced by the source prompt
     * @param options - Source prompt whose keyword definitions should be copied
     * @returns A keyword prompt configured with the same message and keyword set
     */
    AcEdInputManager.prototype.buildKeywordOptions = function (options) {
        var _a, _b;
        var keywordOptions = new AcEdPromptKeywordOptions(options.message);
        keywordOptions.appendKeywordsToMessage = options.appendKeywordsToMessage;
        var keywords = (_b = (_a = options.keywords) === null || _a === void 0 ? void 0 : _a.toArray()) !== null && _b !== void 0 ? _b : [];
        keywords.forEach(function (kw) {
            var added = keywordOptions.keywords.add(kw.displayName, kw.globalName, kw.localName, kw.enabled, kw.visible);
            if (options.keywords.default === kw) {
                keywordOptions.keywords.default = added;
            }
        });
        return keywordOptions;
    };
    /**
     * Copies keyword definitions from one prompt options object to another.
     *
     * This is primarily used by composite prompts such as `getBox()`, which break
     * a higher-level workflow into multiple sub-prompts while preserving the same
     * keyword vocabulary and default keyword behavior across each stage.
     *
     * @param source - Prompt options providing the keyword definitions
     * @param target - Prompt options receiving the cloned keyword definitions
     */
    AcEdInputManager.prototype.copyKeywords = function (source, target) {
        var _a, _b;
        target.appendKeywordsToMessage = source.appendKeywordsToMessage;
        var keywords = (_b = (_a = source.keywords) === null || _a === void 0 ? void 0 : _a.toArray()) !== null && _b !== void 0 ? _b : [];
        keywords.forEach(function (kw) {
            var added = target.keywords.add(kw.displayName, kw.globalName, kw.localName, kw.enabled, kw.visible);
            if (source.keywords.default === kw) {
                target.keywords.default = added;
            }
        });
    };
    /**
     * Resolves a picked object id back to its database entity instance.
     *
     * View-level picking only returns lightweight hit-test data such as object
     * ids and bounding information. Prompt validation, however, needs access to
     * the backing `AcDbEntity` so it can inspect runtime metadata like the entity
     * type and layer.
     *
     * @param objectId - Object id returned by the spatial pick query
     * @returns The matching database entity, or `undefined` if it can no longer be found
     */
    AcEdInputManager.prototype.getEntityById = function (objectId) {
        return AcApDocManager.instance.curDocument.database.tables.blockTable.getEntityById(objectId);
    };
    /**
     * Returns whether the specified entity belongs to a locked layer.
     *
     * The entity itself only stores its layer name, so this helper resolves the
     * layer record from the current drawing database and inspects its lock state.
     * Missing layer records are treated as unlocked to avoid rejecting input due
     * to incomplete metadata.
     *
     * @param entity - Entity being evaluated for prompt selection
     * @returns `true` if the entity's layer exists and is locked; otherwise `false`
     */
    AcEdInputManager.prototype.isEntityOnLockedLayer = function (entity) {
        var _a;
        var layerName = entity.layer;
        if (!layerName) {
            return false;
        }
        return !!((_a = AcApDocManager.instance.curDocument.database.tables.layerTable.getAt(layerName)) === null || _a === void 0 ? void 0 : _a.isLocked);
    };
    /**
     * Checks whether a picked entity satisfies the prompt's allowed-class filter.
     *
     * Different parts of the stack expose the entity type in slightly different
     * forms. The data-model layer provides a short CAD type name through
     * `entity.type` (for example `Line`), while runtime inspection exposes the
     * TypeScript constructor name (for example `AcDbLine`). To maximize
     * compatibility with existing caller expectations, both forms are tested
     * against the prompt's allow-list.
     *
     * @param entity - Picked entity being validated
     * @param options - Prompt options containing the configured allowed classes
     * @returns `true` when the entity matches at least one allowed class, or when
     * no class restriction has been configured
     */
    AcEdInputManager.prototype.isEntityClassAllowed = function (entity, options) {
        var e_1, _a;
        var _b;
        var candidates = new Set();
        if (entity.type) {
            candidates.add(entity.type);
        }
        var constructorName = (_b = entity.constructor) === null || _b === void 0 ? void 0 : _b.name;
        if (constructorName) {
            candidates.add(constructorName);
        }
        try {
            for (var candidates_1 = __values(candidates), candidates_1_1 = candidates_1.next(); !candidates_1_1.done; candidates_1_1 = candidates_1.next()) {
                var candidate = candidates_1_1.value;
                if (options.isClassAllowed(candidate)) {
                    return true;
                }
            }
        }
        catch (e_1_1) { e_1 = { error: e_1_1 }; }
        finally {
            try {
                if (candidates_1_1 && !candidates_1_1.done && (_a = candidates_1.return)) _a.call(candidates_1);
            }
            finally { if (e_1) throw e_1.error; }
        }
        return false;
    };
    /**
     * Starts a command-line keyword session for the given prompt when needed.
     *
     * Many interactive prompts accept both mouse-driven input and typed keywords
     * at the same time. This helper lazily creates the command-line keyword
     * session only when keywords are actually configured, and returns a small
     * control object that lets callers await or cancel that session.
     *
     * @param options - Prompt options that may define keywords
     * @param allowTyping - Whether arbitrary typing is allowed alongside keyword completion
     * @returns An object containing the keyword promise and cancel callback, or
     * `undefined` when the prompt has no keywords
     */
    AcEdInputManager.prototype.startKeywordSession = function (options, allowTyping) {
        var _this = this;
        if (!this.hasKeywords(options))
            return undefined;
        var keywordOptions = this.buildKeywordOptions(options);
        return {
            promise: this._commandLine.getKeywords(keywordOptions, allowTyping),
            cancel: function () { return _this._commandLine.cancelActiveSession(); }
        };
    };
    /**
     * Narrows an unknown error value to the internal keyword control-flow error.
     *
     * Prompt implementations use {@link AcEdKeywordInputError} as a private
     * mechanism for bubbling a keyword pick out of deeply nested async UI flows.
     * This type guard keeps the outer prompt wrappers readable while preserving
     * strong typing for the extracted keyword token.
     *
     * @param error - Unknown error value thrown from an input workflow
     * @returns `true` if the error represents a keyword selection
     */
    AcEdInputManager.prototype.isPromptKeyword = function (error) {
        return error instanceof AcEdKeywordInputError;
    };
    /**
     * Converts internal prompt control-flow errors to typed prompt results.
     *
     * @typeParam T - Prompt result type to construct
     * @param error - Unknown error thrown from prompt workflow
     * @param handlers - Result factories for mapped prompt statuses
     * @returns Mapped prompt result when recognized; otherwise `undefined`
     */
    AcEdInputManager.prototype.mapPromptError = function (error, handlers) {
        if (handlers.none && this.isPromptNone(error)) {
            return handlers.none();
        }
        if (handlers.cancel && this.isPromptCancelled(error)) {
            return handlers.cancel();
        }
        if (handlers.keyword && this.isPromptKeyword(error)) {
            return handlers.keyword(error.keyword);
        }
        return undefined;
    };
    /**
     * Attaches keyword text to a prompt result and returns it.
     */
    AcEdInputManager.prototype.withKeywordResult = function (result, keyword) {
        result.stringResult = keyword;
        return result;
    };
    /**
     * Maps internal control-flow errors to prompt results by status constructor.
     *
     * @typeParam T - Prompt result type
     * @param error - Unknown error thrown from prompt workflow
     * @param create - Factory creating a result from target status
     * @param options - Toggles for supported mapped statuses
     */
    AcEdInputManager.prototype.mapPromptErrorToResult = function (error, create, options) {
        var _this = this;
        var _a, _b, _c;
        var includeNone = (_a = options === null || options === void 0 ? void 0 : options.none) !== null && _a !== void 0 ? _a : true;
        var includeCancel = (_b = options === null || options === void 0 ? void 0 : options.cancel) !== null && _b !== void 0 ? _b : true;
        var includeKeyword = (_c = options === null || options === void 0 ? void 0 : options.keyword) !== null && _c !== void 0 ? _c : true;
        return this.mapPromptError(error, {
            none: includeNone ? function () { return create(AcEdPromptStatus.None); } : undefined,
            cancel: includeCancel ? function () { return create(AcEdPromptStatus.Cancel); } : undefined,
            keyword: includeKeyword
                ? function (keyword) {
                    return _this.withKeywordResult(create(AcEdPromptStatus.Keyword), keyword);
                }
                : undefined
        });
    };
    /**
     * Executes prompt workflow with centralized try/catch mapping.
     *
     * @typeParam T - Raw successful value from prompt workflow
     * @typeParam R - Prompt result type
     * @param run - Async prompt workflow that may throw control-flow errors
     * @param onOk - Maps successful workflow value to result object
     * @param create - Creates a result object from mapped prompt status
     * @param options - Toggles for supported mapped statuses
     */
    AcEdInputManager.prototype.executePrompt = function (run, onOk, create, options) {
        return __awaiter(this, void 0, void 0, function () {
            var value, error_1, mapped;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        _a.trys.push([0, 2, , 3]);
                        return [4 /*yield*/, run()];
                    case 1:
                        value = _a.sent();
                        return [2 /*return*/, onOk(value)];
                    case 2:
                        error_1 = _a.sent();
                        mapped = this.mapPromptErrorToResult(error_1, create, options);
                        if (mapped)
                            return [2 /*return*/, mapped];
                        throw error_1;
                    case 3: return [2 /*return*/];
                }
            });
        });
    };
    /**
     * Extracts default-value behavior from prompt options when supported.
     */
    AcEdInputManager.prototype.resolvePromptDefaultValue = function (promptOptions) {
        if ('useDefaultValue' in promptOptions &&
            'defaultValue' in promptOptions &&
            promptOptions.useDefaultValue) {
            return {
                useDefaultValue: true,
                defaultValue: promptOptions.defaultValue
            };
        }
        return { useDefaultValue: false };
    };
    /**
     * Prompts the user to specify a point.
     *
     * The point may be supplied by clicking in the view, typing coordinates into
     * the floating input, or consuming a queued scripted input token. Keywords are
     * also supported when configured on the prompt options.
     *
     * @param options - Point prompt options controlling messaging, base-point
     * behavior, jig integration, and keywords
     * @returns A prompt result containing the picked point, cancel status, or keyword
     */
    AcEdInputManager.prototype.getPoint = function (options) {
        return __awaiter(this, void 0, void 0, function () {
            var _this = this;
            return __generator(this, function (_a) {
                return [2 /*return*/, this.executePrompt(function () { return _this.getPointInternal(options); }, function (value) { return new AcEdPromptPointResult(AcEdPromptStatus.OK, value); }, function (status) { return new AcEdPromptPointResult(status); })];
            });
        });
    };
    /**
     * Prompts the user for a purely typed numeric value through floating input.
     *
     * This helper is shared by distance, angle, double, and integer prompts when
     * no mouse-driven geometric reference is needed. Validation is delegated to
     * the supplied handler so the floating UI can mark invalid values and keep
     * the prompt alive until the user enters an acceptable number.
     *
     * @param options - Numeric prompt options describing the message and keyword set
     * @param handler - Parser/validator responsible for converting raw text into a number
     * @returns A promise that resolves to the parsed numeric value
     */
    AcEdInputManager.prototype.getNumberTyped = function (options, handler) {
        var getDynamicValue = function () {
            return {
                value: 0,
                raw: { x: '' }
            };
        };
        return this.makeFloatingInputPromise({
            inputCount: 1,
            promptOptions: options,
            handler: handler,
            getDynamicValue: getDynamicValue
        });
    };
    /**
     * Prompts the user to specify a distance value.
     *
     * When a base point is available, the floating input previews the live
     * distance from that reference point to the current cursor. Otherwise, the
     * method falls back to typed numeric entry only. Scripted inputs and keywords
     * are supported as well.
     *
     * @param options - Distance prompt options controlling base-point behavior and messaging
     * @returns A prompt result containing the resolved distance, cancel status, or keyword
     */
    AcEdInputManager.prototype.getDistance = function (options) {
        return __awaiter(this, void 0, void 0, function () {
            var handler, scriptedValue;
            var _this = this;
            return __generator(this, function (_a) {
                handler = new AcEdDistanceHandler(options);
                scriptedValue = this.tryGetScriptedNumber(handler);
                if (scriptedValue != null) {
                    return [2 /*return*/, new AcEdPromptDoubleResult(AcEdPromptStatus.OK, scriptedValue)];
                }
                return [2 /*return*/, this.executePrompt(function () { return __awaiter(_this, void 0, void 0, function () {
                        var getDynamicValue;
                        var _this = this;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0:
                                    if (!!this.lastPoint) return [3 /*break*/, 2];
                                    return [4 /*yield*/, this.getNumberTyped(options, handler)];
                                case 1: return [2 /*return*/, _a.sent()];
                                case 2:
                                    getDynamicValue = function (pos) {
                                        var dx = pos.x - _this.lastPoint.x;
                                        var dy = pos.y - _this.lastPoint.y;
                                        var dist = Math.sqrt(dx * dx + dy * dy);
                                        return {
                                            value: dist,
                                            raw: { x: _this.formatNumber(dist, 'distance') }
                                        };
                                    };
                                    return [4 /*yield*/, this.makeFloatingInputPromise({
                                            inputCount: 1,
                                            promptOptions: options,
                                            handler: handler,
                                            getDynamicValue: getDynamicValue
                                        })];
                                case 3: return [2 /*return*/, _a.sent()];
                            }
                        });
                    }); }, function (value) { return new AcEdPromptDoubleResult(AcEdPromptStatus.OK, value); }, function (status) { return new AcEdPromptDoubleResult(status); })];
            });
        });
    };
    /**
     * Prompts the user to specify an angle in degrees.
     *
     * If a base point is available, the cursor position is converted into a live
     * angular preview relative to that point and the optional prompt base angle.
     * Without a geometric reference, the method accepts typed numeric input only.
     *
     * @param options - Angle prompt options controlling base point, base angle, and messaging
     * @returns A prompt result containing the resolved angle, cancel status, or keyword
     */
    AcEdInputManager.prototype.getAngle = function (options) {
        return __awaiter(this, void 0, void 0, function () {
            var handler, scriptedValue, basePoint, getDynamicValue;
            var _this = this;
            return __generator(this, function (_a) {
                handler = new AcEdAngleHandler(options);
                scriptedValue = this.tryGetScriptedNumber(handler);
                if (scriptedValue != null) {
                    return [2 /*return*/, new AcEdPromptDoubleResult(AcEdPromptStatus.OK, scriptedValue)];
                }
                basePoint = options.useBasePoint && options.basePoint
                    ? options.basePoint
                    : this.lastPoint;
                // No reference point available: fallback to typed angle input only.
                if (!basePoint) {
                    return [2 /*return*/, this.executePrompt(function () { return _this.getNumberTyped(options, handler); }, function (value) { return new AcEdPromptDoubleResult(AcEdPromptStatus.OK, value); }, function (status) { return new AcEdPromptDoubleResult(status); })];
                }
                getDynamicValue = function (pos) {
                    var dx = pos.x - basePoint.x;
                    var dy = pos.y - basePoint.y;
                    var rawAngleRad = Math.atan2(dy, dx);
                    var baseAngleRad = (options.baseAngle * Math.PI) / 180;
                    var angleRad = rawAngleRad - baseAngleRad;
                    while (angleRad <= -Math.PI)
                        angleRad += Math.PI * 2;
                    while (angleRad > Math.PI)
                        angleRad -= Math.PI * 2;
                    var angleDeg = (angleRad * 180) / Math.PI;
                    return {
                        value: angleDeg,
                        raw: { x: _this.formatNumber(angleDeg, 'angle') }
                    };
                };
                return [2 /*return*/, this.executePrompt(function () {
                        return _this.makeFloatingInputPromise({
                            inputCount: 1,
                            promptOptions: options,
                            handler: handler,
                            getDynamicValue: getDynamicValue
                        });
                    }, function (value) { return new AcEdPromptDoubleResult(AcEdPromptStatus.OK, value); }, function (status) { return new AcEdPromptDoubleResult(status); })];
            });
        });
    };
    /**
     * Prompts the user for a floating-point number.
     *
     * This is the generic free-form numeric entry path used when no geometric
     * interpretation such as distance or angle is required.
     *
     * @param options - Double prompt options controlling validation and messaging
     * @returns A prompt result containing the parsed number, cancel status, or keyword
     */
    AcEdInputManager.prototype.getDouble = function (options) {
        return __awaiter(this, void 0, void 0, function () {
            var handler, scriptedValue;
            var _this = this;
            return __generator(this, function (_a) {
                handler = new AcEdDoubleHandler(options);
                scriptedValue = this.tryGetScriptedNumber(handler);
                if (scriptedValue != null) {
                    return [2 /*return*/, new AcEdPromptDoubleResult(AcEdPromptStatus.OK, scriptedValue)];
                }
                return [2 /*return*/, this.executePrompt(function () { return _this.getNumberTyped(options, handler); }, function (value) { return new AcEdPromptDoubleResult(AcEdPromptStatus.OK, value); }, function (status) { return new AcEdPromptDoubleResult(status); })];
            });
        });
    };
    /**
     * Prompts the user for an integer value.
     *
     * The supplied integer handler enforces integer-only parsing for both typed
     * input and scripted command input.
     *
     * @param options - Integer prompt options controlling validation and messaging
     * @returns A prompt result containing the parsed integer, cancel status, or keyword
     */
    AcEdInputManager.prototype.getInteger = function (options) {
        return __awaiter(this, void 0, void 0, function () {
            var scriptedValue;
            var _this = this;
            return __generator(this, function (_a) {
                scriptedValue = this.tryGetScriptedNumber(new AcEdIntegerHandler(options));
                if (scriptedValue != null) {
                    return [2 /*return*/, new AcEdPromptIntegerResult(AcEdPromptStatus.OK, scriptedValue)];
                }
                return [2 /*return*/, this.executePrompt(function () { return _this.getNumberTyped(options, new AcEdIntegerHandler(options)); }, function (value) { return new AcEdPromptIntegerResult(AcEdPromptStatus.OK, value); }, function (status) { return new AcEdPromptIntegerResult(status); })];
            });
        });
    };
    /**
     * Prompts the user to type an arbitrary string.
     *
     * The value is collected through the shared floating-input pipeline so it can
     * participate in the same cancellation, keyword, and scripted-input behavior
     * as the other prompt types.
     *
     * @param options - String prompt options controlling the prompt message and keywords
     * @returns A prompt result containing the entered string, cancel status, or keyword
     */
    AcEdInputManager.prototype.getString = function (options) {
        return __awaiter(this, void 0, void 0, function () {
            var scriptedValue;
            var _this = this;
            return __generator(this, function (_a) {
                scriptedValue = this.tryGetScriptedValue(new AcEdStringHandler(options));
                if (scriptedValue != null) {
                    return [2 /*return*/, new AcEdPromptResult(AcEdPromptStatus.OK, scriptedValue)];
                }
                return [2 /*return*/, this.executePrompt(function () { return __awaiter(_this, void 0, void 0, function () {
                        var getDynamicValue, handler;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0:
                                    getDynamicValue = function () {
                                        return {
                                            value: '',
                                            raw: { x: '' }
                                        };
                                    };
                                    handler = new AcEdStringHandler(options);
                                    return [4 /*yield*/, this.makeFloatingInputPromise({
                                            inputCount: 1,
                                            promptOptions: options,
                                            handler: handler,
                                            getDynamicValue: getDynamicValue
                                        })];
                                case 1: return [2 /*return*/, _a.sent()];
                            }
                        });
                    }); }, function (value) { return new AcEdPromptResult(AcEdPromptStatus.OK, value); }, function (status) { return new AcEdPromptResult(status); })];
            });
        });
    };
    /**
     * Prompts the user to enter one of the configured keywords.
     *
     * Unlike the mixed-mode keyword sessions used by other prompt types, this
     * method runs a dedicated keyword prompt and returns the chosen keyword as the
     * result value.
     *
     * @param options - Keyword prompt options describing the allowed keywords
     * @returns A prompt result containing the chosen keyword or cancel status
     */
    AcEdInputManager.prototype.getKeywords = function (options) {
        return __awaiter(this, void 0, void 0, function () {
            var scriptedValue;
            var _this = this;
            return __generator(this, function (_a) {
                scriptedValue = this.tryGetScriptedValue(new AcEdKeywordHandler(options));
                if (scriptedValue != null) {
                    return [2 /*return*/, new AcEdPromptResult(AcEdPromptStatus.OK, scriptedValue)];
                }
                return [2 /*return*/, this.executePrompt(function () { return __awaiter(_this, void 0, void 0, function () {
                        var result;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0: return [4 /*yield*/, this._commandLine.getKeywords(options, true)];
                                case 1:
                                    result = _a.sent();
                                    if (!result) {
                                        if (options.allowNone) {
                                            throw new AcEdNoneInputError();
                                        }
                                        throw new Error('cancelled');
                                    }
                                    return [2 /*return*/, result];
                            }
                        });
                    }); }, function (value) { return new AcEdPromptResult(AcEdPromptStatus.OK, value); }, function (status) { return new AcEdPromptResult(status); }, { keyword: false })];
            });
        });
    };
    /**
     * Prompts the user to select one or more entities by mouse interaction.
     *
     * This method supports two selection modes:
     *
     * - **Click selection**: Clicking on an entity selects the entity under the cursor.
     * - **Box selection**:
     *   - left-to-right drag: window selection (entities fully inside the box)
     *   - right-to-left drag: crossing selection (entities intersecting the box)
     *
     * The selection operation behaves similarly to AutoCAD's
     * `Editor.GetSelection()` API:
     *
     * - Press **Enter** to accept the current selection set.
     * - Press **Escape** to cancel the operation.
     * - If {@link AcEdPromptSelectionOptions.singleOnly} is `true`, the selection
     *   completes immediately after the first entity is selected.
     *
     * This method does not use floating input boxes. Instead, it relies entirely on
     * mouse gestures and keyboard input. A floating prompt message and command line
     * prompt are displayed during the operation.
     *
     * @param options - Selection prompt options that control user messaging and
     *                  whether only a single entity may be selected.
     * @returns A promise that resolves to an array of selected entity IDs.
     *          The array is empty if no entities are selected and the user presses Enter.
     *          The promise is rejected if the operation is cancelled.
     */
    AcEdInputManager.prototype.getSelection = function (options) {
        return __awaiter(this, void 0, void 0, function () {
            var _this = this;
            return __generator(this, function (_a) {
                return [2 /*return*/, this.executePrompt(function () {
                        return new Promise(function (resolve, reject) {
                            _this.active = true;
                            _this.entitySelectionActive = true;
                            var keywordSession = _this.startKeywordSession(options, true);
                            if (!keywordSession) {
                                _this._commandLine.setPrompt(options.message);
                            }
                            var floatingMessage = new AcEdFloatingMessage(_this.view, {
                                parent: _this.view.canvas,
                                message: options.message
                            });
                            var selected = new Set();
                            var startWcs = null;
                            var startCanvas = null;
                            var previewEl = null;
                            var settled = false;
                            var cleanup = function () {
                                if (settled)
                                    return;
                                settled = true;
                                _this.active = false;
                                _this.entitySelectionActive = false;
                                floatingMessage === null || floatingMessage === void 0 ? void 0 : floatingMessage.dispose();
                                previewEl === null || previewEl === void 0 ? void 0 : previewEl.remove();
                                keywordSession === null || keywordSession === void 0 ? void 0 : keywordSession.cancel();
                                _this._commandLine.clear();
                                document.removeEventListener('keydown', keyHandler);
                                _this.view.canvas.removeEventListener('mousedown', mouseDown);
                                _this.view.canvas.removeEventListener('mousemove', mouseMove);
                                _this.view.canvas.removeEventListener('mouseup', mouseUp);
                                _this.view.canvas.removeEventListener('contextmenu', contextMenuHandler);
                            };
                            keywordSession === null || keywordSession === void 0 ? void 0 : keywordSession.promise.then(function (keyword) {
                                if (settled)
                                    return;
                                if (!keyword) {
                                    cleanup();
                                    reject(new Error('cancelled'));
                                    return;
                                }
                                cleanup();
                                reject(new AcEdKeywordInputError(keyword));
                            });
                            /** ---------- Keyboard ---------- */
                            var keyHandler = function (e) {
                                if (e.key === 'Escape') {
                                    cleanup();
                                    reject(new Error('cancelled'));
                                    return;
                                }
                                if (e.key === 'Enter') {
                                    cleanup();
                                    resolve(__spreadArray([], __read(selected), false));
                                }
                            };
                            /** ---------- Mouse ---------- */
                            var contextMenuHandler = function (e) {
                                if (_this.shouldUseRightClickEnter()) {
                                    e.preventDefault();
                                }
                            };
                            var mouseDown = function (e) {
                                if (e.button === 2) {
                                    if (_this.shouldUseRightClickEnter()) {
                                        e.preventDefault();
                                        cleanup();
                                        resolve(__spreadArray([], __read(selected), false));
                                    }
                                    return;
                                }
                                if (e.button !== 0)
                                    return;
                                startCanvas = _this.view.viewportToCanvas({
                                    x: e.clientX,
                                    y: e.clientY
                                });
                                startWcs = _this.view.screenToWorld(startCanvas);
                                previewEl = document.createElement('div');
                                previewEl.className = 'ml-jig-preview-rect';
                                _this.view.container.appendChild(previewEl);
                            };
                            var mouseMove = function (e) {
                                if (e.buttons !== 1)
                                    return;
                                if (!startWcs || !previewEl || !startCanvas)
                                    return;
                                var curWcs = _this.view.screenToWorld(_this.view.viewportToCanvas({ x: e.clientX, y: e.clientY }));
                                var curCanvas = _this.view.viewportToCanvas({
                                    x: e.clientX,
                                    y: e.clientY
                                });
                                var p1 = _this.view.worldToScreen(startWcs);
                                var p2 = _this.view.worldToScreen(curWcs);
                                var left = Math.min(p1.x, p2.x);
                                var top = Math.min(p1.y, p2.y);
                                var width = Math.abs(p1.x - p2.x);
                                var height = Math.abs(p1.y - p2.y);
                                var mode = _this.view.getSelectionMode(startCanvas, curCanvas);
                                var action = _this.view.getSelectionActionFromEvent(e, 'add');
                                var style = _this.view.getSelectionPreviewStyle(mode, action);
                                Object.assign(previewEl.style, {
                                    left: "".concat(left, "px"),
                                    top: "".concat(top, "px"),
                                    width: "".concat(width, "px"),
                                    height: "".concat(height, "px"),
                                    borderStyle: style.borderStyle,
                                    background: style.background
                                });
                                previewEl.style.setProperty('--line-color', style.lineColor);
                            };
                            var mouseUp = function (e) {
                                var e_2, _a;
                                if (e.button !== 0)
                                    return;
                                if (!startWcs || !startCanvas)
                                    return;
                                var endWcs = _this.view.screenToWorld(_this.view.viewportToCanvas({ x: e.clientX, y: e.clientY }));
                                var endCanvas = _this.view.viewportToCanvas({
                                    x: e.clientX,
                                    y: e.clientY
                                });
                                previewEl === null || previewEl === void 0 ? void 0 : previewEl.remove();
                                previewEl = null;
                                // Click selection
                                var action = _this.view.getSelectionActionFromEvent(e, 'add');
                                if (_this.view.isSelectionClick(startCanvas, endCanvas)) {
                                    var picked = _this.view.pick(endWcs);
                                    if (picked.length > 0) {
                                        _this.view.applySelection([picked[0].id], action);
                                    }
                                    else if (action === 'replace') {
                                        _this.view.selectionSet.clear();
                                    }
                                }
                                else {
                                    // Box selection
                                    var box = new AcGeBox2d()
                                        .expandByPoint(startWcs)
                                        .expandByPoint(endWcs);
                                    var mode = _this.view.getSelectionMode(startCanvas, endCanvas);
                                    _this.view.selectByBoxWithMode(box, mode, action);
                                }
                                selected.clear();
                                try {
                                    for (var _b = __values(_this.view.selectionSet.ids), _c = _b.next(); !_c.done; _c = _b.next()) {
                                        var id = _c.value;
                                        selected.add(id);
                                    }
                                }
                                catch (e_2_1) { e_2 = { error: e_2_1 }; }
                                finally {
                                    try {
                                        if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
                                    }
                                    finally { if (e_2) throw e_2.error; }
                                }
                                if (options.singleOnly && action !== 'remove') {
                                    if (selected.size > 0) {
                                        cleanup();
                                        resolve(__spreadArray([], __read(selected), false));
                                    }
                                }
                                startWcs = null;
                                startCanvas = null;
                            };
                            document.addEventListener('keydown', keyHandler);
                            _this.view.canvas.addEventListener('mousedown', mouseDown);
                            _this.view.canvas.addEventListener('mousemove', mouseMove);
                            _this.view.canvas.addEventListener('mouseup', mouseUp);
                            _this.view.canvas.addEventListener('contextmenu', contextMenuHandler);
                        });
                    }, function (value) {
                        return new AcEdPromptSelectionResult(AcEdPromptStatus.OK, new AcEdSelectionSet(value));
                    }, function (status) { return new AcEdPromptSelectionResult(status); }, { none: false })];
            });
        });
    };
    /**
     * Prompts the user to select a single entity.
     *
     * Selection is performed by clicking in the view and validating the first
     * hit-tested entity under the cursor. The picked entity may be rejected when
     * it belongs to a locked layer or does not satisfy the prompt's allowed-class
     * filter, in which case the rejection message is shown and the prompt remains
     * active. Keywords and `AllowNone` behavior are also supported.
     *
     * @param options - Entity prompt options controlling filtering, messaging, and keywords
     * @returns A prompt result containing the selected entity id, picked point,
     * cancel status, or keyword
     */
    AcEdInputManager.prototype.getEntity = function (options) {
        return __awaiter(this, void 0, void 0, function () {
            var pickedPoint;
            var _this = this;
            return __generator(this, function (_a) {
                return [2 /*return*/, this.executePrompt(function () {
                        return new Promise(function (resolve, reject) {
                            _this.active = true;
                            _this.entitySelectionActive = true;
                            var keywordSession = _this.startKeywordSession(options, true);
                            var floatingMessage = new AcEdFloatingMessage(_this.view, {
                                parent: _this.view.canvas,
                                message: options.message
                            });
                            if (!keywordSession) {
                                _this._commandLine.setPrompt(options.message);
                            }
                            var settled = false;
                            var cleanup = function () {
                                var _a;
                                if (settled)
                                    return;
                                settled = true;
                                _this.active = false;
                                _this.entitySelectionActive = false;
                                (_a = options.jig) === null || _a === void 0 ? void 0 : _a.end();
                                document.removeEventListener('keydown', keyHandler);
                                _this.view.canvas.removeEventListener('mousedown', clickHandler);
                                _this.view.canvas.removeEventListener('contextmenu', contextMenuHandler);
                                floatingMessage === null || floatingMessage === void 0 ? void 0 : floatingMessage.dispose();
                                keywordSession === null || keywordSession === void 0 ? void 0 : keywordSession.cancel();
                                _this._commandLine.clear();
                            };
                            keywordSession === null || keywordSession === void 0 ? void 0 : keywordSession.promise.then(function (keyword) {
                                if (settled)
                                    return;
                                if (!keyword) {
                                    cleanup();
                                    reject(new Error('cancelled'));
                                    return;
                                }
                                cleanup();
                                reject(new AcEdKeywordInputError(keyword));
                            });
                            /** Mouse click → try select entity */
                            var clickHandler = function (e) {
                                if (e.button === 2) {
                                    if (_this.shouldUseRightClickEnter() && options.allowNone) {
                                        e.preventDefault();
                                        cleanup();
                                        resolve(null);
                                    }
                                    return;
                                }
                                if (e.button !== 0)
                                    return;
                                var pos = _this.view.screenToWorld(_this.view.viewportToCanvas({ x: e.clientX, y: e.clientY }));
                                var picked = _this.view.pick(pos, undefined, true);
                                // Clicked empty space
                                if (picked.length == 0) {
                                    _this._commandLine.showError(options.rejectMessage);
                                    return;
                                }
                                var entity = _this.getEntityById(picked[0].id);
                                if (!entity) {
                                    _this._commandLine.showError(options.rejectMessage);
                                    return;
                                }
                                if (!options.allowObjectOnLockedLayer &&
                                    _this.isEntityOnLockedLayer(entity)) {
                                    _this._commandLine.showError(options.rejectMessage);
                                    return;
                                }
                                if (!_this.isEntityClassAllowed(entity, options)) {
                                    _this._commandLine.showError(options.rejectMessage);
                                    return;
                                }
                                pickedPoint = { x: pos.x, y: pos.y, z: 0 };
                                cleanup();
                                resolve(picked[0].id);
                            };
                            /** Keyboard handling */
                            var keyHandler = function (e) {
                                if (e.key === 'Escape') {
                                    cleanup();
                                    reject(new Error('cancelled'));
                                    return;
                                }
                                if (e.key === 'Enter' && options.allowNone) {
                                    cleanup();
                                    resolve(null);
                                }
                            };
                            var contextMenuHandler = function (e) {
                                if (_this.shouldUseRightClickEnter()) {
                                    e.preventDefault();
                                }
                            };
                            document.addEventListener('keydown', keyHandler);
                            _this.view.canvas.addEventListener('mousedown', clickHandler);
                            _this.view.canvas.addEventListener('contextmenu', contextMenuHandler);
                        });
                    }, function (value) {
                        return new AcEdPromptEntityResult(AcEdPromptStatus.OK, value || undefined, pickedPoint);
                    }, function (status) { return new AcEdPromptEntityResult(status); }, { none: false })];
            });
        });
    };
    /**
     * Prompt the user to specify a rectangular box by selecting two corners.
     * Each corner may be specified by clicking on the canvas or typing "x,y".
     * A live HTML overlay rectangle previews the box as the user moves the mouse.
     *
     * The box prompt is implemented as two chained point prompts. Keywords from
     * the original box prompt are copied into each corner prompt so the caller
     * sees a consistent interaction model across both stages.
     *
     * @param options - Box prompt options controlling corner messages, preview behavior, and keywords
     * @returns A prompt result containing the final 2D box, cancel status, or keyword
     */
    AcEdInputManager.prototype.getBox = function (options) {
        return __awaiter(this, void 0, void 0, function () {
            var _this = this;
            return __generator(this, function (_a) {
                return [2 /*return*/, this.executePrompt(function () { return __awaiter(_this, void 0, void 0, function () {
                        var message1, options1, p1Result, p1, cwcsP1, previewEl, cleanup, drawPreview, message2, options2, p2, box;
                        var _this = this;
                        return __generator(this, function (_a) {
                            switch (_a.label) {
                                case 0:
                                    message1 = options.firstCornerMessage ||
                                        AcApI18n.t('main.inputManager.firstCorner');
                                    options1 = new AcEdPromptPointOptions(message1);
                                    this.copyKeywords(options, options1);
                                    options1.useDashedLine = options.useDashedLine;
                                    options1.useBasePoint = options.useBasePoint;
                                    return [4 /*yield*/, this.getPoint(options1)];
                                case 1:
                                    p1Result = _a.sent();
                                    if (p1Result.status !== AcEdPromptStatus.OK) {
                                        return [2 /*return*/, new AcEdPromptBoxResult(p1Result.status, undefined, p1Result.stringResult)];
                                    }
                                    p1 = p1Result.value;
                                    cwcsP1 = this.view.worldToScreen(p1);
                                    previewEl = document.createElement('div');
                                    previewEl.className = 'ml-jig-preview-rect';
                                    this.view.container.appendChild(previewEl);
                                    cleanup = function () {
                                        previewEl.remove();
                                    };
                                    drawPreview = function (pos) {
                                        var cwcsP2 = _this.view.worldToScreen(pos);
                                        var left = Math.min(cwcsP2.x, cwcsP1.x);
                                        var top = Math.min(cwcsP2.y, cwcsP1.y);
                                        var width = Math.abs(cwcsP2.x - cwcsP1.x);
                                        var height = Math.abs(cwcsP2.y - cwcsP1.y);
                                        Object.assign(previewEl.style, {
                                            left: "".concat(left, "px"),
                                            top: "".concat(top, "px"),
                                            width: "".concat(width, "px"),
                                            height: "".concat(height, "px")
                                        });
                                    };
                                    message2 = options.secondCornerMessage ||
                                        AcApI18n.t('main.inputManager.secondCorner');
                                    options2 = new AcEdPromptPointOptions(message2);
                                    this.copyKeywords(options, options2);
                                    options2.useDashedLine = options.useDashedLine;
                                    options2.useBasePoint = options.useBasePoint;
                                    return [4 /*yield*/, this.getPointInternal(options2, cleanup, drawPreview)];
                                case 2:
                                    p2 = _a.sent();
                                    box = new AcGeBox2d().expandByPoint(p1).expandByPoint(p2);
                                    return [2 /*return*/, new AcEdPromptBoxResult(AcEdPromptStatus.OK, box)];
                            }
                        });
                    }); }, function (value) { return value; }, function (status) { return new AcEdPromptBoxResult(status); })];
            });
        });
    };
    /**
     * Shared point input logic used by getPoint() and getBox(). Accepts "x,y"
     * typed input OR mouse click.
     *
     * This helper optionally wires extra cleanup and preview callbacks so
     * higher-level workflows can overlay additional temporary graphics while
     * reusing the same point acquisition behavior.
     *
     * @param options - Point prompt options controlling the interaction
     * @param cleanup - Optional callback invoked when the point prompt ends
     * @param drawPreview - Optional callback invoked as the cursor moves for live preview rendering
     * @returns A promise that resolves to the chosen point
     */
    AcEdInputManager.prototype.getPointInternal = function (options, cleanup, drawPreview) {
        return __awaiter(this, void 0, void 0, function () {
            var scriptedValue, getDynamicValue, handler;
            var _this = this;
            return __generator(this, function (_a) {
                scriptedValue = this.tryGetScriptedPoint(options);
                if (scriptedValue != null) {
                    cleanup === null || cleanup === void 0 ? void 0 : cleanup();
                    return [2 /*return*/, Promise.resolve(scriptedValue)];
                }
                getDynamicValue = function (pos) {
                    return {
                        value: { x: pos.x, y: pos.y, z: 0 },
                        raw: {
                            x: _this.formatNumber(pos.x, 'point'),
                            y: _this.formatNumber(pos.y, 'point')
                        }
                    };
                };
                handler = new AcEdPointHandler(options);
                return [2 /*return*/, this.makeFloatingInputPromise({
                        inputCount: 2,
                        promptOptions: options,
                        cleanup: cleanup,
                        handler: handler,
                        getDynamicValue: getDynamicValue,
                        drawPreview: drawPreview
                    })];
            });
        });
    };
    /**
     * Attempts to consume one scripted input and parse it as a point.
     * Supported forms: "x,y", "x,y,z", or "x y".
     *
     * Successful scripted points also update `lastPoint` so subsequent prompts
     * that rely on prior geometric context behave the same way as with manual
     * point picking.
     *
     * @param options - Point prompt options used to validate the scripted coordinates
     * @returns Parsed point value, or `undefined` when no scripted token is queued
     * @throws Error if a queued scripted token cannot be parsed as a valid point
     */
    AcEdInputManager.prototype.tryGetScriptedPoint = function (options) {
        var token = this.dequeueScriptInput();
        if (token === undefined)
            return undefined;
        var trimmed = token.trim();
        if (!trimmed && options.allowNone) {
            throw new AcEdNoneInputError();
        }
        var keyword = options.keywords.findByName(trimmed);
        if (keyword) {
            throw new AcEdKeywordInputError(keyword.globalName);
        }
        var parsed = this.splitScriptedPoint(token);
        if (!parsed) {
            throw new Error("Invalid point input '".concat(token, "'"));
        }
        var value = new AcEdPointHandler(options).parse(parsed.x, parsed.y);
        if (value == null) {
            throw new Error("Invalid point input '".concat(token, "'"));
        }
        this.lastPoint = { x: value.x, y: value.y };
        return value;
    };
    /**
     * Attempts to consume one scripted input and parse it with the supplied handler.
     *
     * Scripted input is used to emulate command-line entry in automated or
     * replayed workflows. This helper keeps the parsing path consistent with
     * interactive input by delegating to the same handler implementation used by
     * the floating-input UI.
     *
     * @typeParam T - Parsed value type
     * @param handler - Input handler used to parse the queued token
     * @returns Parsed value, or `undefined` when no scripted token is available
     * @throws Error if a queued token exists but fails validation
     */
    AcEdInputManager.prototype.tryGetScriptedValue = function (handler) {
        var token = this.dequeueScriptInput();
        if (token === undefined)
            return undefined;
        var value = handler.parse(token);
        if (value == null) {
            throw new Error("Invalid scripted input '".concat(token, "'"));
        }
        return value;
    };
    /**
     * Attempts to consume one scripted numeric token.
     *
     * This is a thin specialization of {@link tryGetScriptedValue} that narrows
     * the accepted handler types to those used by numeric-style prompts.
     *
     * @param handler - Numeric handler used to parse the queued token
     * @returns Parsed numeric value, or `undefined` when no scripted token is queued
     */
    AcEdInputManager.prototype.tryGetScriptedNumber = function (handler) {
        return this.tryGetScriptedValue(handler);
    };
    /**
     * Removes and returns the next queued scripted input token.
     *
     * @returns The next scripted token, or `undefined` when the queue is empty
     */
    AcEdInputManager.prototype.dequeueScriptInput = function () {
        if (!this._scriptInputs.length)
            return undefined;
        return this._scriptInputs.shift();
    };
    /**
     * Splits a scripted point token into x/y coordinate components.
     *
     * The accepted formats intentionally mirror common CAD command-line point
     * entry conventions, including comma-separated coordinates and whitespace-
     * separated coordinates. An optional third `z` component is tolerated for
     * compatibility, but only the `x` and `y` values are used by 2D prompts.
     *
     * @param token - Raw scripted point token
     * @returns Extracted x/y string pair, or `undefined` if the token is malformed
     */
    AcEdInputManager.prototype.splitScriptedPoint = function (token) {
        var trimmed = token.trim();
        if (!trimmed)
            return undefined;
        if (trimmed.includes(',')) {
            var parts_1 = trimmed.split(',').map(function (v) { return v.trim(); });
            if (parts_1.length !== 2 && parts_1.length !== 3)
                return undefined;
            if (parts_1.length === 3 && Number.isNaN(Number(parts_1[2])))
                return undefined;
            return { x: parts_1[0], y: parts_1[1] };
        }
        var parts = trimmed.split(/\s+/);
        if (parts.length < 2)
            return undefined;
        return { x: parts[0], y: parts[1] };
    };
    /**
     * Returns whether an unknown error value represents prompt cancellation.
     *
     * Prompt flows normalize cancellation to a regular `Error` with the message
     * `'cancelled'`. This helper keeps the outer result-conversion code concise
     * and consistent across prompt types.
     *
     * @param error - Unknown error value thrown from an input workflow
     * @returns `true` if the error represents prompt cancellation
     */
    AcEdInputManager.prototype.isPromptCancelled = function (error) {
        return error instanceof Error && error.message === 'cancelled';
    };
    /**
     * Returns whether an unknown error value represents PromptStatus.None.
     *
     * @param error - Unknown error value thrown from an input workflow
     * @returns `true` if the error represents "no input" confirmation
     */
    AcEdInputManager.prototype.isPromptNone = function (error) {
        return error instanceof AcEdNoneInputError;
    };
    /**
     * Reads SHORTCUTMENU value from current working database.
     *
     * @returns Normalized 0..3 shortcut-menu mode
     */
    AcEdInputManager.prototype.getShortcutMenuMode = function () {
        var db = acdbHostApplicationServices().workingDatabase;
        var raw = AcDbSysVarManager.instance().getVar(AcDbSystemVariables.SHORTCUTMENU, db);
        var value = Math.trunc(Number(raw));
        if (Number.isNaN(value))
            return 0;
        var normalized = value & 0x3;
        return normalized;
    };
    /**
     * Resolves right-click behavior for current prompt session.
     *
     * SHORTCUTMENU:
     * 0 => always Enter
     * 1 => Enter in command, menu when idle
     * 2 => menu in command
     * 3 => always menu
     */
    AcEdInputManager.prototype.shouldUseRightClickEnter = function () {
        var mode = this.getShortcutMenuMode();
        if (mode === 0)
            return true;
        if (mode === 1)
            return this.active;
        return false;
    };
    /**
     * Synchronizes the stored modifier-key snapshot with a DOM keyboard event.
     *
     * Floating preview rendering depends on modifier state for behaviors such as
     * temporary mode switches. This helper updates the cached modifier snapshot
     * and reports whether anything actually changed so callers can avoid
     * unnecessary preview refreshes.
     *
     * @param e - Keyboard-like event carrying modifier-key flags
     * @returns `true` if any modifier flag changed; otherwise `false`
     */
    AcEdInputManager.prototype.updateModifierStateFromEvent = function (e) {
        var next = {
            ctrlKey: !!e.ctrlKey,
            shiftKey: !!e.shiftKey,
            altKey: !!e.altKey,
            metaKey: !!e.metaKey
        };
        var prev = this._modifierState;
        var changed = prev.ctrlKey !== next.ctrlKey ||
            prev.shiftKey !== next.shiftKey ||
            prev.altKey !== next.altKey ||
            prev.metaKey !== next.metaKey;
        if (changed) {
            this._modifierState = next;
        }
        return changed;
    };
    /**
     * Handles the sticky Ctrl toggle used by certain jig interactions.
     *
     * Instead of tracking Ctrl as a purely held modifier, some commands treat a
     * Ctrl key press as a persistent toggle. This helper flips that toggle on the
     * first non-repeating keydown event for the Control key.
     *
     * @param e - Keyboard event to inspect
     * @returns `true` if the toggle state changed and previews should refresh
     */
    AcEdInputManager.prototype.handleCtrlToggleKey = function (e) {
        if (e.key !== 'Control' || e.repeat)
            return false;
        if (e.type !== 'keydown')
            return false;
        this._ctrlArcFlip = !this._ctrlArcFlip;
        return true;
    };
    /**
     * Extracts cross-prompt defaults from a prompt options object.
     *
     * Not every prompt type exposes the same optional properties, but the
     * floating-input pipeline needs a normalized shape for values such as base
     * point, dashed-baseline behavior, jig, and base angle. This helper performs
     * those property-existence checks in one place.
     *
     * @typeParam T - Value type produced by the prompt
     * @param options - Prompt options to normalize
     * @returns A normalized object containing only the floating-input defaults it understands
     */
    AcEdInputManager.prototype.resolvePromptDefaults = function (options) {
        var hasBasePoint = 'basePoint' in options;
        var hasUseBasePoint = 'useBasePoint' in options;
        var hasUseDashedLine = 'useDashedLine' in options;
        var hasBaseAngle = 'baseAngle' in options;
        var basePoint = hasBasePoint && options.basePoint
            ? options.basePoint
            : undefined;
        var useBasePoint = hasUseBasePoint ? options.useBasePoint : false;
        var showBaseLineOnly = hasUseDashedLine ? !options.useDashedLine : false;
        var baseAngle = hasBaseAngle ? options.baseAngle : undefined;
        return {
            message: options.message,
            jig: options.jig,
            basePoint: basePoint,
            useBasePoint: useBasePoint,
            showBaseLineOnly: showBaseLineOnly,
            baseAngle: baseAngle
        };
    };
    /**
     * Runs a floating-input prompt and resolves it to a parsed value.
     *
     * This is the core interaction primitive used by most non-selection prompts.
     * It wires together command-line keyword handling, floating input creation,
     * validation, preview refreshes, jig updates, cancellation handling, and
     * cleanup. The method guarantees that temporary UI and event listeners are
     * torn down no matter how the prompt completes.
     *
     * @typeParam T - Value type produced by the prompt
     * @param options - Configuration describing how the floating prompt should parse,
     * validate, preview, and commit its value
     * @returns A promise that resolves with the committed value or rejects on cancel/keyword
     */
    AcEdInputManager.prototype.makeFloatingInputPromise = function (options) {
        return __awaiter(this, void 0, void 0, function () {
            var _this = this;
            return __generator(this, function (_a) {
                return [2 /*return*/, new Promise(function (resolve, reject) {
                        _this.active = true;
                        _this.entitySelectionActive = false;
                        var settled = false;
                        var validate = function (raw) {
                            var value = options.handler.parse(raw.x, raw.y);
                            return {
                                isValid: value != null,
                                value: value !== null && value !== void 0 ? value : undefined
                            };
                        };
                        var promptDefaults = _this.resolvePromptDefaults(options.promptOptions);
                        var keywordSession = _this.startKeywordSession(options.promptOptions, true);
                        var basePoint = undefined;
                        if (promptDefaults.useBasePoint) {
                            if (promptDefaults.basePoint) {
                                basePoint = promptDefaults.basePoint;
                            }
                            else if (_this.lastPoint) {
                                basePoint = { x: _this.lastPoint.x, y: _this.lastPoint.y };
                            }
                        }
                        var commandLineMessage = promptDefaults.message;
                        if (!keywordSession) {
                            _this._commandLine.setPrompt(commandLineMessage);
                        }
                        var allowNone = 'allowNone' in options.promptOptions
                            ? options.promptOptions.allowNone
                            : false;
                        var defaultBehavior = _this.resolvePromptDefaultValue(options.promptOptions);
                        var floatingInput = new AcEdFloatingInput(_this.view, {
                            parent: _this.view.canvas,
                            inputCount: options.inputCount,
                            message: promptDefaults.message,
                            disableOSnap: options.disableOSnap,
                            showBaseLineOnly: promptDefaults.showBaseLineOnly,
                            basePoint: basePoint,
                            baseAngle: promptDefaults.baseAngle,
                            allowPrompt: options.allowPrompt !== false,
                            allowNone: allowNone,
                            useDefaultValue: defaultBehavior.useDefaultValue,
                            defaultValue: defaultBehavior.defaultValue,
                            validate: validate,
                            getDynamicValue: options.getDynamicValue,
                            drawPreview: function (pos) {
                                var _a;
                                if (promptDefaults.jig) {
                                    var defaults = options.getDynamicValue(pos);
                                    promptDefaults.jig.update(defaults.value);
                                    promptDefaults.jig.render();
                                }
                                (_a = options.drawPreview) === null || _a === void 0 ? void 0 : _a.call(options, pos);
                            },
                            onCommit: function (val) {
                                var result = false;
                                if (!options.onCommit || options.onCommit(val)) {
                                    resolver(val);
                                    result = true;
                                }
                                if (floatingInput.lastPoint) {
                                    _this.lastPoint = {
                                        x: floatingInput.lastPoint.x,
                                        y: floatingInput.lastPoint.y
                                    };
                                }
                                return result;
                            },
                            onCancel: function () { return rejector(); },
                            onNone: function () { return noneRejector(); }
                        });
                        var cleanup = function () {
                            var _a, _b;
                            if (settled)
                                return;
                            settled = true;
                            _this.active = false;
                            _this.entitySelectionActive = false;
                            (_a = options.cleanup) === null || _a === void 0 ? void 0 : _a.call(options);
                            (_b = promptDefaults.jig) === null || _b === void 0 ? void 0 : _b.end();
                            document.removeEventListener('keydown', escHandler);
                            document.removeEventListener('keydown', modifierHandler);
                            document.removeEventListener('keyup', modifierHandler);
                            _this.view.canvas.removeEventListener('contextmenu', contextMenuHandler);
                            floatingInput.dispose();
                            keywordSession === null || keywordSession === void 0 ? void 0 : keywordSession.cancel();
                            _this._commandLine.clear();
                        };
                        var resolver = function (value) {
                            cleanup();
                            resolve(value);
                        };
                        var rejector = function (err) {
                            cleanup();
                            reject(err !== null && err !== void 0 ? err : new Error('cancelled'));
                        };
                        var noneRejector = function () {
                            rejector(new AcEdNoneInputError());
                        };
                        var keywordRejector = function (keyword) {
                            rejector(new AcEdKeywordInputError(keyword));
                        };
                        var escHandler = function (e) {
                            if (e.key === 'Escape') {
                                rejector();
                            }
                        };
                        var modifierHandler = function (e) {
                            var toggled = _this.handleCtrlToggleKey(e);
                            var changed = _this.updateModifierStateFromEvent(e);
                            if (toggled || changed) {
                                floatingInput.requestPreviewRefresh();
                            }
                        };
                        var contextMenuHandler = function (e) {
                            if (!_this.shouldUseRightClickEnter())
                                return;
                            e.preventDefault();
                            noneRejector();
                        };
                        document.addEventListener('keydown', escHandler);
                        document.addEventListener('keydown', modifierHandler);
                        document.addEventListener('keyup', modifierHandler);
                        _this.view.canvas.addEventListener('contextmenu', contextMenuHandler);
                        // showAt() expects viewport coordinates; curMousePos is canvas-local.
                        floatingInput.showAt(_this.view.canvasToViewport(_this.view.curMousePos));
                        keywordSession === null || keywordSession === void 0 ? void 0 : keywordSession.promise.then(function (keyword) {
                            if (settled)
                                return;
                            if (!keyword) {
                                rejector();
                                return;
                            }
                            keywordRejector(keyword);
                        });
                    })];
            });
        });
    };
    /** Inject styles only once */
    AcEdInputManager.stylesInjected = false;
    return AcEdInputManager;
}());
export { AcEdInputManager };
//# sourceMappingURL=AcEdInputManager.js.map