import { OnInit } from '@angular/core';
import { DIControlValueAccessor, DIControlValueAccessorConfig } from './control-value-accessor';
import * as i0 from "@angular/core";
/**
 * Configuration for the `DIControl`.
 */
export interface DIControlConfig<TModel, TChildModel> extends DIControlValueAccessorConfig<TModel> {
    /**
     * Host control for the current control. It can be injected using `DI_HOST_CONTROL` token.
     */
    host?: DIControl<any, TModel> | null;
    /**
     * Function that will be called when the current control receives an update from the child control.
     *
     * @param control - child control that was updated.
     * @param value - new value.
     */
    onChildControlChange?: (control: DIControl<TChildModel>, value: TModel | null) => void;
}
/**
 * `DIControl` can be used to implement any control that you want. It can work with any model type.
 * All updates from children will be accepted as is. And updates from outside (`FormControl`, `NgModel`, another Control)
 * will be accepted as is too.
 *
 * ## Creating a control
 * To create a control you need to extend your `@Component` or `@Directive` from `DIControl` class.
 * After that your control will be able to work with `NgModel`, `FormControl`.
 *
 * ```ts fileName="custom-control.component.ts"
 * @Component({})
 * export class CustomControlComponent extends DIControl<string> {
 *   constructor() {
 *    super();
 *  }
 * }
 *  ```
 *
 * ## Registering as a host
 * By default your control can work only with `NgModel` and `FormControl`. But you can register your control as a host
 * for another controls, then your control will be able to update them and accept updates from them. To do that you need to
 * use `provideHostControl` function.
 *
 * ```ts {2} fileName="custom-control.component.ts"
 * @Component({
 *   providers: [provideHostControl(CustomControlComponent)],
 * })
 * export class CustomControlComponent extends DIControl<string> {
 *   constructor() {
 *     super();
 *   }
 * }
 * ```
 *
 * ## Injecting host control
 * By default your control doesn't communicate with host controls. But you can inject host control and put it
 * into `super` call. This will register your control in the host control and start communication between them.
 *
 * > **Note**
 * > If you register your control as a host for another controls, then you can inject it
 * > only with `skipSelf` option.
 *
 * ```ts {5} fileName="custom-control.component.ts"
 * @Component({})
 * export class CustomControlComponent extends DIControl<string> {
 *   constructor() {
 *     // we add `optional` option to make it possible to use this control without host
 *     super({host: injectHostControl({optional: true})});
 *   }
 * }
 * ```
 *
 * ## Getting model
 * To get model you need to use `model` property. It will return model for the current control.
 *
 * ```ts {9} fileName="custom-control.component.ts"
 * @Component({})
 * export class CustomControlComponent extends DIControl<string> {
 *   constructor() {
 *     super();
 *   }
 *
 *   @HostListener('click')
 *   onClick() {
 *     console.log(this.model());
 *   }
 * }
 * ```
 *
 * ## Updating model
 * To update model you need to call `updateModel` method. It will update model for the current control and all
 * children controls, as well as for the `NgModel` or `FormControl`.
 *
 * ```ts {9} fileName="custom-control.component.ts"
 * @Component({})
 * export class CustomControlComponent extends DIControl<string> {
 *   constructor() {
 *     super();
 *   }
 *
 *   @HostListener('click')
 *   onClick() {
 *     this.updateModel('new value');
 *   }
 * }
 * ```
 * ## Catching updates
 * Sometimes you may need to catch updates from different sources. For example, to update the value of the native
 * input element. To do this, you can provide the `onIncomingUpdate` hook.
 *
 * ```ts {6} fileName="custom-control.component.ts"
 * @Component({})
 * export class CustomControlComponent extends DIControl<string> {
 *   constructor() {
 *     super({
 *       onIncomingUpdate: (value: string | null) => {
 *         this.elementRef.nativeElement.value = value;
 *       },
 *     });
 *   }
 * }
 * ```
 */
export declare abstract class DIControl<TModel, TChildModel = TModel> extends DIControlValueAccessor<TModel> implements OnInit {
    protected readonly config?: DIControlConfig<TModel, TChildModel> | undefined;
    /**
     * List of children controls.
     *
     * @protected
     * @internal
     */
    protected children: Set<DIControl<TChildModel>>;
    /**
     * Control from which we have to update our model.
     *
     * @protected
     * @internal
     */
    protected updateFrom: DIControl<TChildModel> | null;
    /**
     * Request host for update the current control.
     * Host will update the current control based on its current state and host control logic.
     *
     * @protected
     * @internal
     */
    protected requestForUpdate: () => void;
    /**
     * Function that should be used to make control touched.
     */
    protected touch: () => void;
    private onControlChangeFn;
    private destroyRef;
    protected constructor(config?: DIControlConfig<TModel, TChildModel> | undefined);
    ngOnInit(): void;
    /**
     * Registers provided control as a child of the current control.
     *
     * @param control - control that will be registered.
     * @internal
     */
    registerControl(control: DIControl<TChildModel>): void;
    /**
     * Unregisters provided control from the current control.
     *
     * @param control - control that will be unregistered.
     * @internal
     */
    unregisterControl(control: DIControl<TChildModel>): void;
    registerOnTouched(fn: () => void): void;
    /**
     * Registers provided function as a callback that will be called when the current control changes.
     * This function will be provided by the host control to update its model.
     *
     * @param fn - callback function.
     * @internal
     */
    registerOnControlChange(fn: (value: TModel | null) => void): void;
    /**
     * Registers provided function as a callback that can be called to request an update from the host control.
     * After calling this function the host control will update the model of the current control based on the current
     * state of the control and host control logic.
     *
     * @param fn - callback function.
     * @internal
     */
    registerRequestForUpdate(fn: () => void): void;
    /**
     * Updates the model of the current control.
     * This is the main method that should be used to update the model.
     *
     * @param value - new value.
     */
    updateModel(value: TModel | null): void;
    /**
     * Updates the model of the current control.
     * Don't use this method directly, use `updateModel` instead.
     *
     * @param value - new value.
     * @internal
     */
    internalUpdateModel(value: TModel | null): void;
    writeValue(value: TModel | null): void;
    /**
     * Method is called by the host to update the value of the control.
     *
     * @param value - new value
     * @internal
     */
    writeValueFromHost(value: TModel | null): void;
    /**
     * Updates all child controls with the provided value.
     *
     * @param value - new value.
     * @protected
     * @internal
     */
    protected updateControls(value: TModel | null): void;
    /**
     * Updates provided control with the provided value.
     *
     * @param control - control that will be updated.
     * @param value - new value.
     * @protected
     * @internal
     */
    protected updateControl(control: DIControl<TChildModel>, value: TModel | null): void;
    /**
     * Function catches updates from child controls and updates the current control model.
     *
     * @param control - control that was updated.
     * @param value - new value.
     * @protected
     * @internal
     */
    protected childControlChange(control: DIControl<TChildModel>, value: TModel | null): void;
    static ɵfac: i0.ɵɵFactoryDeclaration<DIControl<any, any>, never>;
    static ɵdir: i0.ɵɵDirectiveDeclaration<DIControl<any, any>, never, never, {}, {}, never, never, true, never>;
}
