import { Node } from '@vertexvis/scene-tree-protos/scenetree/protos/domain_pb';
import { GetTreeResponse, SubscribeResponse } from '@vertexvis/scene-tree-protos/scenetree/protos/scene_tree_api_pb';
import { ResponseStream, SceneTreeAPIClient } from '@vertexvis/scene-tree-protos/scenetree/protos/scene_tree_api_pb_service';
import { Disposable, EventDispatcher, Listener } from '@vertexvis/utils';
import { MetadataKey } from '../types';
import { SceneTreeErrorDetails } from './errors';
import { Row } from './row';
export interface ConnectOptions {
    spinnerDelay: number;
    idleReconnectInSeconds?: number;
    lostConnectionReconnectInSeconds?: number;
    subscriptionHandshakeGracePeriodInMs?: number;
}
export type JwtProvider = () => string | undefined;
export interface SceneTreeState {
    totalRows: number;
    totalFilteredRows?: number;
    rows: Row[];
    connection: ConnectionState;
    isSearching: boolean;
    shouldShowLoading?: boolean;
    shouldShowEmptyResults?: boolean;
    filterTerm?: string;
    handshakeReceived?: boolean;
    firstFetchComplete?: boolean;
    isPartialFilterResponse?: boolean;
    isPartialKeysResponse?: boolean;
    filterOptions?: FilterTreeOptions;
}
interface Page {
    id: number;
    index: number;
    metadataKeys: MetadataKey[];
    res: Promise<GetTreeResponse>;
    done?: Promise<void>;
}
export interface DisconnectedState {
    type: 'disconnected';
    jwtProvider?: JwtProvider;
    sceneViewId?: string;
}
export interface ConnectingState {
    type: 'connecting';
    jwtProvider: JwtProvider;
    sceneViewId: string;
}
export interface SubscriptionStatusState {
    attempt: number;
    stream: ResponseStream<SubscribeResponse>;
}
export interface ConnectedState {
    type: 'connected';
    jwtProvider: JwtProvider;
    sceneViewId: string;
    subscription: Disposable;
    subscriptionStatusState?: SubscriptionStatusState;
}
export interface ConnectionFailedState {
    type: 'failure';
    details: SceneTreeErrorDetails;
    jwtProvider: JwtProvider;
    sceneViewId: string;
}
export interface ConnectionCancelledState {
    type: 'cancelled';
    jwtProvider?: JwtProvider;
    sceneViewId?: string;
}
/**
 * A set of options to configure tree filtering behavior.
 */
export interface FilterTreeOptions {
    /**
     * Indicates if the filter should include nodes that within collapsed parent
     * nodes.
     */
    includeCollapsed?: boolean;
    /**
     * Indicates if the filter should be an exact match with the results.
     */
    exactMatch?: boolean;
    /**
     * Indicates whether the metadata search should remove hidden items from the results.
     */
    removeHiddenItems?: boolean;
    /**
     * The metadata keys to filter the tree on.
     */
    columns?: MetadataKey[];
}
type ConnectionState = DisconnectedState | ConnectingState | ConnectedState | ConnectionFailedState | ConnectionCancelledState;
/**
 * The `SceneTreeController` is responsible for coordinating interactions of the
 * view, fetching and mutating tree data on the server, maintaining state and
 * notifying the view about state changes.
 */
export declare class SceneTreeController {
    private client;
    private rowLimit;
    private connectOptions;
    private static IDLE_RECONNECT_IN_SECONDS;
    private static LOST_CONNECTION_RECONNECT_IN_SECONDS;
    private static MAX_SUBSCRIPTION_RETRY_COUNT;
    private nextPageId;
    private pages;
    private activeRowRange;
    private metadataKeys;
    private debugLogs;
    private pendingFilterGrpcRes?;
    private reconnectTimer?;
    private loadingTimer?;
    private subscriptionHandshakeTimer?;
    /**
     * A dispatcher that emits an event whenever the internal state has changed.
     */
    onStateChange: EventDispatcher<SceneTreeState>;
    private state;
    /**
     * The number of pages that have been fetched.
     */
    get fetchedPageCount(): number;
    /**
     * Indicates if the controller is connected to the tree backend, and can make
     * requests.
     */
    get isConnected(): boolean;
    constructor(client: SceneTreeAPIClient, rowLimit: number, connectOptions?: ConnectOptions);
    /**
     * Registers an event listener that will be invoked when the state changes
     *
     * @param listener The listener to add.
     * @returns A disposable that can be used to remove the listener.
     */
    stateChanged(listener: Listener<SceneTreeState | undefined>): Disposable;
    setDebugLogs(debugLogs: boolean): void;
    private handleSubscriptionHandshakeTimeout;
    connect(jwtProvider: JwtProvider): Promise<void>;
    private clearReconnectTimer;
    private restartHandshakeTimer;
    private clearHandshakeTimer;
    private startIdleReconnectTimer;
    private startConnectionLostReconnectTimer;
    private startReconnectTimer;
    connectToViewer(viewer: HTMLVertexViewerElement): Disposable;
    disconnect(reset?: boolean): void;
    cancel(): void;
    /**
     * Collapses a node with the given node ID.
     *
     * @param id A node ID to collapse.
     */
    collapseNode(id: string): Promise<void>;
    /**
     * Expands a node with the given node ID.
     *
     * @param id A node ID to expand.
     */
    expandNode(id: string): Promise<void>;
    /**
     * Collapses all nodes in the tree.
     */
    collapseAll(): Promise<void>;
    /**
     * Expands all nodes in the tree.
     */
    expandAll(): Promise<void>;
    /**
     * Invokes a network request that will expand all the parent nodes for the
     * node mapped to the given ID.
     *
     * @param id An ID of an item.
     * @returns A promise that resolves with the index of the node after
     *  expansion.
     */
    expandParentNodes(id: string): Promise<number>;
    fetchNodeAncestors(nodeId: string): Promise<Node.AsObject[]>;
    /**
     * Fetches a page at the given index. Once the data has been fetched, the
     * controller will emit an `onStateChange` event that contains rows with the
     * fetched page. If a page is invalidated before the request completes, the
     * response is ignored.
     *
     * If the index is out of range, returns without fetching any data.
     *
     * @param index A 0 based index to fetch.
     */
    fetchPage(index: number): Promise<void>;
    /**
     * Fetches a page that contains the given row offset.
     *
     * @param offset The row offset of the page to fetch.
     */
    fetchPageAtOffset(offset: number): Promise<void>;
    /**
     * Fetches pages that contain the given row ranges.
     *
     * @param startOffset A start offset, inclusive.
     * @param endOffset The end offset, inclusive.
     */
    fetchRange(startOffset: number, endOffset: number): Promise<void>;
    /**
     * Fetches the metadata keys for the current scene view.
     */
    fetchMetadataKeys(): Promise<MetadataKey[]>;
    /**
     * Refreshes the filter by re-filtering the current filter term.
     * @returns A promise that resolves when the filter is refreshed.
     */
    refreshFilter(): Promise<void>;
    /**
     * Performs a network request that will filter the nodes in the tree that
     * match the given term and options.
     *
     * @param term The filter term.
     * @param options The options to apply to the filter.
     */
    filter(term: string, options?: FilterTreeOptions): Promise<void>;
    /**
     * Checks if the page at the given index is loaded.
     *
     * @param index A page index.
     * @returns `true` if the page is loaded. `false` otherwise.
     */
    isPageLoaded(index: number): boolean;
    /**
     * Returns a list of page indices within a range that have not been loaded.
     *
     * @param start The start page index, inclusive.
     * @param end The end page index, inclusive.
     * @returns A list of pages indices that have not been loaded.
     */
    getNonLoadedPageIndexes(start: number, end: number): number[];
    /**
     * @internal
     * @ignore
     *
     * Visible for testing.
     */
    getActiveRowRange(): number[];
    /**
     * Returns the page at the given index, or `undefined` if one doesn't exist.
     *
     * @param index The index to return.
     * @returns A `Page` if found, otherwise `undefined`.
     */
    getPage(index: number): Page | undefined;
    /**
     * Clears page data that is outside a given range. Uses a distance algorithm
     * to removes pages that are furthest from either end of the range. This
     * method is useful for clearing out data that is not needed anymore to keep
     * memory pressure in the client low.
     *
     * @param startPage The index of the starting page in the range.
     * @param endPage The index of the ending page in the range.
     * @param threshold A minimum number of pages to keep. No cleanup is performed
     *  if the number of fetched pages doesn't meet this threshold.
     */
    invalidatePagesOutsideRange(startPage: number, endPage: number, threshold?: number): void;
    setMetadataKeys(keys: MetadataKey[]): Promise<void>;
    /**
     * Sets the active rows. Active rows dictate which pages will be refetched
     * when the tree changes.
     *
     * @param start The starting row index.
     * @param end The ending row index.
     * @returns A promise that resolves when the first page of data has been
     *  loaded.
     */
    updateActiveRowRange(start: number, end: number): Promise<void>;
    /**
     * Performs a network request that will listen to server-side changes of the
     * scene tree's data.
     */
    private subscribe;
    private fetchUnloadedPagesInActiveRows;
    private patchNodesInRange;
    private handlePageResult;
    private invalidatePage;
    private invalidateAfterOffset;
    private getState;
    private isViewLoading;
    private restartLoadingTimer;
    private clearLoadingTimer;
    private tryClearLoadingState;
    private tryClearLoadingTimer;
    /**
     * @internal
     * @ignore
     *
     * Visible for testing.
     */
    updateState(newState: SceneTreeState): void;
    getPageForOffset(offset: number): number;
    getPageIndexesForRange(start: number, end: number): [number, number];
    private fetchTree;
    private requestUnary;
    private requestServerStream;
    private createJwtMetadata;
    private ifConnectionHasJwt;
    private ifErrorIsFatal;
    private getConnectionError;
    private constrainPageRange;
    private constrainPageIndex;
    private constrainRowOffsets;
    private get maxPages();
    private log;
    private isConnectedState;
}
export {};
