/** @packageDocumentation
 * @module RangeSearch
 */
import { Range3d } from "../../geometry3d/Range";
/** Type name FlexData is shorthand for a member or parameter which can be:
 * * undefined
 * * an array of values of type T
 * * a singleton of type T
 */
type FlexData<T> = undefined | T[] | T;
/**
 * Type name IndexToType is shorthand for a member or parameter which can be:
 * * an array of values of type T
 * * a function from integers to type T.
 */
type IndexToType<T> = T[] | ((index: number) => T);
/**
 * Abstract class for handler objects called during traversal of a single range tree.
 * @internal
 */
export declare abstract class SingleTreeSearchHandler<AppDataType> {
    /** Return true if appData within the range should be offered to `processAppData`. */
    abstract isRangeActive(range: Range3d): boolean;
    /**
     * Called for a (single) child referenced by a tree.
     * * This is only called when range checks on the path from root have been passed.
     * @param item child (of type AppDataType) in the tree.
     */
    abstract processAppData(item: AppDataType): void;
    /**
     * Query to see if the active search has been aborted.
     * * Default implementation returns false so query runs to completion.
     * * Search processes check this after range tests and child processing.
     */
    getIsAborted(): boolean;
}
/**
 * Abstract class for handler objects called during traversal of two range trees.
 * @internal
 */
export declare abstract class TwoTreeSearchHandler<AppDataType> {
    /** Return true if appData within the ranges should be offered to `processAppDataPair`. */
    abstract isRangePairActive(leftRange: Range3d, rightRange: Range3d): boolean;
    /**
     * Called with AppDataType items from left tree and right tree.
     * * This is only called when range tests have been passed.
     * @param leftItem
     * @param rightItem
     */
    abstract processAppDataPair(leftItem: AppDataType, rightItem: AppDataType): void;
    /**
     * Query to see if the active search has been aborted.
     * * Default implementation returns false so query runs to completion.
     * * Search processes check this after range tests and child processing.
     */
    getIsAborted(): boolean;
    /** Whether to ignore z-coordinates in distance computations. */
    getXYOnly(): boolean;
}
/**
 * This class refines the TwoTreeSearchHandler with an implementation of `isRangePairActive` appropriate for computing the minimum distance between trees.
 * * The concrete class must implement `getCurrentDistance()` method to provide the best-so-far distance.
 * * The implementation of `isRangePairActive` returns true if the distance between ranges is less than or equal to the `getCurrentDistance()` value.
 * @internal
 */
export declare abstract class TwoTreeDistanceMinimizationSearchHandler<AppDataType> extends TwoTreeSearchHandler<AppDataType> {
    /**
     * Provides the allowable distance between ranges.
     * * Range pairs with more than this distance separation are rejected.
     * * The implementation may alter (probably reduce) the getCurrentDistance() value as the search progresses.
     */
    abstract getCurrentDistance(): number;
    /**
     * Method called to decide whether to process subtrees and immediate child appData items from a left tree node and right tree node.
     * @param leftRange range from a node in the left tree
     * @param rightRange range from a node in the right tree.
     * @returns true if the smallest distance from leftRange to rightRange is less than or equal to getCurrentDistance()
     */
    isRangePairActive(leftRange: Range3d, rightRange: Range3d): boolean;
}
/**
 * * TREE STRUCTURE
 *   * A RangeTreeNode is part of a range tree.
 *   * TREE is used here in a strictly _structural_ sense, which has no broad promises about data members.
 *   * Each RangeNode points to 0, 1 or many children.
 *   * Each child has (but does not point back to) a single parent.
 *   * The overall tree has a single root.
 *   * Each node is effectively the root of the tree of its children.
 * * NON-TREE DATA MEMBERS
 *   * Data members in each node (in addition to children) are
 *     * _range = the union of ranges below in the heap
 *     * _appData = application data associated with the node.
 *       * Construction methods may place multiple _appData items in each node.
 *       * In common use, only the leaves will have _appData. However, the class definitions allow _appData at all nodes, and search algorithms must include them.
 * * CONSTRUCTION
 *   * The RangeTreeNode.createByIndexSplits method constructs the tree with simple right-left splits within an array of input items.
 *     * The appData is placed entirely in the leaves.
 *     * The caller can specify:
 *       * the number of _appData items per leaf
 *       * the number of children per node within the tree.
 *     * Compared to "shallow" trees with many children per node and many appData per leaf, "deep" trees with 2 children per node and 1 appData per leaf may have:
 *       * faster search because lower nodes have smaller ranges that will be skipped by search algorithms.
 *       * larger memory use because of more nodes
 *   * For future construction methods:
 *      * _appData "above the leaves" may allow nodes below to have smaller ranges, but add complexity to search.
 * @internal
 */
export declare class RangeTreeNode<AppDataType> {
    private _range;
    private _appData;
    private _children;
    /** an id assigned sequentially as nodes are created.  For debugging use only. */
    private _id;
    /**
     * CONSTRUCTOR
     * CAPTURE (not copy)
     * * range = range for search algorithms
     * * appData = application data relevant to this node.
     * * children = child node reference(s).
     */
    private constructor();
    /** Simplest public create: capture the range, appData, and children. */
    static createCapture<AppDataType>(range: Range3d, appData: FlexData<AppDataType>, children: FlexData<RangeTreeNode<AppDataType>>): RangeTreeNode<AppDataType>;
    /** copy (not capture) from given data into the range in this RangeEntry */
    setRange(data: Range3d): void;
    /** return (a copy of) the range in this RangeEntry */
    getRange(data?: Range3d): Range3d;
    /** return (a reference to) the range in this RangeEntry */
    getRangeRef(): Range3d;
    /**
     * Access a child by index.
     * * If the child data is an array, this dereferences the array.
     * * If the child data is a singleton, treat it as index 0.
     * * return undefined if there are no children.
     * @param index index of item to access.
     */
    getChildByIndex(index: number): RangeTreeNode<AppDataType> | undefined;
    /**
     * * Access an appData by index.
     * * If the appData data is an array, this dereferences the array.
     * * If the appData data is a singleton, treat it as if it is at index 0 in an array
     * * return undefined if there are no appData or for any index out of range.
     * @param index index of item to access.
     */
    getAppDataByIndex(index: number): AppDataType | undefined;
    /** Access the children or child (does not clone). */
    getAllChildren(): FlexData<RangeTreeNode<AppDataType>>;
    /** Access the appData array or singleton (does not clone). */
    getAllAppData(): FlexData<AppDataType>;
    /**
     * Count the direct children in this node of the tree.
     * * This is not recursive. For a recursive count, use `RangeTreeOps.getRecursiveNodeCount`.
     */
    getNumChildren(): number;
    /**
     * Count the appData items in this node of the tree.
     * * This is not recursive. For a recursive count, use `RangeTreeOps.getRecursiveAppDataCount`.
     */
    getNumAppData(): number;
    /**
     * Depth-first tree iteration, calling `announceNode` on each node.
     * @param announceNode callback that returns true to recurse into children
     */
    recurseIntoTree(announceNode: (node: RangeTreeNode<AppDataType>) => boolean): void;
    /**
     * Depth-first tree iteration via handler.
     * * if handler decides the instance range is active, process appData, then recurse on children
     * * if handler decides to abort after processing an appData, skip processing rest of appData and children
     */
    searchTopDown(handler: SingleTreeSearchHandler<AppDataType>): void;
    /**
     * Apply the handler.processAppDataPair method to each pair of appData items from leftAppData and rightStack.
     * @param leftAppData singleton or array with data "from left"
     * @param rightStack stack of nodes to process from right path.
     * @param reverseArgs true if the caller is exchanging the sense of left and right and this should be undone in the actual call to handler.processAppDataPair.
     * @param handler search handler
     */
    private static processAppDataAndAppDataStack;
    /**
     * Apply the handler.processAppDataPair method to each pair of appData items from leftAppData and rightAppData.
     * @param leftAppData singleton or array with data "from left"
     * @param rightAppData singleton or array with data "from right"
     * @param reverseArgs true if the caller is exchanging the sense of left and right and this should be undone in the actual call to handler.processAppDataPair.
     * @param handler search handler
     */
    private static processAppDataAndAppData;
    /**
     * Push the tip node to stack(s).
     * @param tip new node (to be pushed)
     * @param fullPath complete path, which is always extended
     * @param partialPath partial path, which is only extended if the tip has _appData.
     */
    private static pushPaths;
    /**
     * Pop the tip node from stack(s).
     * @param tip should match the fullPath tip.
     * @param fullPath complete path, which is always popped
     * @param partialPath partial path, which is only popped if the tip has _appData.
     */
    private static popPaths;
    /**
     * Process nodes from left and right trees of dual search.
     * * The separate stacks for nodes that have appData is for efficiency.
     * * If data is entirely in the leaves (or just in a few nodes), the stacks will all be empty (or very small) and no time will be wasted looking up the stacks for appData to process with the other tip.
     * @param leftTip tip node being explored on left
     * @param leftStack stack of prior left nodes
     * @param leftStackWithAppData stack of prior left nodes which have appData.
     * @param rightTip tip node being explored on right.
     * @param rightStack stack of prior right nodes.
     * @param rightStackWithAppData stack of prior right nodes which have appData.
     * @param handler search handler
     */
    private static recursivePairSearch;
    /**
     * Recurse below the tip of leftTip, offering each level's appData to the appData of rightTip and rightStackWithAppData.
     * @param leftTip tip node being explored on left. Its appData is not processed.
     * @param rightTip tip node being explored on right. It has no children.
     * @param rightStackWithAppData stack of prior right nodes which have appData.
     * @param reverseArgs true if the caller is exchanging the sense of left and right
     * @param handler search handler
     */
    private static leftRecursivePairSearch;
    /**
     * Recursive search down two trees, with range tests and child processing under control of a handler.
     * @param leftRoot root of left tree
     * @param rightRoot root of right tree
     * @param handler handler for range tests and child process
     */
    static searchTwoTreesTopDown<AppDataType>(leftRoot: RangeTreeNode<AppDataType>, rightRoot: RangeTreeNode<AppDataType>, handler: TwoTreeSearchHandler<AppDataType>): void;
}
/**
 * Utilities for various operations on RangeTree
 * @internal
 */
export declare class RangeTreeOps {
    /** Count nodes in this tree. */
    static getRecursiveNodeCount<AppDataType>(root: RangeTreeNode<AppDataType>): number;
    /** Count appData in this tree. */
    static getRecursiveAppDataCount<AppDataType>(root: RangeTreeNode<AppDataType>): number;
    /**
     * Create a leaf referencing appData items indexed index0<=index<index1 and with combined range of the same indices
     * @param ranges access to ranges
     * @param appData access to AppDataType items
     * @param index0 first index for block of items
     * @param index1 upper limit index for block of items.
     * @param arrayLength one more than the largest range/appData index
     * @returns newly created node.
     */
    private static createLeafInIndexRange;
    /**
     * Split the array entries appData[index0 <= i < index1] into blocks of at most maxChildPerNode * maxAppDataPerLeaf and assemble into a tree structure.
     * @param ranges access to ranges
     * @param appData access to AppDataType items
     * @param index0 start index of the block to access
     * @param index1 terminal index for the block (one after final)
     * @param arrayLength one more than the largest range/appData index
     * @param maxChildPerNode max number of child nodes in each interior node
     * @param maxAppDataPerLeaf max number of appData items in each leaf.
     * @returns
     */
    private static createRecursiveByIndexSplits;
    /**
     * Create a range tree by simple left-right split of given ranges.
     * * Leaves carry the inputs in left-to-right order.
     * * Each leaf range is labeled by its corresponding object(s) in the appData array.
     * @param ranges access to ranges.
     * @param appData access to AppDataType items (for leaves).
     * @param arrayLength one more than the largest range/appData index
     * @param maxChildrenPerNode max number of child nodes allowed for each interior node.
     * @param maxAppDataPerLeaf max number of appData items allowed in each leaf.
     * @returns the root of the new tree, or undefined if array lengths differ or are zero.
     */
    static createByIndexSplits<AppDataType>(ranges: IndexToType<Range3d>, appData: IndexToType<AppDataType>, arrayLength: number, maxChildrenPerNode?: number, maxAppDataPerLeaf?: number): RangeTreeNode<AppDataType> | undefined;
}
export {};
//# sourceMappingURL=RangeTreeNode.d.ts.map