/// <reference types="node" />
import { ContractLoader, CryptoProvider, Executor, Logger, LoggerOptions } from '@evan.network/dbcp';
import { DataContract } from '../data-contract/data-contract';
import { Description } from '../../shared-description';
import { NameResolver } from '../../name-resolver';
import { Profile } from '../../profile/profile';
import { RightsAndRoles } from '../rights-and-roles';
import { Sharing } from '../sharing';
import { Verifications } from '../../verifications/verifications';
/**
 * config properties, specific to `Container` instances
 */
export interface ContainerConfig {
    /** account id of user, that interacts with container */
    accountId: string;
    /** address of a ``DataContract`` instance, can be ENS or contract address */
    address?: string;
    /** description has to be passed to ``.create`` to apply it to to contract */
    description?: any;
    /** factory address can be passed to ``.create`` for custom container factory */
    factoryAddress?: string;
    /** plugin to be used in ``.create``, can be string with name or a ``ContainerTemplate`` */
    plugin?: string | ContainerPlugin;
}
/**
 * description and content of a single file, usually used in arrays (add/get/set operations)
 */
export interface ContainerFile {
    /** filename, e.g. 'animal-animal-photography-cat-96938.jpg' */
    name: string;
    /** mime type of the file, e.g. 'image/jpeg' */
    fileType: string;
    /** file data as Buffer */
    file: Buffer;
}
/**
 * options for Container constructor
 */
export interface ContainerOptions extends LoggerOptions {
    contractLoader: ContractLoader;
    cryptoProvider: CryptoProvider;
    dataContract: DataContract;
    description: Description;
    executor: Executor;
    nameResolver: NameResolver;
    rightsAndRoles: RightsAndRoles;
    sharing: Sharing;
    verifications: Verifications;
    web3: any;
}
/**
 * config for sharing multiple fields to one account (read and/or readWrite access)
 */
export interface ContainerShareConfig {
    /** account, that gets properties shared */
    accountId: string;
    /** list of properties, that are shared read-only */
    read?: string[];
    /** list of properties, that are shared readable and writable */
    readWrite?: string[];
}
/**
 * base definition of a container instance, covers properties setup and permissions
 */
export interface ContainerPlugin {
    /** container dbcp description (name, description, ...) **/
    description?: any;
    /** template for container instances, covers properties setup and permissions **/
    template: ContainerTemplate;
}
/**
 * template for container instances, covers properties setup and permissions
 */
export interface ContainerTemplate {
    /** type of the template (equals name of the template) */
    type: string;
    /** list of properties included in this template, key is field name, value is property setup */
    properties?: {
        [id: string]: ContainerTemplateProperty;
    };
}
/**
 * property in `ContainerTemplate`, defines an `entry` or `list` at the data contract
 */
export interface ContainerTemplateProperty {
    /** `Ajv <https://github.com/epoberezkin/ajv>`_ data schema for field */
    dataSchema: any;
    /** permissions for this template, key is role id, value is array with 'set' and/or 'remove' */
    permissions: {
        [id: number]: string[];
    };
    /** type of property (entry/list) */
    type: string;
    /** value of property */
    value?: any;
}
/**
 * data for verifications for containers, see ``Validation`` documentation for details
 */
export interface ContainerVerificationEntry {
    /** validation path */
    topic: string;
    /** domain, where the description of this validation is stored */
    descriptionDomain?: string;
    /** if set, validations created in a sub-path are invalid by default */
    disableSubverifications?: boolean;
    /** expiration date, validations do not expire if omitted */
    expirationDate?: number;
    /** reference to additional validation details */
    verificationValue?: string;
}
/**
 * helper class for managing data contracts; all values are stored encrypted, hashes are encrypted
 * as well, use `contract` property and `DataContract` module for custom logic for special cases
 * like unencrypted values
 *
 * @class      Container (name)
 */
export declare class Container extends Logger {
    static defaultDescription: {
        name: string;
        description: string;
        author: string;
        version: string;
        dbcpVersion: number;
    };
    static defaultSchemas: {
        booleanEntry: {
            type: string;
        };
        booleanList: {
            type: string;
            items: {
                type: string;
            };
        };
        filesEntry: {
            type: string;
            $comment: string;
            properties: {
                additionalProperties: boolean;
                files: {
                    type: string;
                    items: {
                        type: string;
                    };
                };
            };
            required: string[];
        };
        filesList: {
            type: string;
            items: {
                type: string;
                $comment: string;
                properties: {
                    additionalProperties: boolean;
                    files: {
                        type: string;
                        items: {
                            type: string;
                        };
                    };
                };
                required: string[];
            };
        };
        numberEntry: {
            type: string;
        };
        numberList: {
            type: string;
            items: {
                type: string;
            };
        };
        objectEntry: {
            type: string;
        };
        objectList: {
            type: string;
            items: {
                type: string;
            };
        };
        stringEntry: {
            type: string;
        };
        stringList: {
            type: string;
            items: {
                type: string;
            };
        };
    };
    static defaultPlugin: string;
    static profilePluginsKey: string;
    static plugins: {
        [id: string]: ContainerPlugin;
    };
    private config;
    private contract;
    private mutexes;
    private options;
    private reservedRoles;
    /**
     * Clone ``Container`` instance into template and creates new ``Container`` with it.
     *
     * @param      {ContainerOptions}  options  runtime for new `Container`
     * @param      {ContainerConfig}   config   config for new container
     * @param      {Container}         source   will be serialized to a template that will be applied
     *                                          to new `Container`
     */
    static clone(options: ContainerOptions, config: ContainerConfig, source: Container, copyValues?: boolean): Promise<Container>;
    /**
     * Creates a new digital container contract on the blockchain.
     *
     * @param      {ContainerOptions}  options  runtime for new `Container`
     * @param      {ContainerConfig}   config   config for new container
     */
    static create(options: ContainerOptions, config: ContainerConfig): Promise<Container>;
    /**
     * Remove a container plugin from a users profile.
     *
     * @param      {Profile}  profile  profile instance
     * @param      {string}   name     plugin name
     */
    static deleteContainerPlugin(profile: Profile, name: string): Promise<void>;
    /**
     * Get one container plugin for a users profile by name.
     *
     * @param      {Profile}  profile  profile instance
     * @param      {string}   name     plugin name
     */
    static getContainerPlugin(profile: Profile, name: string): Promise<ContainerPlugin>;
    /**
     * Get all container plugins for a users profile.
     *
     * @param      {Profile}            profile      profile instance
     */
    static getContainerPlugins(profile: Profile): Promise<{
        [id: string]: ContainerPlugin;
    }>;
    /**
     * Persists a plugin including an dbcp description to the users profile.
     *
     * @param      {Profile}            profile     profile instance
     * @param      {string}             name        plugin name
     * @param      {ContainerTemplate}  plugin      container plugin object
     * @param      {string}             beforeName  remove previous plugin instance when it was
     *                                              renamed
     * @param      {any}  description  predefined plugin dbcp description
     */
    static saveContainerPlugin(profile: Profile, name: string, plugin: ContainerPlugin, beforeName?: string): Promise<void>;
    /**
     * Create new ``Container`` instance. This will not create a smart contract contract but is used
     * to load existing containers. To create a new contract, use the static ``create`` function.
     *
     * @param      {ContainerOptions}  options  runtime for new container
     * @param      {ContainerConfig}   config   config for new container
     */
    constructor(options: ContainerOptions, config: ContainerConfig);
    /**
     * Add list entries to a list list property.
     *
     * List entries can be added in bulk, so the value argument is an array with values. This array
     * can be arbitrarily large **up to a certain degree**. Values are inserted on the blockchain side
     * and adding very large arrays this way may take more gas during the contract transaction, than
     * may fit into a single transaction. If this is the case, values can be added in chunks (multiple
     * transactions).
     *
     * @param      {string}  listName  name of the list in the data contract
     * @param      {any}     values    values to add
     */
    addListEntries(listName: string, values: any[]): Promise<void>;
    /**
     * Add verifications to this container; this will also add verifications to contract description.
     * Due to the automatic expansion of the contract description, this function can only be called by
     * the container owner.
     *
     * @param      {ContainerVerificationEntry[]}  verifications  list of verifications to add
    */
    addVerifications(verifications: ContainerVerificationEntry[]): Promise<void>;
    /**
     * Ensure that container supports given property.
     *
     * @param      {string}  propertyName  name of an entry or list
     * @param      {any}     dataSchema    ajv data schema
     * @param      {string}  propertyType  (optional) 'list' if dataSchema.type is 'array', otherwise
     *                                     'entry'
     */
    ensureProperty(propertyName: string, dataSchema: any, propertyType?: string): Promise<void>;
    /**
     * Get contract address of underlying ``DataContract``.
     */
    getContractAddress(): Promise<string>;
    /**
     * Get description from container contract.
     */
    getDescription(): Promise<any>;
    /**
     * Return entry from contract.
     *
     * @param      {string}  entryName  entry name
     */
    getEntry(entryName: string): Promise<any>;
    /**
     * Return list entries from contract. Note, that in the current implementation, this function
     * retrieves the entries one at a time and may take a longer time when querying large lists, so be
     * aware of that
     *
     * @param      {string}   listName  name of a list in the container
     * @param      {number}   count     number of items to retrieve
     * @param      {number}   offset    skip this many entries
     * @param      {boolean}  reverse   if true, fetches last items first
     */
    getListEntries(listName: string, count?: number, offset?: number, reverse?: boolean): Promise<any[]>;
    /**
     * Return a single list entry from contract.
     *
     * @param      {string}  listName  name of a list in the container
     * @param      {number}  index     list entry id to retrieve
     */
    getListEntry(listName: string, index: number): Promise<any>;
    /**
     * Return number of entries in the list.
     * Does not try to actually fetch and decrypt values, but just returns the count.
     *
     * @param      {string}  listName  name of a list in the container
     */
    getListEntryCount(listName: string): Promise<number>;
    /**
     * Check permissions for given account and return them as ContainerShareConfig object.
     *
     * @param      {string}  accountId  account to check permissions for
     */
    getContainerShareConfigForAccount(accountId: string): Promise<ContainerShareConfig>;
    /**
     * Check permissions for all members and return them as array of ContainerShareConfig.
     */
    getContainerShareConfigs(): Promise<ContainerShareConfig[]>;
    /**
     * Gets the owner account id.
     */
    getOwner(): Promise<string>;
    /**
     * Gets verifications from description and fetches list of verifications for each of them.
     */
    getVerifications(): Promise<any[]>;
    /**
     * Write given description to containers DBCP.
     *
     * @param      {any}  description  description (public part)
     */
    setDescription(description: any): Promise<void>;
    /**
     * Set a value for an entry.
     *
     * @param      {string}  entryName  name of an entry in the container
     * @param      {any}     value      value to set
     */
    setEntry(entryName: string, value: any): Promise<void>;
    /**
     * Share entry/list to another user; this handles role permissions, role memberships.
     *
     * @param      {ContainerShareConfig[]}  shareConfigs  list of share configs
     */
    shareProperties(shareConfigs: ContainerShareConfig[]): Promise<void>;
    /**
     * Export current container state as plugin.
     *
     * @param      {boolean}  getValues  export entry values or not (list entries are always excluded)
     */
    toPlugin(getValues?: boolean): Promise<ContainerPlugin>;
    /**
     * Helper function for encrypting and decrypting, checks if a given property requires file
     * encryption.
     *
     * @param      {any}       subSchema  schema to check in
     * @param      {any}       toInspect  value to inspect
     * @param      {Function}  toApply    function, that will be applied to values in `toInspect`
     */
    private applyIfEncrypted;
    /**
     * checks if given property is a `ContainerFile` object and decrypts in that case
     *
     * @param      {string}  entryName  name of the property
     * @param      {any}     value      (raw) value to analyze
     */
    private decryptFilesIfRequired;
    /**
     * create ajv schema (without $id value) by analyzing value
     *
     * @param      {any}    value    value to analyze
     * @param      {any[]}  visited  (optional) not intended for direct use, visited nodes for
     *                               recursion
     * @return     {any}    ajv schema
     */
    private deriveSchema;
    /**
     * checks if given property is a `ContainerFile` array and encrypts in that case
     *
     * @param      {string}             propertyName  name of the property
     * @param      {ContainerFile|any}  value         value to encrypt (if required)
     */
    private encryptFilesIfRequired;
    /**
     * Check if container contract already has been loaded, load from address / ENS if required.
     */
    private ensureContract;
    /**
     * ensure that current account has a key for given entry in sharings
     *
     * @param      {string}  entryName  name of an entry to ensure a key for
     */
    private ensureKeyInSharing;
    /**
     * ensure, that current user has permission to set values on given property; note that this
     * function is for internal use in `Container` and skips a check to verify, that given account is
     * in specified role; used out of context, this may check check if an account has permissions on a
     * field and add then adds this account to an unrelated role, therefore not granting permissions
     * on checked field
     *
     * @param      {string}  name       name of the property to ensure permission for
     * @param      {string}  type       type of property ('entry'/'list')
     * @param      {string}  accountId  (optional) accountId to ensure permission for, defaults to
     *                                  account from container config (active account)
     * @param      {number}  role       (optional) role id, defaults to 0
     */
    private ensurePermissionOnField;
    /**
     * derive type from item value, ensure, that it is in DBCPs data schema
     *
     * @param      {string}  name    property name
     * @param      {any}     value   property value
     */
    private ensureTypeInSchema;
    /**
     * get mutex for keyword, this can be used to lock several sections during updates
     *
     * @param      {string}  name    name of a section; e.g. 'sharings', 'schema'
     * @return     {Mutex}   Mutex instance
     */
    private getMutex;
    /**
     * get hash for operation permission, this creates the hashes, that are used in
     * `DSRolesPerContract` to check operation capabilities
     *
     * @param      {string}  name       property name
     * @param      {string}  type       'entry' or 'list'
     * @param      {string}  operation  'set' or 'remove'
     * @return     {string}  bytes32 hash as string
     */
    private getOperationHash;
    /**
     * get role permission for given property and type from authority contract
     *
     * @param      {any}     authorityContract  `DSRolesPerContract` instance
     * @param      {string}  property           property name
     * @param      {string}  type               'entry' or 'list'
     */
    private getRolePermission;
    /**
     * Checks a ajv data schema is type of encrypted files.
     *
     * @param      {any}      schema  ajv data sub schema
     * @return     {boolean}  True if encrypted file, False otherwise
     */
    private isEncryptedFile;
    /**
     * wrap try, catch around promise and throw error with message if rejected
     *
     * @param      {string}      task     name of a task, is included in error message
     * @param      {Promise<any>}  promise  promise to await
     */
    private wrapPromise;
}
