import { BimChangeLayer, LayerCompatibleChange } from '../loader/bim-api-client';
import { Failure } from '../fail';
import { MergableObject, MergableObjectWithState, ImmutableMergableObjectWithState } from '../MergableSet';
import { LayerDefinition } from '../loader/LayerDefinitions';
import { Permission, Permissions } from '../loader/Permission';
import { BimApi } from '../BimApi';
import { LayerAttachmentsApi } from './LayerAttachmentsApi';
/**
 * Methods to serialize/deserialize from one representation to another.
 */
export interface Serialize<DataTransferObject, DeserializedType extends MergableObject<DeserializedType>, LAYER extends LayerInterface<DeserializedType>> {
    from(dto: DataTransferObject, layer: LAYER): DeserializedType[];
    to(o: DeserializedType[], layer: LAYER): DataTransferObject;
}
/**
 * Represents a layer failure.
 */
export type LayerFailure = Failure<{
    /**
     * If specified then the failure was due to a http request failure.
     */
    httpStatus?: number;
    /**
     * Gives reason for failure
     */
    reason: string;
}>;
/**
 * A layer can contain any type of object data structure.
 * When objects are added, deleted or modified events on the corresponding objects are raised. Since layer objects are divided
 * into local and remote objects. Remote objects are those that are retrieved from the backend.
 */
export interface LayerInterface<P extends MergableObject<P>> {
    /**
     * Id of the layer
     */
    readonly id: string;
    /**
     * `true` if a layer exists and if {@link Layer.saveAndMerge} or {@link Layer.loadAndMerge}
     * has been called successfully at least once.
     */
    readonly isLoaded: boolean;
    /**
     * Get the version of the currently loaded layer. [-1] if no layer has yet been loaded.
     */
    readonly version: number;
    /**
     * Get the name of the layer. Returns undefined if no layer has been loaded.
     */
    readonly name: string | undefined;
    /**
     * Number of objects with conflicts in the layer. A conflict occurs if there is a mismatch between the local
     * and the remote representation of the layer. Conflicts can only occur when {@link Layer.saveAndMerge} or {@link Layer.loadAndMerge}
     * is called.
     */
    readonly conflictCount: number;
    /**
     * Number of objects in layer not marked with state {@link MergableObjectState.Unchanged}.
     */
    readonly changeCount: number;
    /**
     * The layer definition.
     */
    readonly definition: LayerDefinition;
    /**
     * Permissions user has on layer.
     */
    readonly permission: Permissions;
    /**
     * Get the objects currently in the layer
     */
    readonly objects: IterableIterator<ImmutableMergableObjectWithState<P>>;
    /**
     * Conflicts in the layer. A conflict occurs if there is a mismatch between the local
     * and the remote representation of a object in the layer. Conflicts can only occur when {@link Layer.saveAndMerge} or {@link Layer.loadAndMerge}
     * is called.
     */
    readonly conflicts: ImmutableMergableObjectWithState<P>[];
    /**
     * Get a specific object in the layer. Both the local and the remote representation
     * of the object is returned
     * @param id id of the object to get. Returns undefined if no such object exists.
     */
    get(id: string): MergableObjectWithState<P> | undefined;
    /**
     * Deletes a object
     * @param p Id of object to delete
     * @returns `true` if object was deleted. Otherwise `false`
     */
    delete(p: P | string): boolean;
    /**
     * Add an object. If object already exists it will not be added. That is if an item where
     * {@link MergableObjectProps.id} already exists.
     * @param o Object to add
     * @returns `true` if object was added, otherwise `false`.
     */
    add(o: P): boolean;
    /**
     * Updates an object that already exists.
     * @param id Id of object to update
     * @param updateAction function called with {@link MergableObject} instance of specified id.
     * Caller should make any required modfifications to the object in this function.
     * @returns `true` if object did exist, otherwise `false`.
     */
    update(id: string, updateAction: (existingItem: P) => void): boolean;
    /**
     * Saves all objects in {@link objects} and retrieves any added, modified layer objects
     * made in backend (Remote) at the same time. An attempt is then made to merge the object from
     * the backend (Remote) into the local (browser) objects.
     * @param overwriteLatestVersion If `true` then latest version is overwritten (if save was successful).
     * @return Number of conflicts. If > 0 then the operation was not successful. The conflicts must be resolved before
     * a new attempt is made. If a {@link LayerFailure} is returned then it signifies that some unexpected error
     * occured. Inspect the contents to determine the cause.
     */
    saveAndMerge(overwriteLatestVersion?: boolean): Promise<number | LayerFailure>;
    /**
     * Clear the layer.
     */
    clear(): void;
    /**
     * Loads all existing (remote) objects from the backend and attempts to merge them into {@link objects}.
     * This may result in conflicts between the local and the remote objects. A typical example is if the same
     * object has been modified locally but also remotely (in the backend.)
     */
    loadAndMerge(): Promise<number | LayerFailure>;
    /**
     * Provides access to the layer attachments API ({@link LayerAttachmentsApi})
     * Use methods on it to get, add, update and delete attachments for this layer.
     */
    attachments: LayerAttachmentsApi;
}
/**
 * A layer is attached to a {@link BimChangeBase} instance. A layer can contain any type of object data structure.
 * When objects are added, deleted or modified events on the corresponding objects are raised. Since layer objects are divided
 * into local and remote objects. Remote objects are those that are retrieved from the backend.
 */
export declare class Layer<Change extends LayerCompatibleChange, P extends MergableObject<P>, LayerDataTransferObject> implements LayerInterface<P> {
    private readonly _api;
    readonly attachedTo: Change;
    readonly layerFormat: string;
    private readonly serialize;
    private _layerOnClient?;
    private readonly _expectedLayerId;
    private readonly _layerObjects;
    attachments: LayerAttachmentsApi;
    /**
     *
     * @param _api BimCoreApi instance
     * @param attachedTo Change this layer is attached to
     * @param layerFormat Format of layer. Example: "sensors"
     * @param serialize Methods to transform layer objects into their DTO counterparts (data transfer object).
     * DTO's are what is actually is stored in the layer.
     */
    constructor(_api: BimApi, attachedTo: Change, layerFormat: string, serialize: Serialize<LayerDataTransferObject, P, LayerInterface<P>>);
    /**
     * Access to the layer instance that is currently loaded. If no layer is loaded then an exception is thrown.
     * This is the representation of the layer that is stored in the backend.
     * {@link Layer.saveAndMerge} or {@link Layer.loadAndMerge} will change the instance of the layer so
     * do not store a reference to it and expect it to be valid after a call to these methods.
     */
    get layer(): BimChangeLayer;
    /**
     * Id of the layer
     */
    get id(): string;
    /**
     * `true` if a layer exists and if {@link Layer.saveAndMerge} or {@link Layer.loadAndMerge}
     * has been called successfully at least once.
     */
    get isLoaded(): boolean;
    /**
     * Get the version of the currently loaded layer. [-1] if no layer has yet been loaded.
     */
    get version(): number;
    /**
     * Get the name of the layer. Returns undefined if no layer has been loaded.
     */
    get name(): string | undefined;
    /**
     * Number of objects with conflicts in the layer. A conflict occurs if there is a mismatch between the local
     * and the remote representation of the layer. Conflicts can only occur when {@link Layer.saveAndMerge} or {@link Layer.loadAndMerge}
     * is called.
     */
    get conflictCount(): number;
    /**
     * Number of objects in layer not marked with state {@link MergableObjectState.Unchanged}.
     */
    get changeCount(): number;
    /**
     * The layer definition.
     */
    get definition(): LayerDefinition;
    /**
     * Permissions user has on layer.
     */
    get permission(): Permissions;
    /**
     * Get the objects currently in the layer
     */
    get objects(): IterableIterator<ImmutableMergableObjectWithState<P>>;
    /**
     * Conflicts in the layer. A conflict occurs if there is a mismatch between the local
     * and the remote representation of an object in the layer. Conflicts can only occur when {@link Layer.saveAndMerge} or {@link Layer.loadAndMerge}
     * is called.
     */
    get conflicts(): ImmutableMergableObjectWithState<P>[];
    /**
     * Get a specific object in the layer. Both the local and the remote representation
     * of the object are returned
     * @param id id of the object to get. Returns undefined if no such object exists.
     */
    get(id: string): MergableObjectWithState<P> | undefined;
    /**
     * Deletes an object. Requires user to have {@link Access.delete} on layer. {@link permission} should therefore be validated before method call to ensure that no exception is generated.
     * @param p Id of object to delete
     * @returns `true` if object was deleted. Otherwise `false`
     */
    delete(p: P | string): boolean;
    /**
     * Adds an object. If an object with the same {@link MergableObjectProps.id} already exists, no further object will be added.
     * Requires user to have {@link Access.add} on layer. {@link permission} should therefore be validated before method
     *  call to ensure that no exception is generated.
     * @param o Object to add
     * @returns `true` if object was added, otherwise `false`.
     */
    add(o: P): boolean;
    /**
     * Updates an existing object.
     * Requires user to have {@link Access.edit} on layer. {@link permission} should therefore
     * be validated before method call to ensure that no exception is generated.
     * @param id Id of object to update
     * @param updateAction function called with {@link MergableObject} instance of specified id.
     * Caller should make any required modfifications to the object in this function.
     * @returns `true` if object did exist, otherwise `false`.
     */
    update(id: string, updateAction: (existingItem: P) => void): boolean;
    /**
     * Saves all objects in {@link objects} and retrieves any added, modified layer objects
     * made in backend (Remote) at the same time. An attempt is then made to merge the object from
     * the backend (Remote) into the local (browser) objects.
     * Requires that user has {@link Access.view} (to add new layer) or {@link Access.edit} (to edit existing layer). {@link permission} should therefore
     * be validated before method call to ensure that no exception is generated.
     * @param overwriteLatestVersion If `true` then latest version is overwritten (if save was successful).
     * @return Number of conflicts. If > 0 then the operation was not successful. The conflicts must be resolved before
     * a new attempt is made. If a {@link LayerFailure} is returned then it signifies that some unexpected error
     * occured. Inspect the contents to determine the cause.
     */
    saveAndMerge(overwriteLatestVersion?: boolean): Promise<number | LayerFailure>;
    /**
     * Clear the layer.
     */
    clear(): void;
    /**
     * Loads all existing (remote) objects from the backend and attempts to merge them into {@link objects}.
     * This may result in conflicts between the local and the remote objects. A typical example is if the same
     * object has been modified locally but also remotely (in the backend.)
     */
    loadAndMerge(): Promise<number | LayerFailure>;
    throwIfNoPermissionsAreSatisfied(...requiredPermissions: Permission[]): void;
    private getLayerContents;
    private getBlobIndependentLayerContentUrl;
    private attemptMergeLayerContents;
}
//# sourceMappingURL=Layer.d.ts.map