/**
 * Copyright (c) 2020-present, Goldman Sachs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { type GeneratorFn, LogEvent, ActionState } from '@finos/legend-shared';
import type { EditorStore } from './EditorStore.js';
import type { EditorGraphState } from './EditorGraphState.js';
import type { Entity } from '@finos/legend-storage';
import { type EntityChangeConflictResolution, EntityChangeConflict, EntityDiff } from '@finos/legend-server-sdlc';
import { ObserverContext } from '@finos/legend-graph';
declare class RevisionChangeDetectionState {
    editorStore: EditorStore;
    graphState: EditorGraphState;
    changes: EntityDiff[];
    entityHashesIndex: Map<string, string>;
    isBuildingEntityHashesIndex: boolean;
    entities: Entity[];
    currentEntityHashesIndex: Map<string, string>;
    setEntityHashesIndex(hashesIndex: Map<string, string>): void;
    setIsBuildingEntityHashesIndex(building: boolean): void;
    setEntities(entities: Entity[]): void;
    constructor(editorStore: EditorStore, graphState: EditorGraphState);
    computeChanges(quiet?: boolean): GeneratorFn<void>;
    computeChangesInTextMode(currentEntities: Entity[], quiet?: boolean): GeneratorFn<void>;
    buildEntityHashesIndex(entities: Entity[], logEvent: LogEvent, quiet?: boolean): GeneratorFn<void>;
}
/**
 * In the SDLC flow of the app, there are several important revision that we want to keep track of. See diagram below:
 *
 *    (1. PJL)
 *     |
 *     |
 *    (2. CRB) ------- (3. CRH) ------ (4. CRL)
 *     |
 *     |
 *    (5. WSB) ------- (6. WSH) ------ (7. WSL)
 *     |
 *    ... (earlier revisions in the project)
 *
 * Annotations:
 * 1. PJL: Project HEAD revision
 * 2. CRB: Conflict resolution BASE revision
 * 3. CRH: Conflict resolution HEAD revision
 * 4. CRL: Conflict resolution LIVE revision (i.e. local graph state in conflict resolution mode)
 * 5. WSB: Workspace BASE revision
 * 6. WSH: Workspace HEAD revision
 * 7. WSL: Workspace LIVE revision (i.e. local graph state in standard mode)
 */
export declare class ChangeDetectionState {
    editorStore: EditorStore;
    graphState: EditorGraphState;
    graphObserveState: ActionState;
    initState: ActionState;
    /**
     * Keep the list of disposers to deactivate `keepAlive` for computed value of element hash code.
     * See {@link preComputeGraphElementHashes} for more details
     */
    private graphElementHashCodeKeepAliveComputationDisposers;
    private changeDetectionReaction?;
    /**
     * [1. PJL] Store the entities from project HEAD (i.e. project latest revision)
     * This can be used to compute changes for a review as well as changes and potential conflicts when updating workspace
     */
    projectLatestRevisionState: RevisionChangeDetectionState;
    /**
     * [2. CRB] Store the entities from the BASE revision of workspace with conflict resolution (this is different from the current workspace the user is on)
     * NOTE: the flow for conflict resolution is briefly like this (assume current user workspace is `w1`):
     * 1. When the user chooses to update workspace `w1`, the backend will compute changes between `w1` HEAD and `w1` BASE
     * 2. Create a new conflict resolution branch on top of project HEAD
     * 3. Apply the changes on this branch.
     *
     * So we now have 2 branchs normal `w1` and `w1` in conflict resolution. From the user perspective, they might not need to know this
     * So in the app, we have to check for the existence of the conflict resolution branch and make it supercede the original `w1` branch
     *
     * This branch, thus, will be used to show the users all the changes they have on top of conflict resolution BASE revision
     * during conflict resolution stage
     */
    conflictResolutionBaseRevisionState: RevisionChangeDetectionState;
    /**
     * [3. CRH] Store the entities from the conflict resolution HEAD revision
     * This is used for computing the live diff, so that when we mark conflicts as resolved and accept conflict resolution
     * we can compute the entity changes
     */
    conflictResolutionHeadRevisionState: RevisionChangeDetectionState;
    /**
     * [5. WSB] Store the entities from workspace BASE revision
     * This can be used for conflict resolution
     */
    workspaceBaseRevisionState: RevisionChangeDetectionState;
    /**
     * [6. WSH] Store the entities from LOCAL workspace HEAD revision.
     * This can be used for computing local changes/live diffs (i.e. changes between local graph and workspace HEAD)
     */
    workspaceLocalLatestRevisionState: RevisionChangeDetectionState;
    /**
     * Store the entities from remote workspace HEAD revision.
     * This can be used for computing the diffs between local workspace and remote workspace to check if the local workspace is out-of-sync
     */
    workspaceRemoteLatestRevisionState: RevisionChangeDetectionState;
    aggregatedWorkspaceChanges: EntityDiff[];
    aggregatedProjectLatestChanges: EntityDiff[];
    aggregatedWorkspaceRemoteChanges: EntityDiff[];
    potentialWorkspaceUpdateConflicts: EntityChangeConflict[];
    potentialWorkspacePullConflicts: EntityChangeConflict[];
    /**
     * For conflict resolution, the procedure is split into 2 steps:
     * 1. The user resolves conflicts (no graph is built at this point)
     * 2. The user marks all conflicts as resolved and starts building the graph to fix any residual problems
     *
     * Ideally, we would like to use the live diff (conflict resolution BASE <-> local graph), but since for step 1
     * we do not build the graph, this is not possible, so we have to use the following to store the diff until we move to step 2
     */
    aggregatedConflictResolutionChanges: EntityDiff[];
    conflicts: EntityChangeConflict[];
    resolutions: EntityChangeConflictResolution[];
    currentGraphHash: string | undefined;
    observerContext: ObserverContext;
    constructor(editorStore: EditorStore, graphState: EditorGraphState);
    setAggregatedProjectLatestChanges(diffs: EntityDiff[]): void;
    setAggregatedWorkspaceRemoteChanges(diffs: EntityDiff[]): void;
    setPotentialWorkspaceUpdateConflicts(conflicts: EntityChangeConflict[]): void;
    setPotentialWorkspacePullConflicts(conflicts: EntityChangeConflict[]): void;
    getCurrentGraphHash(): string;
    stop(force?: boolean): void;
    /**
     * The change detection check is not free, although due to the power of mobx's computed, this is really fast
     * but we want to use a reaction here instead of having changes as a computed getter is that:
     * 1. We want to debounce the action
     * 2. We want to control when we would start observing for changes (this is useful since we need to compute the initial
     * hashes index before this, otherwise users will get false report about the number of changes)
     * This function might cause the UI to jank the since it involves expensive computation of the all the elements' hashes
     * for the first time. Currently there is no workaround so we might need to comeback and evaluate this
     */
    start(): void;
    snapshotLocalEntityHashesIndex(quiet?: boolean): Map<string, string>;
    private computeAggregatedChangesBetweenStates;
    computeAggregatedWorkspaceChanges(quiet?: boolean): GeneratorFn<void>;
    computeAggregatedWorkspaceRemoteChanges(quiet?: boolean): GeneratorFn<void>;
    computeAggregatedProjectLatestChanges(quiet?: boolean): GeneratorFn<void>;
    computeAggregatedConflictResolutionChanges(quiet?: boolean): GeneratorFn<void>;
    /**
     * Workspace update conflicts are computed between 2 sets of changes:
     * 1. Incoming changes: changes between workspace BASE revision and project LATEST revision
     * 2. Current changes: changes between workspace BASE revision and workspace HEAD revision
     */
    computeWorkspaceUpdateConflicts(quiet?: boolean): GeneratorFn<void>;
    /**
     * Conflict resolution conflicts are computed between 2 sets of changes:
     * 1. Incoming changes: changes between workspace BASE revision and conflict resolution BASE revision
     * 2. Current changes: changes between workspace BASE revision and workspace HEAD revision
     */
    computeConflictResolutionConflicts(quiet?: boolean): GeneratorFn<void>;
    /**
     * This function computes the entity change conflicts between 2 set of entity changes (let's call them incoming changes and current changes).
     * For a more comprehensive explanation, we take a look at how we can use this to compute potential conflicts during workspace update:
     *
     * To compute potential conflicts during workspace update, we must base off the project latest changes [incChg] (workspace BASE <-> project HEAD)
     * and the merge request changes [currChng] (workspace BASE <-> workspace HEAD). We have a case table below (`N.A.` means it's impossible cases)
     * For cases we with `conflict` there might be potential conflicts as the change to the entity appear in both [incChg] and [currChng]. But we must
     * note that this is `potential` because we cannot be too sure how SDCL server handle merging these during update.
     *
     * NOTE: it's important to remember that these are truly potential conflicts, because of git merge mechanism,
     * it will apply one intermediate commit at a time, this means that if, we have a file A:
     *
     * Workspace change: 1. A is deleted; 2. A is created with content `a`
     * Project latest change: 1. A is modified with content `a`
     *
     * These could mean no conflict from our computation but is a conflict when Git tries to merge.
     *
     * NOTE: Also, there could be strange case for SVN that a file can be DELETED and CREATED, it's called "replace".
     *
     *             | [incChg] |          |          |          |
     * -----------------------------------------------------------
     *  [currChng] |          |  CREATE  |  DELETE  |  MODIFY  |
     * -----------------------------------------------------------
     *             |  CREATE  | conflict |   N.A.   |   N.A.   |
     * -----------------------------------------------------------
     *             |  DELETE  |   N.A.   |   none   | conflict |
     * -----------------------------------------------------------
     *             |  MODIFY  |   N.A.   | conflict | conflict |
     * -----------------------------------------------------------
     */
    computeEntityChangeConflicts(currentChanges: EntityDiff[], incomingChanges: EntityDiff[], currentChangeEntityHashesIndex: Map<string, string>, incomingChangeEntityHashesIndex: Map<string, string>): GeneratorFn<EntityChangeConflict[]>;
    /**
     * NOTE: here we have not dealt with non-entity changes like project dependency for example.
     * We will have to count that as part of the change in the future.
     */
    computeLocalChanges(quiet?: boolean): GeneratorFn<void>;
    computeLocalChangesInTextMode(currentEntities: Entity[], quiet?: boolean): GeneratorFn<void>;
    observeGraph(): GeneratorFn<void>;
    /**
     * Call `get hashCode()` on each element once so we trigger the first time we compute the hash for that element.
     * Notice that we do this in asynchronous manner to not block the main execution thread, as this is quiet an expensive
     * task.
     *
     * We also want to take advantage of `mobx computed` here so we save time when starting change detection. However,
     * since `mobx computed` does not track async contexts, we have to use the `keepAlive` option for `computed`
     *
     * To avoid memory leak potentially caused by `keepAlive`, we use `keepAlive` utility from `mobx-utils`
     * so we could manually dispose `keepAlive` later after we already done with starting change detection.
     */
    preComputeGraphElementHashes(): Promise<void>;
}
export {};
//# sourceMappingURL=ChangeDetectionState.d.ts.map