import { RecordNode, ROM, RecordMap, ClipboardR } from "./RecordNode";
import { RT, RTP } from "./RecordTypes";
/**
 * A convenient Factory class to maninpulate a RecordNode object of any type
 * This class can be extended to provide any recordType specific funcitonality
 *
 * Using arrow functions in Classes has a runtime performance cost. The constructor bloats up.
 * Solution: https://www.typescriptlang.org/docs/handbook/2/classes.html#this-parameters
 */
export declare class RecordFactory<T extends RT> {
    protected readonly _json: RecordNode<T>;
    protected readonly _type: RT;
    constructor(json: RecordNode<T>);
    /**
     * Returns the value of a property, or it default in case the value isn't defined.
     * In case there is no default defined, it returns "undefined"
     */
    getValueOrDefault(this: RecordFactory<T>, property: RTP[T]): unknown;
    /**
     * Returns a clone default value of a property. If no default is found, returns undefined
     * Note: the returned object is a cloned value to avoid reuse of references across r objects
     */
    getDefault(this: RecordFactory<T>, property: RTP[T]): unknown;
    json(this: RecordFactory<T>): RecordNode<T>;
    getId(this: RecordFactory<T>): number;
    getName(this: RecordFactory<T>): string | undefined;
    /** A list of recordNode.props' keys in the json */
    getProps(this: RecordFactory<T>): string[];
    /** A list of Records this json has (eg: project might have scene, variable, menu) */
    getROMTypes(this: RecordFactory<T>): RT[];
    /** A list of props this RecordType is supposed to have */
    getRecordTypeProps(this: RecordFactory<T>): string[];
    /** In case a property isn't defined in the json, this method returns "undefined" */
    get(this: RecordFactory<T>, property: RTP[T]): unknown;
    set(this: RecordFactory<T>, property: RTP[T], value: unknown): RecordFactory<T>;
    delete(this: RecordFactory<T>, property: string): RecordFactory<T>;
    /** get RecordOrderedMap for a particular sub record, of the shape {map: {}, order: []} -  */
    getROM<N extends RT>(this: RecordFactory<T>, type: N): ROM<N> | undefined;
    getRecordMap<N extends RT>(this: RecordFactory<T>, type: N): RecordMap<N>;
    getRecordOrder(this: RecordFactory<T>, type: RT): number[];
    getRecord<N extends RT>(this: RecordFactory<T>, type: N, id: number): RecordNode<N> | undefined;
    getRecords<N extends RT>(this: RecordFactory<T>, type: N): RecordNode<N>[];
    changeRecordId<N extends RT>(this: RecordFactory<T>, type: N, id: number, newId?: number): RecordNode<N> | undefined;
    changeRecordName<N extends RT>(this: RecordFactory<T>, type: N, id: number, newName?: string): RecordNode<N> | undefined;
    changeDeepRecordName<N extends RT>(this: RecordFactory<T>, type: N, id: number, newName?: string): RecordNode<N> | undefined;
    changePropertyName(this: RecordFactory<T>, propertyName: string, newPropertyName: string): RecordFactory<T>;
    deleteProperty(this: RecordFactory<T>, propertyName: string): RecordFactory<T>;
    addBlankRecord<N extends RT>(this: RecordFactory<T>, type: N, position?: number): RecordNode<N>;
    addRecord<N extends RT>(this: RecordFactory<T>, record: RecordNode<N>, position?: number): RecordNode<N> | undefined;
    duplicateRecord<N extends RT>(this: RecordFactory<T>, type: N, id: number): RecordNode<N> | undefined;
    duplicateDeepRecord<N extends RT>(this: RecordFactory<T>, type: N, id: number): RecordNode<N> | undefined;
    deleteRecord<N extends RT>(this: RecordFactory<T>, type: N, id: number): RecordNode<N> | undefined;
    deleteDeepRecord<N extends RT>(this: RecordFactory<T>, type: N, id: number): RecordNode<N> | undefined;
    /**
     * Used in drag-drop operations
     * Allows moving multiple items at the same time
     * Changes order in place
     *
     * Input: [1, 2, 3, 4, 5, 6]
     * Operation: nodeIds: [2,4], position: 5
     * Output: [1, 3, 5, 6, 2, 4]
     */
    transposeRecords(this: RecordFactory<T>, type: RT, ids: number[], position: number): undefined;
    getDeepChildAndParent<N extends RT>(this: RecordFactory<T>, type: N, id: number): {
        c: RecordNode<N>;
        p: RecordNode<RT>;
    } | undefined;
    getAllDeepChildrenIds<N extends RT>(this: RecordFactory<T>, type: N): number[];
    getAllDeepChildren<N extends RT>(this: RecordFactory<T>, type: N): RecordNode<N>[];
    /**
     * Documentation for filter predicate: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter#description
     */
    getAllDeepChildrenIdsWithFilter<N extends RT>(this: RecordFactory<T>, type: N, predicate: (value: RecordNode<N>, index?: number, array?: RecordNode<N>[]) => boolean): number[];
    getAllDeepChildrenWithFilter<N extends RT>(this: RecordFactory<T>, type: N, predicate: (value: RecordNode<N>, index?: number, array?: RecordNode<N>[]) => boolean): RecordNode<N>[];
    /**
     * Returns the object that needs to be stringified before sending to clipboard
     * Needs to be overriden at Project/Scene level to ensure that
     * 1) Vars are copied correctly (in case of scene copy). Vars pasting will be a bit different - no point changing ids.
     * 2) element ids don't conflict at any depth while pasting
     * 3) To ensure Ctrl+V of scene works even within another scene (ie project's paste gets used)
     *
     * * For clipboard operation, this function can only be called at the parent level
     * * For scene copy, call to r.project()
     * * For element copy, call to r.scene()
     *
     * Scene copy logic:
     * In scene rules, vars can be referenced via ids or via variable names (in templates used in elements)
     * Copy all variables referenced.
     *
     * Scene paste logic:
     * For EACH variable which was copied
     * - If the variable id and name doesn't exist - paste it
     * - If the variable id exists, but name doesn't - ignore it. (To make this work, we need to go to each string template used in rules
     * and elements in the new scene, and change the templates to use the new name)
     * - If the variable id doesn't exist, but name does - replace the variable id in the new scene being pasted (in all rules)
     * with the new variable id
     * - If both the variable id and name exist - ignore it
     */
    copyToClipboardObject(this: RecordFactory<T>, ids: number[]): ClipboardR;
    /**
     * Once the clipboard has been converted into ClipboardR, this function can be used to merge into parent RecordNode
     */
    pasteFromClipboardObject(this: RecordFactory<T>, { obj, position }: {
        obj: ClipboardR;
        position?: number;
    }): void;
    /**
     * Add moveRecords in RecordFactory. ProjectFactory will override this to add rules logic.
     * moveRecords(selectIds: [{id: , path: [recordId, parentRecordId, parent2RecordId....]}], destiation: {id: ,path: []}, destinationPosition)
     */
    /**
     * RFC: https://docs.google.com/document/d/1DVM_i_Go5iX5-EShV5FikfI29k8YEC9cAjzeAY49blc/edit#
     * get the address of the RecordNode. In case parentAddr is not passed (root levels) then self address is returned
     */
    getSelfRecordAddress(this: RecordFactory<T>, parentAddr?: string): string;
    /**
     * get the address of a reacord node property. incase when index is passed, return address to indexed property
     * 1. project:1|scene:1|element:2!opacity
     * 2. project:1|scene:1|element:2!wh>1
     */
    getPropertyAddress(this: RecordFactory<T>, recordAddress: string, property: RTP[T], index?: number): string;
    /**
     * Find the record at a given address. Searches only in child record nodes.
     * Assumes that 1st entry in addr is self
     *
     * examples for ref
     * 1. project:1|scene:1
     * 2. project:1|scene:1|element:2
     * 3. project:1|scene:1|element:2!opacity
     * 4. project:1|scene:1|element:2!wh>1
     *
     */
    getRecordAtAddress(this: RecordFactory<T>, addr: string): RecordNode<RT> | null;
    /**
     * Find the record at a given address. Searches only in child record nodes.
     * Returns both self and parent
     * Assumes that 1st entry in addr is self
     *
     * examples for ref
     * 1. project:1|scene:1
     * 2. project:1|scene:1|element:2
     * 3. project:1|scene:1|element:2!opacity
     * 4. project:1|scene:1|element:2!wh>1
     *
     */
    getRecordAndParentAtAddress(this: RecordFactory<T>, addr: string): {
        p?: RecordNode<RT>;
        c: RecordNode<RT>;
    } | null;
    /**
     * Update the value of a property at an address
     * examples for ref
     * 1. project:1|scene:1|element:2!opacity
     * 2. project:1|scene:1|element:2!wh>1
     *
     * First find the RecordNode using getRecordAtAddress method
     * if the property address contains an index, check if the property is an array type
     *  1. if yes, udpate the value at index
     *  2. else return false
     * else update property value directly in the RecordNode
     *
     */
    updatePropertyAtAddress(this: RecordFactory<T>, addr: string, value: unknown): boolean;
    /**
     * This allows re-parenting records between different depths inside a tree using their addresses.
     * This needs to be called for the record where both sourceParentRecord and destParentRecord are child records of a common super parent record
     * For almost all operations, we will use a top down approach here for re-parenting, i.e re-parenting process needs to start from the top most parent
     * in this case, it is almost always project
     * Example1: moving elements from within a group to 1 level above.
     *
     * Scene1
     *  Element1 <-------|
     *  Element2         |
     *  Element3 (group) |
     *    Element31 -----|
     *    Element32
     *
     * In above scenario we want to move Element31 below Element1
     * sourceRecordAddr = [{parentAddr: Scene:1|Element:3, recordAddr: Scene:1|Element:3|Element:31}]
     * destParentAddr = Scene:1
     * destPosition = 0 (we insert at x+1 index)
     *
     * Example2: moving elements from one scene to another
     *
     * Scene1
     *  Element1
     *  Element2
     *  Element3 (group)
     *    Element31
     *    Element32  <-|
     * Scene2          |
     *  Element4 ------|
     *  Element5
     *
     * In above scenario we want to move Element4 from Scene2 to Element3(Group)
     * sourceRecordAddr = [{parentAddr: Scene:2, recordAddr: Scene:2|Element:4}]
     * destParentAddr = Scene:1|Element:3
     * destPosition = 1 (we insert at x+1 index)
     *
     */
    reParentRecordsWithAddress(destParentAddr: string, sourceRecordAddr: {
        parentAddr: string;
        recordAddr: string;
    }[], destPosition?: number): [RecordNode<RT>[], RecordNode<RT>[]];
    /**
     * This returns all the nodes in the path from a parent to a leaf
     */
    getBreadcrumbs(this: RecordFactory<T>, id: number, type: RT): RecordNode<RT>[];
    /**
     * Get address for a deep record
     */
    getDeepRecordAddress(this: RecordFactory<T>, { id, type, parentAddr }: {
        id: number;
        type: RT;
        parentAddr?: string;
    }): string;
    /**
     * Get record + parent address for a given record
     */
    getDeepChildAndParentAddress(this: RecordFactory<T>, id: number, type: RT): string[] | undefined;
}
export declare class RecordUtils {
    static getDefaultValues: <T extends RT>(type: T) => Record<string, unknown>;
}
