/// <reference types="xrm" />
/// <reference types="react" />
/**
 * Helpers for dealing with entity form state.
 */
import * as React from "react";
import * as PropTypes from "prop-types";
import { Dynamics, DynamicsProps, DynamicsContext } from "./Dynamics";
import { Notifier } from "./NotificationManager";
/** A dynamics form attribute. Entity lookup by default. */
export interface Attribute<T = Xrm.LookupValue> {
    /** Standardized name e.g. "account" or "contact". Not sure this is needed. */
    name: string;
    /** Dynamics logical name. */
    logicalName: string;
    /** If the attribute currently has a value. */
    hasValue: boolean;
    /** Dynamics attribute, it must be a lookup. */
    attribute: Xrm.Attributes.LookupAttribute;
    /** Used to unregister the callback handler. */
    unregisterToken?: any;
    /** Current value. Typically an array so you need index-0. */
    value: T | null;
}
/**
 * Dynamics form attribute state. keys are dynamics attribute names
 * (logical names) and values are this module's Attributes.
 */
export declare type AttributeState = Record<string, Attribute>;
/** Empty state. */
export declare const EmptyAttributeState: {};
/**
 * Add on change handlers to attributes. Return a new state. Existing
 * attributes in AttributeState are included in the return value untouched
 * so this is safe to call incrementally.
 */
export declare function connect(attributes: Array<string>, state: AttributeState, getAttribute: (n: string) => Xrm.Attributes.Attribute, onChangeHandler: (name: string, value: any) => void): AttributeState;
/** Clears all values but setting it to null. */
export declare function clear(state: AttributeState): void;
/** Something that can dispose. Very traditional OOP. */
export interface Disposable {
    dispose: () => void;
}
/** EntityForm's props, *not* for the children of EntityForm (see EntityFormChildProps). */
export interface EntityFormProps extends Partial<DynamicsProps> {
    entityId?: string | null;
    entityName?: string | null;
    userId?: string | null;
    /** Track form save and re-grab ids, etc. */
    trackSave?: boolean;
    /** Pass in strict value for the FormContext, if available. */
    formContext?: Xrm.FormContext;
}
/**
 * Extend these for your child's props using EntityFormChildProps or
 * Partial<EntityFormChildProps>. Form attributes are also injected once
 * they are connected to the form.
 */
export interface EntityFormChildProps {
    /** Whether you can change values on the form e.g. true => can use Attribute.setValue. */
    canChange: boolean | null;
    /** entityId for the entity represented by the form. May be null if the entity is new w/o save. */
    entityId: string | null;
    entityName: string | null;
    userId: string | null;
    /** See Xrmenum.FormType */
    formType: number | null;
    /** Connect to Dynamics attributes so we get them as props. */
    connect: (attributes: Array<string>) => Promise<void>;
    /** Clear attributes by setting their values to null. */
    clear: (attributes: Array<string>, fire: boolean) => Promise<void>;
    /** Set an attribute value. */
    setValue: (attribute: string, value: any) => Promise<void>;
    /** Form context. */
    formContextP: Promise<Xrm.FormContext>;
    /** Convenience, a Notifier (a user message handler). */
    notifier: Notifier;
}
export interface EntityFormState {
    stateCode: number | null;
    canChange: boolean | null;
    entityId: string | null;
    ename: string | null;
    entityName: string | null;
    formType: number | null;
}
export interface EntityFormContext extends DynamicsContext {
    /** A form context promise. */
    formContextP: Promise<Xrm.FormContext>;
}
/** Not used yet. */
export declare const entityFormShape: PropTypes.Requireable<any>;
/**
 * Inject Xrm state into a child and provide Xrm state through
 * a component's context. Can detect when the form has been saved
 * because the entityId will appear as a value in the child props.
 * Save handlers are run properly after the save. An update after
 * save is automatically called. Using this component as your parent
 * is alot like using `connect` in `react-redux`.
 *
 * The Xrm.FormContext is obtained via FormContextHolder or window.parent.
 */
export declare class EntityForm<P extends EntityFormProps = EntityFormProps, S extends EntityFormState = EntityFormState> extends Dynamics<P, S> {
    constructor(props: P, context: any);
    private formContextResolved;
    private deferredFormContext;
    private __className;
    private __disposables;
    private __afterSaves;
    /** Attributes live outside the react world, so make it instance var. */
    protected _attributeState: AttributeState;
    getChildContext(): EntityFormContext;
    static childContextTypes: {
        notifier: PropTypes.Requireable<any>;
        xrm: PropTypes.Requireable<any>;
        errorHandler: PropTypes.Requireable<any>;
        formContextP: PropTypes.Requireable<any>;
    };
    /** Can push a thunk. */
    readonly _afterSaves: Array<() => void>;
    /** Can push a Disposable. */
    readonly _disposables: Array<Disposable>;
    /** Get the class name. From Office Fabric. */
    readonly className: string;
    /**
     * Setup the FormContext if it is not already set. When resolved, force an update.
     */
    componentDidMount(): void;
    componentWillUnmount(): void;
    componentWillMount(): void;
    /**
     * Setup connections force an update so that values are propagated.
     * @returns true if connections were created, false otherwise.
     */
    protected connect: (attributes: string[]) => Promise<boolean>;
    protected onChangeHandler: (name: string, value: any) => void;
    /** For each value in a connected state. */
    protected clear: (names: string[], fire?: boolean) => Promise<void>;
    /** Give a FormContext, extract some values to pass to children as props on the next render. */
    protected extractValues: (fctx: Xrm.FormContext) => void;
    /**
     * Setting value in dynamics attribute does *not* fire change event automatically,
     * which is good for us. If fire is true, `fireOnChange()` is called.
     */
    protected setValue: (name: string, value: any, fire?: boolean) => Promise<void>;
    render(): React.ReactElement<any>;
}
export default EntityForm;
