"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Tools
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.DefineACSByPointsTool = exports.DefineACSByElementTool = exports.AccuDrawRotatePerpendicularTool = exports.AccuDrawRotateElementTool = exports.AccuDrawRotateAxesTool = exports.AccuDrawRotateViewTool = exports.AccuDrawRotateSideTool = exports.AccuDrawRotateFrontTool = exports.AccuDrawRotateTopTool = exports.AccuDrawRotateCycleTool = exports.AccuDrawChangeModeTool = exports.AccuDrawSetLockAngleTool = exports.AccuDrawSetLockDistanceTool = exports.AccuDrawSetLockZTool = exports.AccuDrawSetLockYTool = exports.AccuDrawSetLockXTool = exports.AccuDrawSetLockIndexTool = exports.AccuDrawSetLockSmartTool = exports.AccuDrawSetOriginTool = exports.AccuDrawSuspendToggleTool = exports.AccuDrawSessionToggleTool = exports.AccuDrawShortcuts = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const core_geometry_1 = require("@itwin/core-geometry");
const AccuDraw_1 = require("../AccuDraw");
const AccuSnap_1 = require("../AccuSnap");
const AuxCoordSys_1 = require("../AuxCoordSys");
const HitDetail_1 = require("../HitDetail");
const IModelApp_1 = require("../IModelApp");
const Tool_1 = require("./Tool");
// cSpell:ignore dont unlockedz
function normalizedDifference(point1, point2, out) {
    return point2.vectorTo(point1).normalizeWithLength(out).mag;
}
function normalizedCrossProduct(vec1, vec2, out) {
    return vec1.crossProduct(vec2, out).normalizeWithLength(out).mag;
}
/**
 * A shortcut may require no user input (immediate) or it may install a tool to collect the needed input. AccuDrawShortcuts are how users control AccuDraw.
 * A tool implementor should not use this class to setup AccuDraw, instead use AccuDrawHintBuilder to provide hints.
 * @alpha
 */
class AccuDrawShortcuts {
    /** Disable/Enable AccuDraw for the session */
    static sessionToggle() {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (accudraw.isEnabled)
            accudraw.disableForSession();
        else
            accudraw.enableForSession();
    }
    /** Suspend/Unsuspend AccuDraw for the active tool */
    static suspendToggle() {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        if (accudraw.isActive)
            accudraw.deactivate();
        else
            accudraw.activate();
        accudraw.refreshDecorationsAndDynamics();
    }
    static rotateAxesByPoint(isSnapped, aboutCurrentZ) {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return false;
        const vp = accudraw.currentView;
        if (!vp)
            return false;
        const point = accudraw.point;
        if (!vp.view.is3d())
            point.z = 0.0;
        if (aboutCurrentZ)
            accudraw.hardConstructionPlane(point, point, accudraw.planePt, accudraw.axes.z, vp, isSnapped);
        else
            accudraw.softConstructionPlane(point, point, accudraw.planePt, accudraw.axes.z, vp, isSnapped);
        // Snap point and compass origin coincide...
        const xVec = new core_geometry_1.Vector3d();
        if (normalizedDifference(point, accudraw.planePt, xVec) < core_geometry_1.Geometry.smallAngleRadians)
            return false;
        accudraw.axes.x.setFrom(xVec);
        if (AccuDraw_1.RotationMode.Context !== accudraw.rotationMode)
            accudraw.setRotationMode(AccuDraw_1.RotationMode.Context);
        accudraw.flags.contextRotMode = AccuDraw_1.ContextMode.XAxis;
        accudraw.flags.lockedRotation = false;
        accudraw.updateRotation();
        // Always want index line to display for x-Axis...changing rotation clears this...so it flashes...
        accudraw.indexed |= AccuDraw_1.LockedStates.X_BM;
        return true;
    }
    static updateACSByPoints(acs, vp, points, isDynamics) {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return false;
        let accept = false;
        const vec = [new core_geometry_1.Vector3d(), new core_geometry_1.Vector3d(), new core_geometry_1.Vector3d()];
        acs.setOrigin(points[0]);
        switch (points.length) {
            case 1:
                acs.setRotation(vp.rotation);
                if (!isDynamics) {
                    accudraw.published.origin.setFrom(points[0]);
                    accudraw.published.flags = AccuDraw_1.AccuDrawFlags.SetOrigin;
                    accudraw.flags.fixedOrg = true;
                }
                break;
            case 2:
                if (normalizedDifference(points[1], points[0], vec[0]) < 0.00001) {
                    accept = true;
                    break;
                }
                if (vp.view.is3d()) {
                    if (normalizedCrossProduct(accudraw.axes.y, vec[0], vec[1]) < 0.00001) {
                        vec[2].set(0.0, 0.0, 1.0);
                        if (normalizedCrossProduct(vec[2], vec[0], vec[1]) < 0.00001) {
                            vec[2].set(0.0, 1.0, 0.0);
                            normalizedCrossProduct(vec[2], vec[0], vec[1]);
                        }
                    }
                    normalizedCrossProduct(vec[0], vec[1], vec[2]);
                    acs.setRotation(core_geometry_1.Matrix3d.createRows(vec[0], vec[1], vec[2]));
                    if (!isDynamics) {
                        accudraw.published.origin.setFrom(points[0]);
                        accudraw.published.flags = AccuDraw_1.AccuDrawFlags.SetOrigin | AccuDraw_1.AccuDrawFlags.SetNormal;
                        accudraw.published.vector.setFrom(vec[0]);
                    }
                    break;
                }
                vec[2].set(0.0, 0.0, 1.0);
                normalizedCrossProduct(vec[2], vec[0], vec[1]);
                acs.setRotation(core_geometry_1.Matrix3d.createRows(vec[0], vec[1], vec[2]));
                accept = true;
                break;
            case 3:
                if (normalizedDifference(points[1], points[0], vec[0]) < 0.00001 ||
                    normalizedDifference(points[2], points[0], vec[1]) < 0.00001 ||
                    normalizedCrossProduct(vec[0], vec[1], vec[2]) < 0.00001) {
                    accept = true;
                    break;
                }
                normalizedCrossProduct(vec[2], vec[0], vec[1]);
                acs.setRotation(core_geometry_1.Matrix3d.createRows(vec[0], vec[1], vec[2]));
                accept = true;
                break;
        }
        return accept;
    }
    static processPendingHints() { IModelApp_1.IModelApp.accuDraw.processHints(); }
    static requestInputFocus() {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        accudraw.grabInputFocus();
        accudraw.refreshDecorationsAndDynamics();
    }
    // Helper method for GUI implementation...
    static async itemFieldNavigate(index, str, forward) {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        if (accudraw.getFieldLock(index))
            accudraw.saveCoordinate(index, accudraw.getValueByIndex(index));
        if (!accudraw.isActive && AccuDraw_1.KeyinStatus.Partial === accudraw.getKeyinStatus(index)) {
            await accudraw.processFieldInput(index, str, true);
        }
        else {
            accudraw.setKeyinStatus(index, AccuDraw_1.KeyinStatus.Dynamic);
            accudraw.onFieldValueChange(index);
        }
        const vp = accudraw.currentView;
        const is3d = vp ? vp.view.is3d() : false;
        const isPolar = (AccuDraw_1.CompassMode.Polar === accudraw.compassMode);
        switch (index) {
            case AccuDraw_1.ItemField.DIST_Item:
                index = ((is3d && !forward) ? AccuDraw_1.ItemField.Z_Item : AccuDraw_1.ItemField.ANGLE_Item);
                break;
            case AccuDraw_1.ItemField.ANGLE_Item:
                index = ((is3d && forward) ? AccuDraw_1.ItemField.Z_Item : AccuDraw_1.ItemField.DIST_Item);
                break;
            case AccuDraw_1.ItemField.X_Item:
                index = ((is3d && !forward) ? AccuDraw_1.ItemField.Z_Item : AccuDraw_1.ItemField.Y_Item);
                break;
            case AccuDraw_1.ItemField.Y_Item:
                index = ((is3d && forward) ? AccuDraw_1.ItemField.Z_Item : AccuDraw_1.ItemField.X_Item);
                break;
            case AccuDraw_1.ItemField.Z_Item:
                index = (forward ? (isPolar ? AccuDraw_1.ItemField.DIST_Item : AccuDraw_1.ItemField.X_Item) : (isPolar ? AccuDraw_1.ItemField.ANGLE_Item : AccuDraw_1.ItemField.Y_Item));
                break;
        }
        accudraw.setKeyinStatus(index, AccuDraw_1.KeyinStatus.Partial);
        accudraw.setFocusItem(index);
        accudraw.dontMoveFocus = true;
    }
    static itemFieldNewInput(index) { IModelApp_1.IModelApp.accuDraw.setKeyinStatus(index, AccuDraw_1.KeyinStatus.Partial); }
    static async itemFieldAcceptInput(index, str) {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        await accudraw.processFieldInput(index, str, true);
        accudraw.setKeyinStatus(index, AccuDraw_1.KeyinStatus.Dynamic);
        if (accudraw.getFieldLock(index))
            accudraw.saveCoordinate(index, accudraw.getValueByIndex(index));
        const vp = accudraw.currentView;
        if (accudraw.isActive) {
            if (!vp)
                return;
            if (AccuDraw_1.CompassMode.Polar === accudraw.compassMode)
                accudraw.fixPointPolar(vp);
            else
                accudraw.fixPointRectangular(vp);
            accudraw.flags.dialogNeedsUpdate = true;
            return;
        }
        const is3d = vp ? vp.view.is3d() : false;
        const isPolar = (AccuDraw_1.CompassMode.Polar === accudraw.compassMode);
        switch (index) {
            case AccuDraw_1.ItemField.DIST_Item:
                index = AccuDraw_1.ItemField.ANGLE_Item;
                break;
            case AccuDraw_1.ItemField.ANGLE_Item:
                index = (is3d ? AccuDraw_1.ItemField.Z_Item : AccuDraw_1.ItemField.DIST_Item);
                break;
            case AccuDraw_1.ItemField.X_Item:
                index = AccuDraw_1.ItemField.Y_Item;
                break;
            case AccuDraw_1.ItemField.Y_Item:
                index = (is3d ? AccuDraw_1.ItemField.Z_Item : AccuDraw_1.ItemField.X_Item);
                break;
            case AccuDraw_1.ItemField.Z_Item:
                index = (isPolar ? AccuDraw_1.ItemField.DIST_Item : AccuDraw_1.ItemField.X_Item);
                break;
        }
        accudraw.setFocusItem(index);
    }
    static itemFieldLockToggle(index) {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        if (accudraw.getFieldLock(index)) {
            switch (index) {
                case AccuDraw_1.ItemField.DIST_Item:
                    accudraw.distanceLock(true, false);
                    break;
                case AccuDraw_1.ItemField.ANGLE_Item:
                    accudraw.angleLock();
                    break;
                case AccuDraw_1.ItemField.X_Item:
                    accudraw.clearTentative();
                    accudraw.locked |= AccuDraw_1.LockedStates.X_BM;
                    break;
                case AccuDraw_1.ItemField.Y_Item:
                    accudraw.clearTentative();
                    accudraw.locked |= AccuDraw_1.LockedStates.Y_BM;
                    break;
                case AccuDraw_1.ItemField.Z_Item:
                    accudraw.clearTentative();
                    break;
            }
            return;
        }
        switch (index) {
            case AccuDraw_1.ItemField.DIST_Item:
                accudraw.locked &= ~AccuDraw_1.LockedStates.DIST_BM;
                break;
            case AccuDraw_1.ItemField.ANGLE_Item:
                accudraw.locked &= ~AccuDraw_1.LockedStates.ANGLE_BM;
                break;
            case AccuDraw_1.ItemField.X_Item:
                accudraw.locked &= ~AccuDraw_1.LockedStates.X_BM;
                break;
            case AccuDraw_1.ItemField.Y_Item:
                accudraw.locked &= ~AccuDraw_1.LockedStates.Y_BM;
                break;
            case AccuDraw_1.ItemField.Z_Item:
                break;
        }
        accudraw.dontMoveFocus = false;
        accudraw.clearTentative();
    }
    static itemRotationModeChange(rotation) {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        const vp = accudraw.currentView;
        const is3d = vp ? vp.view.is3d() : true;
        if (!is3d && (AccuDraw_1.RotationMode.Front === rotation || AccuDraw_1.RotationMode.Side === rotation))
            accudraw.setRotationMode(AccuDraw_1.RotationMode.Top);
        accudraw.flags.baseRotation = rotation;
        accudraw.updateRotation(true);
    }
    // Shortcut implementations for GUI entry points...
    static setOrigin(explicitOrigin) {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        if (explicitOrigin) {
            accudraw.published.origin.setFrom(explicitOrigin);
            accudraw.flags.haveValidOrigin = true;
        }
        else if (accudraw.isInactive || accudraw.isDeactivated) {
            // If AccuSnap is active use adjusted snap point, otherwise use last data point...
            const snap = AccuSnap_1.TentativeOrAccuSnap.getCurrentSnap(false);
            if (undefined !== snap) {
                accudraw.published.origin.setFrom(snap.isPointAdjusted ? snap.adjustedPoint : snap.getPoint());
                accudraw.flags.haveValidOrigin = true;
            }
            else {
                const ev = new Tool_1.BeButtonEvent();
                IModelApp_1.IModelApp.toolAdmin.fillEventFromLastDataButton(ev);
                if (ev.viewport) {
                    accudraw.published.origin.setFrom(ev.point);
                    accudraw.flags.haveValidOrigin = true;
                }
                else {
                    // NOTE: If current point isn't valid setDefaultOrigin will be called...
                    accudraw.published.origin.setFrom(accudraw.point);
                }
            }
        }
        else {
            accudraw.published.origin.setFrom(accudraw.point);
            accudraw.flags.haveValidOrigin = true;
            accudraw.setLastPoint(accudraw.published.origin);
        }
        accudraw.clearTentative();
        const vp = accudraw.currentView;
        // NOTE: _AdjustPoint should have been called to have setup currentView...
        if (vp && !vp.view.is3d())
            accudraw.published.origin.z = 0.0;
        accudraw.origin.setFrom(accudraw.published.origin);
        accudraw.point.setFrom(accudraw.published.origin);
        accudraw.planePt.setFrom(accudraw.published.origin);
        accudraw.published.flags |= AccuDraw_1.AccuDrawFlags.SetOrigin;
        accudraw.activate();
        accudraw.refreshDecorationsAndDynamics();
    }
    static changeCompassMode() {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        let axisLockStatus = accudraw.locked & AccuDraw_1.LockedStates.XY_BM;
        if (axisLockStatus) {
            if (AccuDraw_1.CompassMode.Rectangular === accudraw.compassMode) {
                if (axisLockStatus & AccuDraw_1.LockedStates.X_BM && accudraw.delta.x !== 0.0)
                    axisLockStatus &= ~AccuDraw_1.LockedStates.X_BM;
                if (axisLockStatus & AccuDraw_1.LockedStates.Y_BM && accudraw.delta.y !== 0.0)
                    axisLockStatus &= ~AccuDraw_1.LockedStates.Y_BM;
            }
        }
        accudraw.changeCompassMode(true);
        if (axisLockStatus) {
            if (AccuDraw_1.CompassMode.Rectangular === accudraw.compassMode) {
                accudraw.delta.x = accudraw.delta.y = 0.0;
                if (axisLockStatus & AccuDraw_1.LockedStates.X_BM)
                    accudraw.setFieldLock(AccuDraw_1.ItemField.X_Item, true);
                else if (axisLockStatus & AccuDraw_1.LockedStates.Y_BM)
                    accudraw.setFieldLock(AccuDraw_1.ItemField.Y_Item, true);
            }
            else {
                accudraw.setFieldLock(AccuDraw_1.ItemField.ANGLE_Item, true);
            }
            accudraw.locked = axisLockStatus;
        }
        accudraw.flags.baseMode = accudraw.compassMode;
        accudraw.refreshDecorationsAndDynamics();
    }
    static lockSmart() {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        const accuSnap = IModelApp_1.IModelApp.accuSnap;
        // Don't want AccuSnap to influence axis or Z...
        if (accuSnap.isHot) {
            accuSnap.clear();
            const vp = accudraw.currentView;
            if (vp) {
                if (AccuDraw_1.CompassMode.Polar === accudraw.compassMode)
                    accudraw.fixPointPolar(vp);
                else
                    accudraw.fixPointRectangular(vp);
            }
        }
        if (AccuDraw_1.CompassMode.Polar === accudraw.compassMode) {
            const isSnapped = accudraw.clearTentative();
            if (accudraw.locked & AccuDraw_1.LockedStates.ANGLE_BM) { // angle locked (unlock it)
                accudraw.setFieldLock(AccuDraw_1.ItemField.ANGLE_Item, false);
                accudraw.locked &= ~AccuDraw_1.LockedStates.ANGLE_BM;
            }
            else if (accudraw.getFieldLock(AccuDraw_1.ItemField.DIST_Item)) { // distance locked (unlock it)
                accudraw.setFieldLock(AccuDraw_1.ItemField.DIST_Item, false);
                accudraw.locked &= ~AccuDraw_1.LockedStates.DIST_BM;
            }
            else if (isSnapped) {
                accudraw.doLockAngle(isSnapped);
            }
            else if (accudraw.indexed & AccuDraw_1.LockedStates.ANGLE_BM) { // angle indexed (lock it)
                accudraw.angleLock();
            }
            else {
                if (Math.abs(accudraw.vector.dotProduct(accudraw.axes.x)) > Math.abs(accudraw.vector.dotProduct(accudraw.axes.y)))
                    accudraw.indexed |= AccuDraw_1.LockedStates.Y_BM;
                else
                    accudraw.indexed |= AccuDraw_1.LockedStates.X_BM;
                accudraw.angleLock();
            }
            accudraw.refreshDecorationsAndDynamics();
            return;
        }
        if (accudraw.locked) { // if locked, unlock
            accudraw.clearTentative();
            accudraw.locked &= ~AccuDraw_1.LockedStates.XY_BM;
            accudraw.setFieldLock(AccuDraw_1.ItemField.X_Item, false);
            accudraw.setFieldLock(AccuDraw_1.ItemField.Y_Item, false);
            if (accudraw.getFieldLock(AccuDraw_1.ItemField.Z_Item) && accudraw.delta.z === 0.0 && !accudraw.stickyZLock)
                accudraw.setFieldLock(AccuDraw_1.ItemField.Z_Item, false);
        }
        else { // lock to nearest axis
            if (accudraw.clearTentative()) {
                if (Math.abs(accudraw.delta.x) >= core_geometry_1.Geometry.smallAngleRadians && Math.abs(accudraw.delta.y) >= core_geometry_1.Geometry.smallAngleRadians) {
                    accudraw.doLockAngle(false);
                    return;
                }
            }
            const vp = accudraw.currentView;
            if (Math.abs(accudraw.delta.x) > Math.abs(accudraw.delta.y)) {
                accudraw.delta.y = 0.0;
                accudraw.onFieldValueChange(AccuDraw_1.ItemField.Y_Item);
                accudraw.locked |= AccuDraw_1.LockedStates.Y_BM;
                accudraw.locked &= ~AccuDraw_1.LockedStates.X_BM;
                accudraw.setFieldLock(AccuDraw_1.ItemField.X_Item, false);
                accudraw.setFieldLock(AccuDraw_1.ItemField.Y_Item, true);
                accudraw.setFieldLock(AccuDraw_1.ItemField.Z_Item, vp ? vp.view.is3d() : false);
            }
            else {
                accudraw.delta.x = 0.0;
                accudraw.onFieldValueChange(AccuDraw_1.ItemField.X_Item);
                accudraw.locked |= AccuDraw_1.LockedStates.X_BM;
                accudraw.locked &= ~AccuDraw_1.LockedStates.Y_BM;
                accudraw.setFieldLock(AccuDraw_1.ItemField.Y_Item, false);
                accudraw.setFieldLock(AccuDraw_1.ItemField.X_Item, true);
                accudraw.setFieldLock(AccuDraw_1.ItemField.Z_Item, vp ? vp.view.is3d() : false);
            }
            if (!accudraw.flags.lockedRotation) {
                accudraw.flags.lockedRotation = true;
                accudraw.flags.contextRotMode = AccuDraw_1.ContextMode.Locked;
                accudraw.setRotationMode(AccuDraw_1.RotationMode.Context);
            }
        }
        accudraw.refreshDecorationsAndDynamics();
    }
    /** Disable indexing when not currently indexed; if indexed, enable respective lock. */
    static lockIndex() {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        if (accudraw.flags.indexLocked) {
            if (accudraw.locked)
                this.lockSmart();
            accudraw.flags.indexLocked = false;
        }
        else {
            if (AccuDraw_1.CompassMode.Polar === accudraw.compassMode) {
                if (accudraw.indexed & AccuDraw_1.LockedStates.XY_BM) {
                    accudraw.setFieldLock(AccuDraw_1.ItemField.ANGLE_Item, true);
                    accudraw.angleLock();
                }
                if (accudraw.indexed & AccuDraw_1.LockedStates.DIST_BM)
                    this.lockDistance();
            }
            else {
                if (accudraw.indexed & AccuDraw_1.LockedStates.X_BM) {
                    this.lockX();
                    if (accudraw.indexed & AccuDraw_1.LockedStates.DIST_BM)
                        this.lockY();
                }
                if (accudraw.indexed & AccuDraw_1.LockedStates.Y_BM) {
                    this.lockY();
                    if (accudraw.indexed & AccuDraw_1.LockedStates.DIST_BM)
                        this.lockX();
                }
                if (accudraw.indexed & AccuDraw_1.LockedStates.DIST_BM && !(accudraw.indexed & AccuDraw_1.LockedStates.XY_BM)) {
                    if (accudraw.locked & AccuDraw_1.LockedStates.X_BM)
                        this.lockY();
                    else
                        this.lockX();
                }
            }
            accudraw.flags.indexLocked = true;
        }
    }
    static lockX() {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        accudraw.clearTentative();
        if (AccuDraw_1.CompassMode.Rectangular !== accudraw.compassMode) {
            const vp = accudraw.currentView;
            if (!vp)
                return;
            accudraw.fixPointRectangular(vp);
            accudraw.changeCompassMode(true);
        }
        if (accudraw.getFieldLock(AccuDraw_1.ItemField.X_Item)) {
            accudraw.setFieldLock(AccuDraw_1.ItemField.X_Item, false);
            accudraw.locked = accudraw.locked & ~AccuDraw_1.LockedStates.X_BM;
        }
        else {
            accudraw.saveCoordinate(AccuDraw_1.ItemField.X_Item, accudraw.delta.x);
            accudraw.setFieldLock(AccuDraw_1.ItemField.X_Item, true);
            accudraw.locked = accudraw.locked | AccuDraw_1.LockedStates.X_BM;
        }
        accudraw.refreshDecorationsAndDynamics();
    }
    static lockY() {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        accudraw.clearTentative();
        if (AccuDraw_1.CompassMode.Rectangular !== accudraw.compassMode) {
            const vp = accudraw.currentView;
            if (!vp)
                return;
            accudraw.fixPointRectangular(vp);
            accudraw.changeCompassMode(true);
        }
        if (accudraw.getFieldLock(AccuDraw_1.ItemField.Y_Item)) {
            accudraw.setFieldLock(AccuDraw_1.ItemField.Y_Item, false);
            accudraw.locked = accudraw.locked & ~AccuDraw_1.LockedStates.Y_BM;
        }
        else {
            accudraw.saveCoordinate(AccuDraw_1.ItemField.Y_Item, accudraw.delta.y);
            accudraw.setFieldLock(AccuDraw_1.ItemField.Y_Item, true);
            accudraw.locked = accudraw.locked | AccuDraw_1.LockedStates.Y_BM;
        }
        accudraw.refreshDecorationsAndDynamics();
    }
    static lockZ() {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        const vp = accudraw.currentView;
        if (!vp || !vp.view.is3d())
            return;
        const isSnapped = accudraw.clearTentative();
        if (accudraw.getFieldLock(AccuDraw_1.ItemField.Z_Item)) {
            accudraw.setFieldLock(AccuDraw_1.ItemField.Z_Item, false);
        }
        else {
            // Move focus to Z field...
            if (!isSnapped && accudraw.autoFocusFields) {
                accudraw.setFocusItem(AccuDraw_1.ItemField.Z_Item);
                accudraw.dontMoveFocus = true;
            }
            accudraw.setFieldLock(AccuDraw_1.ItemField.Z_Item, true);
        }
        accudraw.refreshDecorationsAndDynamics();
    }
    static lockDistance() {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        const isSnapped = accudraw.clearTentative();
        if (AccuDraw_1.CompassMode.Polar !== accudraw.compassMode) {
            const vp = accudraw.currentView;
            if (!vp)
                return;
            accudraw.locked = 0;
            accudraw.fixPointPolar(vp);
            accudraw.changeCompassMode(true);
        }
        if (accudraw.getFieldLock(AccuDraw_1.ItemField.DIST_Item)) {
            accudraw.setFieldLock(AccuDraw_1.ItemField.DIST_Item, false);
            accudraw.locked &= ~AccuDraw_1.LockedStates.DIST_BM;
            accudraw.setKeyinStatus(AccuDraw_1.ItemField.DIST_Item, AccuDraw_1.KeyinStatus.Dynamic); // Need to clear partial status if locked by entering distance since focus stays in distance field...
        }
        else {
            // Move focus to distance field...
            if (!isSnapped && accudraw.autoFocusFields)
                accudraw.setFocusItem(AccuDraw_1.ItemField.DIST_Item);
            accudraw.distanceLock(true, true);
        }
        accudraw.refreshDecorationsAndDynamics();
    }
    static lockAngle() {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        accudraw.doLockAngle(accudraw.clearTentative());
        accudraw.refreshDecorationsAndDynamics();
    }
    lockIndex() {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        if (accudraw.flags.indexLocked) {
            if (accudraw.locked)
                AccuDrawShortcuts.lockSmart();
            accudraw.flags.indexLocked = false;
        }
        else {
            if (AccuDraw_1.CompassMode.Polar === accudraw.compassMode) {
                if (accudraw.indexed & AccuDraw_1.LockedStates.XY_BM) {
                    accudraw.setFieldLock(AccuDraw_1.ItemField.ANGLE_Item, true);
                    accudraw.angleLock();
                }
                if (accudraw.indexed & AccuDraw_1.LockedStates.DIST_BM)
                    AccuDrawShortcuts.lockDistance();
            }
            else {
                if (accudraw.indexed & AccuDraw_1.LockedStates.X_BM) {
                    AccuDrawShortcuts.lockX();
                    if (accudraw.indexed & AccuDraw_1.LockedStates.DIST_BM)
                        AccuDrawShortcuts.lockY();
                }
                if (accudraw.indexed & AccuDraw_1.LockedStates.Y_BM) {
                    AccuDrawShortcuts.lockY();
                    if (accudraw.indexed & AccuDraw_1.LockedStates.DIST_BM)
                        AccuDrawShortcuts.lockX();
                }
                if (accudraw.indexed & AccuDraw_1.LockedStates.DIST_BM && !(accudraw.indexed & AccuDraw_1.LockedStates.XY_BM)) {
                    if (accudraw.locked & AccuDraw_1.LockedStates.X_BM)
                        AccuDrawShortcuts.lockY();
                    else
                        AccuDrawShortcuts.lockX();
                }
            }
            accudraw.flags.indexLocked = true;
        }
        accudraw.refreshDecorationsAndDynamics();
    }
    static setStandardRotation(rotation) {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        if (AccuDraw_1.RotationMode.Context === rotation) {
            const axes = accudraw.baseAxes.clone();
            accudraw.accountForAuxRotationPlane(axes, accudraw.flags.auxRotationPlane);
            accudraw.setContextRotation(axes.toMatrix3d(), false, true);
            accudraw.refreshDecorationsAndDynamics();
            return;
        }
        else {
            accudraw.flags.baseRotation = rotation;
            accudraw.setRotationMode(rotation);
        }
        accudraw.updateRotation(true);
        accudraw.refreshDecorationsAndDynamics();
    }
    static alignView() {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        const vp = accudraw.currentView;
        if (!vp)
            return;
        const newMatrix = accudraw.getRotation();
        if (newMatrix.isExactEqual(vp.rotation))
            return;
        const targetMatrix = newMatrix.multiplyMatrixMatrix(vp.rotation);
        const rotateTransform = core_geometry_1.Transform.createFixedPointAndMatrix(vp.view.getTargetPoint(), targetMatrix);
        const newFrustum = vp.getFrustum();
        newFrustum.multiply(rotateTransform);
        vp.view.setupFromFrustum(newFrustum);
        vp.synchWithView();
        vp.animateFrustumChange();
        accudraw.refreshDecorationsAndDynamics();
    }
    static rotateToBase() { this.setStandardRotation(IModelApp_1.IModelApp.accuDraw.flags.baseRotation); }
    static rotateToACS() {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        // NOTE: Match current ACS orientation..reset auxRotationPlane to top!
        accudraw.flags.auxRotationPlane = AccuDraw_1.RotationMode.Top;
        this.setStandardRotation(AccuDraw_1.RotationMode.ACS);
    }
    static rotateCycle() {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        const vp = accudraw.currentView;
        if (!vp || !vp.view.is3d())
            return;
        let rotation;
        switch (accudraw.rotationMode) {
            case AccuDraw_1.RotationMode.View:
            case AccuDraw_1.RotationMode.Side:
                rotation = AccuDraw_1.RotationMode.Top;
                break;
            case AccuDraw_1.RotationMode.Top:
                rotation = AccuDraw_1.RotationMode.Front;
                break;
            case AccuDraw_1.RotationMode.Front:
                rotation = AccuDraw_1.RotationMode.Side;
                break;
            case AccuDraw_1.RotationMode.Context:
                rotation = AccuDraw_1.RotationMode.Context;
                if (rotation !== accudraw.flags.baseRotation) {
                    accudraw.baseAxes.setFrom(accudraw.axes);
                    accudraw.flags.auxRotationPlane = AccuDraw_1.RotationMode.Top;
                    accudraw.flags.baseRotation = rotation;
                }
                else {
                    const axes = accudraw.baseAxes.clone();
                    accudraw.accountForAuxRotationPlane(axes, accudraw.flags.auxRotationPlane);
                    if (!accudraw.axes.equals(axes))
                        accudraw.changeBaseRotationMode(rotation);
                }
                switch (accudraw.flags.auxRotationPlane) {
                    case AccuDraw_1.RotationMode.Front:
                        accudraw.flags.auxRotationPlane = AccuDraw_1.RotationMode.Side;
                        break;
                    case AccuDraw_1.RotationMode.Side:
                        accudraw.flags.auxRotationPlane = AccuDraw_1.RotationMode.Top;
                        break;
                    case AccuDraw_1.RotationMode.Top:
                        accudraw.flags.auxRotationPlane = AccuDraw_1.RotationMode.Front;
                        break;
                }
                break;
            case AccuDraw_1.RotationMode.ACS:
                rotation = AccuDraw_1.RotationMode.ACS;
                switch (accudraw.flags.auxRotationPlane) {
                    case AccuDraw_1.RotationMode.Front:
                        accudraw.flags.auxRotationPlane = AccuDraw_1.RotationMode.Side;
                        break;
                    case AccuDraw_1.RotationMode.Side:
                        accudraw.flags.auxRotationPlane = AccuDraw_1.RotationMode.Top;
                        break;
                    case AccuDraw_1.RotationMode.Top:
                        accudraw.flags.auxRotationPlane = AccuDraw_1.RotationMode.Front;
                        break;
                }
                break;
            default:
                return;
        }
        this.setStandardRotation(rotation);
    }
    static rotate90(axis) {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return;
        const newRotation = new AccuDraw_1.ThreeAxes();
        accudraw.locked = accudraw.indexed = 0;
        accudraw.unlockAllFields();
        switch (axis) {
            case 0:
                newRotation.x.setFrom(accudraw.axes.x);
                newRotation.z.setFrom(accudraw.axes.y);
                newRotation.z.crossProduct(newRotation.x, newRotation.y);
                break;
            case 1:
                newRotation.x.setFrom(accudraw.axes.z);
                newRotation.y.setFrom(accudraw.axes.y);
                newRotation.x.crossProduct(newRotation.y, newRotation.z);
                break;
            case 2:
                newRotation.x.setFrom(accudraw.axes.y);
                newRotation.z.setFrom(accudraw.axes.z);
                newRotation.z.crossProduct(newRotation.x, newRotation.y);
                break;
        }
        accudraw.setContextRotation(newRotation.toMatrix3d(), true, true);
        accudraw.refreshDecorationsAndDynamics();
    }
    static async rotateAxes(aboutCurrentZ) {
        return IModelApp_1.IModelApp.tools.run("AccuDraw.RotateAxes", aboutCurrentZ);
    }
    static async rotateToElement() {
        return IModelApp_1.IModelApp.tools.run("AccuDraw.RotateElement");
    }
    static async rotatePerpendicular() {
        return IModelApp_1.IModelApp.tools.run("AccuDraw.RotatePerpendicular");
    }
    static async defineACSByElement() {
        return IModelApp_1.IModelApp.tools.run("AccuDraw.DefineACSByElement");
    }
    static async defineACSByPoints() {
        return IModelApp_1.IModelApp.tools.run("AccuDraw.DefineACSByPoints");
    }
    static getACS(acsName, useOrigin, useRotation) {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return core_bentley_1.BentleyStatus.ERROR;
        const vp = accudraw.currentView;
        if (!vp)
            return core_bentley_1.BentleyStatus.ERROR;
        let currRotation = 0, currBaseRotation = 0;
        const axes = new AccuDraw_1.ThreeAxes();
        if (!useRotation) {
            // Save current rotation, event listener on ACS change will orient AccuDraw to ACS...
            currRotation = accudraw.rotationMode;
            currBaseRotation = accudraw.flags.baseRotation;
            axes.setFrom(accudraw.axes);
        }
        if (acsName && "" !== acsName) {
            //   // See if this ACS already exists...
            //   DgnCode acsCode = AuxCoordSystem:: CreateCode(vp -> GetViewControllerR().GetViewDefinition(), acsName);
            //   DgnElementId acsId = vp -> GetViewController().GetDgnDb().Elements().QueryElementIdByCode(acsCode);
            //   if (!acsId.IsValid())
            //     return ERROR;
            //   AuxCoordSystemCPtr auxElm = vp -> GetViewController().GetDgnDb().Elements().Get<AuxCoordSystem>(acsId);
            //   if (!auxElm.IsValid())
            //     return ERROR;
            //   AuxCoordSystemPtr acsPtr = auxElm -> MakeCopy<AuxCoordSystem>();
            //   if (!acsPtr.IsValid())
            //     return ERROR;
            //   AuxCoordSystemCR oldACS = vp -> GetViewController().GetAuxCoordinateSystem();
            //   if (!useOrigin)
            //     acsPtr -> SetOrigin(oldACS.GetOrigin());
            //   if (!useRotation)
            //     acsPtr -> SetRotation(oldACS.GetRotation());
            //   AccuDraw:: UpdateAuxCoordinateSystem(* acsPtr, * vp);
        }
        const currentACS = vp.view.auxiliaryCoordinateSystem;
        if (useOrigin) {
            accudraw.origin.setFrom(currentACS.getOrigin());
            accudraw.point.setFrom(accudraw.origin);
            accudraw.planePt.setFrom(accudraw.origin);
        }
        if (useRotation) {
            accudraw.flags.auxRotationPlane = AccuDraw_1.RotationMode.Top;
            this.setStandardRotation(AccuDraw_1.RotationMode.ACS);
        }
        else {
            this.itemFieldUnlockAll();
            accudraw.setRotationMode(currRotation);
            accudraw.flags.baseRotation = currBaseRotation;
            accudraw.axes.setFrom(axes);
            if (AccuDraw_1.RotationMode.ACS === accudraw.flags.baseRotation) {
                const acs = currentACS.clone();
                const rMatrix = accudraw.getRotation();
                acs.setRotation(rMatrix);
                AccuDraw_1.AccuDraw.updateAuxCoordinateSystem(acs, vp);
            }
            accudraw.published.flags &= ~AccuDraw_1.AccuDrawFlags.OrientACS;
        }
        return core_bentley_1.BentleyStatus.SUCCESS;
    }
    static writeACS(_acsName) {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (!accudraw.isEnabled)
            return core_bentley_1.BentleyStatus.ERROR;
        const vp = accudraw.currentView;
        if (!vp)
            return core_bentley_1.BentleyStatus.ERROR;
        // const origin = accudraw.origin;
        // const rMatrix = accudraw.getRotation();
        // AuxCoordSystemPtr acsPtr = AuxCoordSystem:: CreateFrom(vp -> GetViewController().GetAuxCoordinateSystem());
        // acsPtr -> SetOrigin(origin);
        // acsPtr -> SetRotation(rMatrix);
        // acsPtr -> SetType(CompassMode.Polar == accudraw.getCompassMode() ? ACSType :: Cylindrical : ACSType:: Rectangular);
        // acsPtr -> SetCode(AuxCoordSystem:: CreateCode(vp -> GetViewControllerR().GetViewDefinition(), nullptr != acsName ? acsName : ""));
        // acsPtr -> SetDescription("");
        // if (acsName && '\0' != acsName[0]) {
        //   DgnDbStatus status;
        //   acsPtr -> Insert(& status);
        //   if (DgnDbStatus:: Success != status)
        //   return BentleyStatus.ERROR;
        // }
        // AccuDraw:: UpdateAuxCoordinateSystem(* acsPtr, * vp);
        // accudraw.flags.baseRotation = RotationMode.ACS;
        // accudraw.SetRotationMode(RotationMode.ACS);
        return core_bentley_1.BentleyStatus.SUCCESS;
    }
    static itemFieldUnlockAll() {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (accudraw.isEnabled)
            accudraw.unlockAllFields();
    }
    /** @internal Temporary keyboard shortcuts. */
    static async processShortcutKey(keyEvent) {
        switch (keyEvent.key.toLowerCase()) {
            case "enter":
                AccuDrawShortcuts.lockSmart();
                return true;
            case "x":
                AccuDrawShortcuts.lockX();
                return true;
            case "y":
                AccuDrawShortcuts.lockY();
                return true;
            case "z":
                AccuDrawShortcuts.lockZ();
                return true;
            case "a":
                AccuDrawShortcuts.lockAngle();
                return true;
            case "d":
                AccuDrawShortcuts.lockDistance();
                return true;
            case "h":
                AccuDrawShortcuts.suspendToggle();
                return true;
            case "l":
                AccuDrawShortcuts.lockIndex();
                return true;
            case "m":
                AccuDrawShortcuts.changeCompassMode();
                return true;
            case "t":
                AccuDrawShortcuts.setStandardRotation(AccuDraw_1.RotationMode.Top);
                return true;
            case "f":
                AccuDrawShortcuts.setStandardRotation(AccuDraw_1.RotationMode.Front);
                return true;
            case "s":
                AccuDrawShortcuts.setStandardRotation(AccuDraw_1.RotationMode.Side);
                return true;
            case "v":
                AccuDrawShortcuts.setStandardRotation(AccuDraw_1.RotationMode.View);
                return true;
            case "o":
                AccuDrawShortcuts.setOrigin();
                return true;
            case "c":
                AccuDrawShortcuts.rotateCycle();
                return true;
            case "q":
                return AccuDrawShortcuts.rotateAxes(true);
            case "e":
                return AccuDrawShortcuts.rotateToElement();
            case "p":
                return AccuDrawShortcuts.rotatePerpendicular();
            case "r":
                return AccuDrawShortcuts.defineACSByPoints();
        }
        return false;
    }
}
exports.AccuDrawShortcuts = AccuDrawShortcuts;
/** @internal */
class AccuDrawSessionToggleTool extends Tool_1.Tool {
    async run() {
        AccuDrawShortcuts.sessionToggle();
        return true;
    }
}
exports.AccuDrawSessionToggleTool = AccuDrawSessionToggleTool;
AccuDrawSessionToggleTool.toolId = "AccuDraw.SessionToggle";
/** @internal */
class AccuDrawSuspendToggleTool extends Tool_1.Tool {
    async run() {
        AccuDrawShortcuts.suspendToggle();
        return true;
    }
}
exports.AccuDrawSuspendToggleTool = AccuDrawSuspendToggleTool;
AccuDrawSuspendToggleTool.toolId = "AccuDraw.SuspendToggle";
/** @internal */
class AccuDrawSetOriginTool extends Tool_1.Tool {
    async run() {
        AccuDrawShortcuts.setOrigin();
        return true;
    }
}
exports.AccuDrawSetOriginTool = AccuDrawSetOriginTool;
AccuDrawSetOriginTool.toolId = "AccuDraw.SetOrigin";
/** @internal */
class AccuDrawSetLockSmartTool extends Tool_1.Tool {
    async run() {
        AccuDrawShortcuts.lockSmart();
        return true;
    }
}
exports.AccuDrawSetLockSmartTool = AccuDrawSetLockSmartTool;
AccuDrawSetLockSmartTool.toolId = "AccuDraw.LockSmart";
/** @internal */
class AccuDrawSetLockIndexTool extends Tool_1.Tool {
    async run() {
        AccuDrawShortcuts.lockIndex();
        return true;
    }
}
exports.AccuDrawSetLockIndexTool = AccuDrawSetLockIndexTool;
AccuDrawSetLockIndexTool.toolId = "AccuDraw.LockIndex";
/** @internal */
class AccuDrawSetLockXTool extends Tool_1.Tool {
    async run() {
        AccuDrawShortcuts.lockX();
        return true;
    }
}
exports.AccuDrawSetLockXTool = AccuDrawSetLockXTool;
AccuDrawSetLockXTool.toolId = "AccuDraw.LockX";
/** @internal */
class AccuDrawSetLockYTool extends Tool_1.Tool {
    async run() {
        AccuDrawShortcuts.lockY();
        return true;
    }
}
exports.AccuDrawSetLockYTool = AccuDrawSetLockYTool;
AccuDrawSetLockYTool.toolId = "AccuDraw.LockY";
/** @internal */
class AccuDrawSetLockZTool extends Tool_1.Tool {
    async run() {
        AccuDrawShortcuts.lockZ();
        return true;
    }
}
exports.AccuDrawSetLockZTool = AccuDrawSetLockZTool;
AccuDrawSetLockZTool.toolId = "AccuDraw.LockZ";
/** @internal */
class AccuDrawSetLockDistanceTool extends Tool_1.Tool {
    async run() {
        AccuDrawShortcuts.lockDistance();
        return true;
    }
}
exports.AccuDrawSetLockDistanceTool = AccuDrawSetLockDistanceTool;
AccuDrawSetLockDistanceTool.toolId = "AccuDraw.LockDistance";
/** @internal */
class AccuDrawSetLockAngleTool extends Tool_1.Tool {
    async run() {
        AccuDrawShortcuts.lockAngle();
        return true;
    }
}
exports.AccuDrawSetLockAngleTool = AccuDrawSetLockAngleTool;
AccuDrawSetLockAngleTool.toolId = "AccuDraw.LockAngle";
/** @internal */
class AccuDrawChangeModeTool extends Tool_1.Tool {
    async run() {
        AccuDrawShortcuts.changeCompassMode();
        return true;
    }
}
exports.AccuDrawChangeModeTool = AccuDrawChangeModeTool;
AccuDrawChangeModeTool.toolId = "AccuDraw.ChangeMode";
/** @internal */
class AccuDrawRotateCycleTool extends Tool_1.Tool {
    async run() {
        AccuDrawShortcuts.rotateCycle();
        return true;
    }
}
exports.AccuDrawRotateCycleTool = AccuDrawRotateCycleTool;
AccuDrawRotateCycleTool.toolId = "AccuDraw.RotateCycle";
/** @internal */
class AccuDrawRotateTopTool extends Tool_1.Tool {
    async run() {
        AccuDrawShortcuts.setStandardRotation(AccuDraw_1.RotationMode.Top);
        return true;
    }
}
exports.AccuDrawRotateTopTool = AccuDrawRotateTopTool;
AccuDrawRotateTopTool.toolId = "AccuDraw.RotateTop";
/** @internal */
class AccuDrawRotateFrontTool extends Tool_1.Tool {
    async run() {
        AccuDrawShortcuts.setStandardRotation(AccuDraw_1.RotationMode.Front);
        return true;
    }
}
exports.AccuDrawRotateFrontTool = AccuDrawRotateFrontTool;
AccuDrawRotateFrontTool.toolId = "AccuDraw.RotateFront";
/** @internal */
class AccuDrawRotateSideTool extends Tool_1.Tool {
    async run() {
        AccuDrawShortcuts.setStandardRotation(AccuDraw_1.RotationMode.Side);
        return true;
    }
}
exports.AccuDrawRotateSideTool = AccuDrawRotateSideTool;
AccuDrawRotateSideTool.toolId = "AccuDraw.RotateSide";
/** @internal */
class AccuDrawRotateViewTool extends Tool_1.Tool {
    async run() {
        AccuDrawShortcuts.setStandardRotation(AccuDraw_1.RotationMode.View);
        return true;
    }
}
exports.AccuDrawRotateViewTool = AccuDrawRotateViewTool;
AccuDrawRotateViewTool.toolId = "AccuDraw.RotateView";
/** @internal */
class AccuDrawShortcutsTool extends Tool_1.InputCollector {
    constructor() {
        super(...arguments);
        this._complete = false;
    }
    get allowShortcut() { return this.wantActivateOnStart ? IModelApp_1.IModelApp.accuDraw.isEnabled : true; }
    get wantActivateOnStart() { return false; } // Whether to automatically enable AccuDraw before the 1st data button...
    get wantClearSnapOnStart() { return false; } // Whether to preserve active Tentative/AccuSnap on install...
    get wantManipulationImmediate() { return false; } // Whether additional input is required to process on install...
    get wantExitOnDataButtonUp() { return false; } // Whether to exit on button up instead of down (see rotate perpendicular)...
    async onInstall() {
        if (!this.allowShortcut)
            return false;
        return super.onInstall();
    }
    async onPostInstall() {
        await super.onPostInstall();
        if (this.wantActivateOnStart)
            IModelApp_1.IModelApp.accuDraw.activate();
        this.onManipulationStart();
        if (this.wantManipulationImmediate && this.doManipulation(undefined, false)) {
            this._complete = true;
            return this.exitTool();
        }
        // NOTE: InputCollector inherits suspended primitive's state, set everything...
        if (this.wantClearSnapOnStart) {
            this.initLocateElements(false, true, undefined, Tool_1.CoordinateLockOverrides.None); // This clears the active Tentative/AccuSnap, some shortcuts have special behavior when invoked with an active snap...
        }
        else {
            IModelApp_1.IModelApp.locateManager.initLocateOptions();
            this.changeLocateState(false, true, undefined, Tool_1.CoordinateLockOverrides.None);
        }
        this.doManipulation(undefined, true);
        ;
    }
    async onCleanup() {
        if (this._complete)
            IModelApp_1.IModelApp.accuDraw.savedStateInputCollector.ignoreFlags = this.onManipulationComplete();
    }
    async exitTool() {
        await super.exitTool();
        AccuDrawShortcuts.requestInputFocus(); // re-grab focus when auto-focus tool setting set...
    }
    async onDataButtonDown(ev) {
        if (this.doManipulation(ev, false)) {
            this._complete = true;
            if (!this.wantExitOnDataButtonUp)
                await this.exitTool();
        }
        return Tool_1.EventHandled.No;
    }
    async onDataButtonUp(_ev) {
        if (this._complete && this.wantExitOnDataButtonUp)
            await this.exitTool();
        return Tool_1.EventHandled.No;
    }
    async onMouseMotion(ev) {
        this.doManipulation(ev, true);
    }
    onManipulationStart() { }
    onManipulationComplete() { return AccuDraw_1.AccuDrawFlags.SetRMatrix; }
}
/** @internal */
class AccuDrawRotateAxesTool extends AccuDrawShortcutsTool {
    static get maxArgs() { return 1; }
    constructor(aboutCurrentZ = true) {
        super();
        this.aboutCurrentZ = aboutCurrentZ;
    }
    get allowShortcut() { return IModelApp_1.IModelApp.accuDraw.isActive; } // Require compass to already be active for this shortcut...
    get wantActivateOnStart() { return true; } // State is demoted to inactive when a tool install, still need this...
    get wantManipulationImmediate() {
        if (AccuSnap_1.TentativeOrAccuSnap.isHot)
            return true;
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        if (AccuDraw_1.CompassMode.Polar === accudraw.compassMode)
            return accudraw.getFieldLock(AccuDraw_1.ItemField.ANGLE_Item);
        return accudraw.getFieldLock(AccuDraw_1.ItemField.X_Item) && accudraw.getFieldLock(AccuDraw_1.ItemField.Y_Item);
    }
    onManipulationStart() {
        if (this.aboutCurrentZ)
            IModelApp_1.IModelApp.accuDraw.changeBaseRotationMode(AccuDraw_1.RotationMode.Context); // Establish current orientation as base for when defining compass rotation by x axis...
        Tool_1.CoreTools.outputPromptByKey("AccuDraw.RotateAxes.Prompts.FirstPoint");
    }
    doManipulation(ev, isMotion) {
        const vp = ev ? ev.viewport : IModelApp_1.IModelApp.accuDraw.currentView;
        if (!vp)
            return false;
        if (!AccuDrawShortcuts.rotateAxesByPoint(AccuSnap_1.TentativeOrAccuSnap.isHot, this.aboutCurrentZ))
            return false;
        vp.invalidateDecorations();
        if (!isMotion) {
            AccuDrawShortcuts.itemFieldUnlockAll();
            IModelApp_1.IModelApp.tentativePoint.clear(true);
        }
        return true;
    }
    async parseAndRun(...args) {
        for (const arg of args) {
            if (arg.toLowerCase() === "unlockedz")
                this.aboutCurrentZ = false;
        }
        return this.run(args);
    }
}
exports.AccuDrawRotateAxesTool = AccuDrawRotateAxesTool;
AccuDrawRotateAxesTool.toolId = "AccuDraw.RotateAxes";
/** @internal */
class AccuDrawRotateElementTool extends AccuDrawShortcutsTool {
    constructor() {
        super(...arguments);
        this._moveOrigin = !IModelApp_1.IModelApp.accuDraw.isActive || IModelApp_1.IModelApp.tentativePoint.isActive; // Preserve current origin if AccuDraw already active and not tentative snap...
    }
    get wantActivateOnStart() { return true; }
    get wantManipulationImmediate() { return IModelApp_1.IModelApp.tentativePoint.isSnapped; }
    onManipulationStart() {
        IModelApp_1.IModelApp.accuDraw.setContext(AccuDraw_1.AccuDrawFlags.FixedOrigin); // Don't move compass when updateOrientation returns false...
        Tool_1.CoreTools.outputPromptByKey("AccuDraw.RotateElement.Prompts.FirstPoint");
    }
    onManipulationComplete() {
        let ignoreFlags = AccuDraw_1.AccuDrawFlags.SetRMatrix | AccuDraw_1.AccuDrawFlags.Disable; // If AccuDraw wasn't active when the shortcut started, let it remain active for suspended tool when shortcut completes...
        if (this._moveOrigin)
            ignoreFlags |= AccuDraw_1.AccuDrawFlags.SetOrigin;
        return ignoreFlags;
    }
    updateOrientation(snap, viewport, _isMotion) {
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        const rMatrix = AccuDraw_1.AccuDraw.getSnapRotation(snap, viewport);
        if (undefined === rMatrix)
            return false;
        const point = this._moveOrigin ? snap.snapPoint : accudraw.origin;
        accudraw.setContext(AccuDraw_1.AccuDrawFlags.SetRMatrix | AccuDraw_1.AccuDrawFlags.AlwaysSetOrigin, point, rMatrix);
        return true;
    }
    doManipulation(ev, isMotion) {
        const viewport = ev ? ev.viewport : IModelApp_1.IModelApp.accuDraw.currentView;
        if (!viewport)
            return false;
        const snap = AccuSnap_1.TentativeOrAccuSnap.getCurrentSnap(false);
        if (undefined === snap || !this.updateOrientation(snap, viewport, isMotion))
            return false;
        if (undefined === ev)
            AccuDrawShortcuts.processPendingHints(); // Would normally be processed after button down, necessary when called from post install...
        if (!isMotion)
            IModelApp_1.IModelApp.accuDraw.changeBaseRotationMode(AccuDraw_1.RotationMode.Context); // Hold temporary rotation for tool duration...
        return true;
    }
}
exports.AccuDrawRotateElementTool = AccuDrawRotateElementTool;
AccuDrawRotateElementTool.toolId = "AccuDraw.RotateElement";
/** @internal */
class AccuDrawRotatePerpendicularTool extends AccuDrawRotateElementTool {
    get wantExitOnDataButtonUp() { return true; } // Complete on button up since button down clears tentative...
    onManipulationComplete() {
        if (undefined !== this._location) {
            // Use tentative to hold adjusted snap location for suspended tool...
            IModelApp_1.IModelApp.tentativePoint.setPoint(this._location.point);
            IModelApp_1.IModelApp.tentativePoint.viewport = this._location.viewport;
            IModelApp_1.IModelApp.tentativePoint.showTentative();
        }
        return AccuDraw_1.AccuDrawFlags.SetRMatrix | AccuDraw_1.AccuDrawFlags.Disable;
    }
    updateOrientation(snap, viewport, isMotion) {
        const curve = snap.getCurvePrimitive();
        if (undefined === curve)
            return false;
        const accudraw = IModelApp_1.IModelApp.accuDraw;
        const rMatrix = AccuDraw_1.AccuDraw.getSnapRotation(snap, viewport);
        if (undefined === rMatrix)
            return false;
        const zVec = rMatrix.getRow(2); // This is a row matrix...
        const spacePoint = AccuDraw_1.AccuDrawHintBuilder.projectPointToPlaneInView(accudraw.origin, snap.getPoint(), zVec, viewport, true);
        if (undefined === spacePoint)
            return false;
        const detail = curve.closestPoint(spacePoint, true);
        if (undefined === detail?.curve)
            return false;
        const point = AccuDraw_1.AccuDrawHintBuilder.projectPointToPlaneInView(detail.point, accudraw.origin, zVec, viewport, true);
        if (undefined === point)
            return false;
        const xVec = new core_geometry_1.Vector3d();
        if (normalizedDifference(point, accudraw.origin, xVec) < core_geometry_1.Geometry.smallAngleRadians)
            return false;
        ; // Closest point and compass origin coincide...
        const yVec = xVec.unitCrossProduct(zVec);
        if (undefined === yVec)
            return false;
        rMatrix.setColumns(xVec, yVec, zVec);
        core_geometry_1.Matrix3d.createRigidFromMatrix3d(rMatrix, core_geometry_1.AxisOrder.XZY, rMatrix);
        rMatrix.transposeInPlace();
        snap.setSnapPoint(point, HitDetail_1.SnapHeat.InRange); // Force hot snap so that adjust point uses it for alignments...
        accudraw.setContext(AccuDraw_1.AccuDrawFlags.SetRMatrix | AccuDraw_1.AccuDrawFlags.AlwaysSetOrigin, accudraw.origin, rMatrix);
        accudraw.adjustPoint(point, viewport, false); // Update internals for new snap location...
        if (!isMotion)
            this._location = { point, viewport };
        return true;
    }
}
exports.AccuDrawRotatePerpendicularTool = AccuDrawRotatePerpendicularTool;
AccuDrawRotatePerpendicularTool.toolId = "AccuDraw.RotatePerpendicular";
/** @internal */
class DefineACSByElementTool extends AccuDrawShortcutsTool {
    constructor() {
        super(...arguments);
        this._origin = core_geometry_1.Point3d.create();
        this._rMatrix = core_geometry_1.Matrix3d.createIdentity();
    }
    onManipulationStart() { Tool_1.CoreTools.outputPromptByKey("AccuDraw.DefineACSByElement.Prompts.FirstPoint"); }
    updateOrientation(snap, vp) {
        const rMatrix = AccuDraw_1.AccuDraw.getSnapRotation(snap, vp);
        if (undefined === rMatrix)
            return false;
        this._origin = snap.snapPoint;
        this._rMatrix = rMatrix;
        return true;
    }
    doManipulation(ev, isMotion) {
        const vp = ev ? ev.viewport : undefined;
        if (!vp)
            return false;
        const snapDetail = AccuSnap_1.TentativeOrAccuSnap.getCurrentSnap(false);
        if (undefined === snapDetail || !this.updateOrientation(snapDetail, vp))
            return false;
        IModelApp_1.IModelApp.viewManager.invalidateDecorationsAllViews();
        if (isMotion)
            return true;
        if (!this._acs)
            this._acs = vp.view.auxiliaryCoordinateSystem.clone();
        this._acs.setOrigin(this._origin);
        this._acs.setRotation(this._rMatrix);
        AccuDraw_1.AccuDraw.updateAuxCoordinateSystem(this._acs, vp);
        AccuDrawShortcuts.rotateToACS();
        return true;
    }
    decorate(context) {
        const vp = context.viewport;
        if (!this._acs)
            this._acs = vp.view.auxiliaryCoordinateSystem.clone();
        this._acs.setOrigin(this._origin);
        this._acs.setRotation(this._rMatrix);
        this._acs.display(context, AuxCoordSys_1.ACSDisplayOptions.Active | AuxCoordSys_1.ACSDisplayOptions.Dynamics);
    }
}
exports.DefineACSByElementTool = DefineACSByElementTool;
DefineACSByElementTool.toolId = "AccuDraw.DefineACSByElement";
/** @internal */
class DefineACSByPointsTool extends AccuDrawShortcutsTool {
    constructor() {
        super(...arguments);
        this._points = [];
    }
    onManipulationStart() {
        if (!IModelApp_1.IModelApp.tentativePoint.isActive) {
            Tool_1.CoreTools.outputPromptByKey("AccuDraw.DefineACSByPoints.Prompts.FirstPoint");
            return;
        }
        const origin = IModelApp_1.IModelApp.tentativePoint.getPoint().clone();
        Tool_1.CoreTools.outputPromptByKey("AccuDraw.DefineACSByPoints.Prompts.SecondPoint");
        IModelApp_1.IModelApp.accuDraw.setContext(AccuDraw_1.AccuDrawFlags.SetOrigin | AccuDraw_1.AccuDrawFlags.FixedOrigin, origin);
        this._points.push(origin);
        IModelApp_1.IModelApp.tentativePoint.clear(true);
    }
    doManipulation(ev, isMotion) {
        if (!ev || !ev.viewport)
            return false;
        IModelApp_1.IModelApp.viewManager.invalidateDecorationsAllViews();
        if (isMotion)
            return false;
        IModelApp_1.IModelApp.accuDraw.activate();
        this._points.push(ev.point.clone());
        const vp = ev.viewport;
        if (!this._acs)
            this._acs = vp.view.auxiliaryCoordinateSystem.clone();
        if (AccuDrawShortcuts.updateACSByPoints(this._acs, vp, this._points, false)) {
            AccuDraw_1.AccuDraw.updateAuxCoordinateSystem(this._acs, vp);
            AccuDrawShortcuts.rotateToACS();
            return true;
        }
        Tool_1.CoreTools.outputPromptByKey(`AccuDraw.DefineACSByPoints.Prompts${1 === this._points.length ? ".SecondPoint" : ".NextPoint"}`);
        return false;
    }
    decorate(context) {
        const tmpPoints = [];
        this._points.forEach((pt) => tmpPoints.push(pt));
        const ev = new Tool_1.BeButtonEvent();
        IModelApp_1.IModelApp.toolAdmin.fillEventFromCursorLocation(ev);
        tmpPoints.push(ev.point);
        const vp = context.viewport;
        if (!this._acs)
            this._acs = vp.view.auxiliaryCoordinateSystem.clone();
        AccuDrawShortcuts.updateACSByPoints(this._acs, vp, tmpPoints, true);
        this._acs.display(context, AuxCoordSys_1.ACSDisplayOptions.Active | AuxCoordSys_1.ACSDisplayOptions.Dynamics);
    }
}
exports.DefineACSByPointsTool = DefineACSByPointsTool;
DefineACSByPointsTool.toolId = "AccuDraw.DefineACSByPoints";
//# sourceMappingURL=AccuDrawTool.js.map