/** @packageDocumentation
 * @module Tools
 */
import { CompressedId64Set, Id64Arg, Id64Array, Id64String, OrderedId64Array } from "@itwin/core-bentley";
import { Point3d, XAndY } from "@itwin/core-geometry";
import { LocateFilterStatus, LocateResponse } from "../ElementLocateManager";
import { HitDetail } from "../HitDetail";
import { IModelConnection } from "../IModelConnection";
import { SelectionSet } from "../SelectionSet";
import { DecorateContext } from "../ViewContext";
import { Viewport } from "../Viewport";
import { PrimitiveTool } from "./PrimitiveTool";
import { SelectionMethod } from "./SelectTool";
import { BeButtonEvent, BeModifierKeys, EventHandled } from "./Tool";
import { ToolAssistanceInstruction } from "./ToolAssistance";
/** Identifies the source of the elements in the agenda.
 * @public
 */
export declare enum ModifyElementSource {
    /** The source for the element is unknown - not caused by a modification command. */
    Unknown = 0,
    /** The element is selected by the user. */
    Selected = 1,
    /** The element is processed because it is in the selection set. */
    SelectionSet = 2,// eslint-disable-line @typescript-eslint/no-shadow
    /** The element is selected by the user using drag box or crossing line selection. */
    DragSelect = 3
}
/** Identifies groups of elements added to agenda along with the source.
 * @public
 */
export interface GroupMark {
    start: number;
    source: ModifyElementSource;
}
/** The ElementAgenda class is used by [[ElementSetTool]] to hold the collection of elements it will operate on
 * and to manage their hilite state.
 * @see [[ElementSetTool]]
 * @public
*/
export declare class ElementAgenda {
    iModel: IModelConnection;
    /** The IDs of the elements in this agenda.
     * @note Prefer methods like [[ElementAgenda.add]] instead of modifying directly.
     */
    readonly elements: Id64Array;
    /** The group source identifiers for the elements in this agenda.
     * @note Prefer methods like [[ElementAgenda.add]] instead of modifying directly.
     */
    readonly groupMarks: GroupMark[];
    manageHiliteState: boolean;
    constructor(iModel: IModelConnection);
    /** Get the source for the last group added to this agenda, if applicable. The "source" is merely an indication of what the collection of elements represents. */
    getSource(): ModifyElementSource;
    /** Set the source for the last group added to this agenda. */
    setSource(val: ModifyElementSource): void;
    get isEmpty(): boolean;
    get count(): number;
    get length(): number;
    /** Create [[OrderedId64Array]] from agenda. */
    orderIds(): OrderedId64Array;
    /** Create [[CompressedId64Set]] from agenda. */
    compressIds(): CompressedId64Set;
    /** Empties the agenda and clears hilite state when manageHiliteState is true. */
    clear(): void;
    private setEntriesHiliteState;
    /** Removes the last group of elements added to this agenda. */
    popGroup(): void;
    /** Return true if elementId is already in this agenda. */
    has(id: string): boolean;
    /** Return true if elementId is already in this agenda. */
    find(id: Id64String): boolean;
    /** Add elements to this agenda. */
    add(arg: Id64Arg): boolean;
    private removeOne;
    remove(arg: Id64Arg): boolean;
    /** Add elements not currently in the agenda and remove elements currently in the agenda. */
    invert(arg: Id64Arg): boolean;
}
/** The ElementSetTool class is a specialization of [[PrimitiveTool]] designed to unify operations on sets of elements.
 * Use to query or modify existing elements as well as to create new elements from existing elements.
 * Basic tool sequence:
 * - Populate [[ElementSetTool.agenda]] with the element ids to query or modify.
 * - Gather any additional input and if requested, enable dynamics to preview result.
 * - Call [[ElementSetTool.processAgenda]] to apply operation to [[ElementSetTool.agenda]].
 * - Call [[ElementSetTool.onProcessComplete]] to restart or exit.
 * Common element sources:
 * - Pre-selected elements from an active [[SelectionSet]].
 * - Clicking in a view to identify elements using [[ElementLocateManager]].
 * - Drag box and crossing line selection.
 * Default behavior:
 * - Identify a single element with left-click.
 * - Immediately apply operation.
 * - Restart.
 * Sub-classes are required to opt-in to additional element sources, dynamics, AccuSnap, additional input, etc.
 * @public
 */
export declare abstract class ElementSetTool extends PrimitiveTool {
    private _agenda?;
    private _useSelectionSet;
    private _processDataButtonUp;
    /** The accept point for a selection set, drag select, or final located element. */
    protected anchorPoint?: Point3d;
    /** The button down location that initiated box or crossing line selection. */
    protected dragStartPoint?: Point3d;
    /** Get the [[ElementAgenda]] the tool will operate on. */
    protected get agenda(): ElementAgenda;
    /** Convenience method to get current count from [[ElementSetTool.agenda]]. */
    protected get currentElementCount(): number;
    /** Minimum required number of elements for tool to be able to complete.
     * @return number to compare with [[ElementSetTool.currentElementCount]] to determine if more elements remain to be identified.
     * @note A tool to subtract elements is an example where returning 2 would be necessary.
     */
    protected get requiredElementCount(): number;
    /** Whether to allow element identification by drag box or crossing line selection.
     * @return true to allow drag select as an element source when the ctrl key is down.
     * @note Use ctrl+left drag for box selection. Inside/overlap is based on left/right direction (shift key inverts).
     * @note Use ctrl+right drag for crossing line selection.
     */
    protected get allowDragSelect(): boolean;
    /** Support operations on groups/assemblies independent of selection scope.
     * @return true to add or remove all members of an assembly from [[ElementSetTool.agenda]] when any single member is identified.
     * @note Applies to [[ElementSetTool.getLocateCandidates]] only.
     */
    protected get allowGroups(): boolean;
    /** Whether [[ElementSetTool.agenda]] should be populated from an active selection set.
     * @return true to allow selection sets as an element source.
     * @note A selection set must have at least [[ElementSetTool.requiredElementCount]] elements to be considered.
     */
    protected get allowSelectionSet(): boolean;
    /** Whether to clear the active selection set for tools that return false for [[ElementSetTool.allowSelectionSet]].
     * @return true to clear unsupported selection sets (desired default behavior).
     * @note It is expected that the selection set be cleared before using [[ElementLocateManager]] to identify elements.
     * This allows the element hilite to be a visual representation of the [[ElementSetTool.agenda]] contents.
     */
    protected get clearSelectionSet(): boolean;
    /** Whether a selection set should be processed immediately upon installation or require a data button to accept.
     * @return false only for tools without settings or a need for confirmation.
     * @note A tool to delete elements is an example where returning false could be desirable.
     */
    protected get requireAcceptForSelectionSetOperation(): boolean;
    /** Whether to begin dynamics for a selection set immediately or wait for a data button.
     * @return false for tools that can start showing dynamics without any additional input.
     * @note A tool to rotate elements by an active angle setting is an example where returning false could be desirable.
     */
    protected get requireAcceptForSelectionSetDynamics(): boolean;
    /** Whether original source of elements being modified was the active selection set.
     * @return true when [[ElementSetTool.allowSelectionSet]] and active selection set count >= [[ElementSetTool.requiredElementCount]].
     */
    protected get isSelectionSetModify(): boolean;
    /** Whether drag box or crossing line selection is currently active.
     * @return true when [[ElementSetTool.allowDragSelect]] and corner points are currently being defined.
     */
    protected get isSelectByPoints(): boolean;
    /** Whether to continue selection of additional elements by holding the ctrl key down.
     * @return true to continue the element identification phase beyond [[ElementSetTool.requiredElementCount]] by holding down the ctrl key.
     */
    protected get controlKeyContinuesSelection(): boolean;
    /** Whether to invert selection of elements identified with the ctrl key held down.
     * @return true to allow ctrl to deselect already selected elements.
     */
    protected get controlKeyInvertsSelection(): boolean;
    /** Whether [[ElementSetTool.setupAndPromptForNextAction]] should call [[AccuSnap.enableSnap]] for current tool phase.
     * @return true to enable snapping to elements.
     * @note A tool that just needs to identify elements and doesn't care about location should not enable snapping.
     */
    protected get wantAccuSnap(): boolean;
    /** Whether to automatically start element dynamics after all required elements have been identified.
     * @return true if tool will implement [[InteractiveTool.onDynamicFrame]] to show element dynamics.
     */
    protected get wantDynamics(): boolean;
    /** Whether tool is done identifying elements and is ready to move to the next phase.
     * @return true when [[ElementSetTool.requiredElementCount]] is not yet satisfied or ctrl key is being used to extend selection.
     */
    protected get wantAdditionalElements(): boolean;
    /** Whether the tool has gathered enough input to call [[ElementSetTool.processAgenda]].
     * Sub-classes should override to check for additional point input they collected in [[ElementSetTool.wantProcessAgenda]].
     * @return true if tool does not yet have enough information to complete.
     * @note When [[ElementSetTool.wantDynamics]] is true an additional point is automatically required to support the dynamic preview.
     */
    protected get wantAdditionalInput(): boolean;
    /** Whether the tool is ready for [[ElementSetTool.processAgenda]] to be called to complete the tool operation.
     * Sub-classes should override to collect additional point input before calling super or [[ElementSetTool.wantAdditionalInput]].
     * @return true if tool has enough information and is ready to complete.
     */
    protected wantProcessAgenda(_ev: BeButtonEvent): boolean;
    /** Whether tool should operate on an existing selection set or instead prompt user to identity elements.
     * Unsupported selection sets will be cleared when [[ElementSetTool.clearSelectionSet]] is true.
    */
    protected setPreferredElementSource(): void;
    /** Get element ids to process from the active selection set.
     * Sub-classes may override to support selection scopes or apply tool specific filtering.
     */
    protected getSelectionSetCandidates(ss: SelectionSet): Promise<Id64Arg>;
    /** Populate [[ElementSetTool.agenda]] from a [[SelectionSet]].
     * @see [[ElementSetTool.getSelectionSetCandidates]] to filter or augment the set of elements.
     */
    protected buildSelectionSetAgenda(ss: SelectionSet): Promise<boolean>;
    /** If the supplied element is part of an assembly, return all member ids. */
    protected getGroupIds(id: Id64String): Promise<Id64Arg>;
    /** Get element id(s) to process from a [[HitDetail]] already accepted by [[ElementSetTool.isElementValidForOperation]].
     * Sub-classes may override to support selection scopes.
     */
    protected getLocateCandidates(hit: HitDetail): Promise<Id64Arg>;
    /** Populate [[ElementSetTool.agenda]] from a [[HitDetail]].
     * @see [[ElementSetTool.getLocateCandidates]] to add additional elements.
     */
    protected buildLocateAgenda(hit: HitDetail): Promise<boolean>;
    /** Get ids of spatial elements to process from a clip volume created by drag box selection. */
    private static getVolumeSelectionCandidates;
    /** Get ids of visible elements to process from drag box or crossing line selection. */
    private static getAreaSelectionCandidates;
    /** Get ids of elements to process from drag box or crossing line selection using either the depth buffer or clip vector...
     * @internal
     */
    static getAreaOrVolumeSelectionCandidates(vp: Viewport, origin: XAndY, corner: XAndY, method: SelectionMethod, allowOverlaps: boolean, filter?: (id: Id64String) => boolean, includeDecorationsForVolume?: boolean): Promise<Set<Id64String>>;
    /** Get element ids to process from drag box or crossing line selection.
     * Sub-classes may override to support selection scopes or apply tool specific filtering.
     */
    protected getDragSelectCandidates(vp: Viewport, origin: Point3d, corner: Point3d, method: SelectionMethod, overlap: boolean): Promise<Id64Arg>;
    /** Populate [[ElementSetTool.agenda]] by drag box or crossing line information.
     * @see [[ElementSetTool.getDragSelectCandidates]] to filter or augment the set of elements.
     */
    protected buildDragSelectAgenda(vp: Viewport, origin: Point3d, corner: Point3d, method: SelectionMethod, overlap: boolean): Promise<boolean>;
    /** Quick id validity check. Sub-classes that wish to allow pickable decorations from selection sets can override. */
    protected isElementIdValid(id: Id64String, source: ModifyElementSource): boolean;
    /** Sub-classes should override to apply tool specific filtering and to provide an explanation for rejection. */
    protected isElementValidForOperation(hit: HitDetail, _out?: LocateResponse): Promise<boolean>;
    /** Called from [[ElementSetTool.doLocate]] as well as auto-locate to accept or reject elements under the cursor. */
    filterHit(hit: HitDetail, out?: LocateResponse): Promise<LocateFilterStatus>;
    /** Identify an element and update the element agenda.
     * @param newSearch true to locate new elements, false to cycle between elements within locate tolerance from a previous locate.
     * @return true if [[ElementSetTool.agenda]] was changed.
     */
    protected doLocate(ev: BeButtonEvent, newSearch: boolean): Promise<boolean>;
    /** Whether drag box selection only identifies elements that are wholly inside or also allows those that overlap
     * the selection rectangle.
     * @note Inside/overlap is based on left/right direction of corner points (shift key inverts check).
     */
    protected useOverlapSelection(ev: BeButtonEvent): boolean;
    /** Initiate tool state for start of drag selection. */
    protected selectByPointsStart(ev: BeButtonEvent): Promise<boolean>;
    /** Finish drag selection and update [[ElementSetTool.agenda]] with any elements that may have been identified. */
    protected selectByPointsEnd(ev: BeButtonEvent): Promise<boolean>;
    /** Display drag box and crossing line selection graphics. */
    protected selectByPointsDecorate(context: DecorateContext): void;
    /** Show graphics for when drag selection is active. */
    decorate(context: DecorateContext): void;
    /** Make sure drag selection graphics are updated when mouse moves. */
    onMouseMotion(ev: BeButtonEvent): Promise<void>;
    /** Support initiating drag selection on mouse start drag event when [[ElementSetTool.allowDragSelect]] is true. */
    onMouseStartDrag(ev: BeButtonEvent): Promise<EventHandled>;
    /** Support completing active drag selection on mouse end drag event and update [[ElementSetTool.agenda]]. */
    onMouseEndDrag(ev: BeButtonEvent): Promise<EventHandled>;
    /** Update prompts, cursor, graphics, etc. as appropriate on ctrl and shift key transitions. */
    onModifierKeyTransition(_wentDown: boolean, modifier: BeModifierKeys, _event: KeyboardEvent): Promise<EventHandled>;
    /** Allow reset to cycle between elements identified for overlapping the locate circle.
     * Advances to next pre-located hit from [[AccuSnap.aSnapHits]] or changes last accepted hit to next hit from [[ElementLocateManger.hitList]].
     * @returns EventHandled.Yes if onReinitialize was called to restart or exit tool.
     */
    protected chooseNextHit(ev: BeButtonEvent): Promise<EventHandled>;
    /** Orchestrates updating the internal state of the tool on a reset button event.
     * @returns EventHandled.Yes if onReinitialize was called to restart or exit tool.
     */
    protected processResetButton(ev: BeButtonEvent): Promise<EventHandled>;
    onResetButtonUp(ev: BeButtonEvent): Promise<EventHandled>;
    onResetButtonDown(ev: BeButtonEvent): Promise<EventHandled>;
    /** Collect element input until tool has a sufficient number to complete. */
    protected gatherElements(ev: BeButtonEvent): Promise<EventHandled | undefined>;
    /** Collect point input until tool has a sufficient number to complete. */
    protected gatherInput(ev: BeButtonEvent): Promise<EventHandled | undefined>;
    /** Orchestrates advancing the internal state of the tool on a data button event.
     * - Collect elements: Add to the element agenda until no additional elements are requested.
     * - Gather input: Initiates element dynamics and accepts additional points as required.
     * - Complete operation: Process agenda entries, restart or exit tool.
     * @returns EventHandled.Yes if onReinitialize was called to restart or exit tool.
     */
    protected processDataButton(ev: BeButtonEvent): Promise<EventHandled>;
    onDataButtonUp(ev: BeButtonEvent): Promise<EventHandled>;
    onDataButtonDown(ev: BeButtonEvent): Promise<EventHandled>;
    protected initAgendaDynamics(): Promise<boolean>;
    /** Sub-classes can override to be notified of [[ElementSetTool.agenda]] changes by other methods.
     * @note Tools should not modify [[ElementSetTool.agenda]] in this method, it should merely serve as a convenient place
     * to update information, such as element graphics once dynamics has started, ex. [[ElementSetTool.chooseNextHit]].
    */
    protected onAgendaModified(): Promise<void>;
    /** Sub-classes can override to continue with current [[ElementSetTool.agenda]] or restart after processing has completed. */
    protected onProcessComplete(): Promise<void>;
    /** Sub-classes that return false for [[ElementSetTool.requireAcceptForSelectionSetOperation]] should override to apply the tool operation to [[ElementSetTool.agenda]]. */
    protected processAgendaImmediate(): Promise<void>;
    /** Sub-classes that require and use the accept point should override to apply the tool operation to [[ElementSetTool.agenda]].
     * @note Not called for [[ElementSetTool.isSelectionSetModify]] when [[ElementSetTool.requireAcceptForSelectionSetOperation]] is false.
     */
    protected processAgenda(_ev: BeButtonEvent): Promise<void>;
    /** Support either [[ElementSetTool.requireAcceptForSelectionSetOperation]] or [[ElementSetTool.requireAcceptForSelectionSetDynamics]] returning false. */
    protected doProcessSelectionSetImmediate(): Promise<void>;
    /** Setup initial element state, prompts, check [[SelectionSet]], etc. */
    onPostInstall(): Promise<void>;
    /** Make sure elements from [[ElementSetTool.agenda]] that aren't also from [[SelectionSet]] aren't left hilited. */
    onCleanup(): Promise<void>;
    /** Exit and start default tool when [[ElementSetTool.isSelectionSetModify]] is true to allow [[SelectionSet]] to be modified,
     * or call [[PrimitiveTool.onRestartTool]] to install a new tool instance.
     */
    onReinitialize(): Promise<void>;
    /** Restore tool assistance after no longer being suspended by either a [[ViewTool]] or [[InputCollector]]. */
    onUnsuspend(): Promise<void>;
    protected get shouldEnableLocate(): boolean;
    protected get shouldEnableSnap(): boolean;
    /** Setup auto-locate, AccuSnap, AccuDraw, and supply tool assistance. */
    protected setupAndPromptForNextAction(): void;
    /** Sub-classes should override to provide tool specific instructions. */
    protected provideToolAssistance(mainInstrText?: string, additionalInstr?: ToolAssistanceInstruction[]): void;
}
//# sourceMappingURL=ElementSetTool.d.ts.map