import './extensions';
import { InjectionToken, NgZone } from '@angular/core';
import { ValidatorFn } from '@angular/forms';
import { Router } from '@angular/router';
import { Platform, ToastController } from '@ionic/angular';
import { Tap, TapResponse } from '@iotize/tap';
import { TapConfiguratorConfig } from '@iotize/tap/config/schema/v1';
import { ComProtocol, ConnectionStateChangeEvent } from '@iotize/tap/protocol/api';
import { NdefTag } from '@iotize/device-com-nfc.cordova';
import { BehaviorSubject, Observable, Subject } from 'rxjs';
import { OnTapEvent, TapInfo, TapInfoHolder } from './definitions';
import { DataManagerIonic } from './extensions/data-manager/impl';
import { ProtocolMeta, ProtocolMetaNfc } from './extensions/protocol-info';
import { ProtocolFactoryService } from './protocol-factory.service';
import { TapSelectedEvent } from './tap-connect/api';
import { TagDiscoveredEvent } from './tap-scanner/tap-scanner-nfc/definitions';
import { KeepAliveEngine } from '@iotize/tap/keep-alive';
import { TapAuth } from '@iotize/tap/auth';
import { IonicDataLogger } from './extensions/datalogger/data-logger';
export declare function isSameTag(t1: NdefTag, t2: NdefTag): boolean;
export declare function LONG_RANGE_PROTOCOL_FILTER(meta: ProtocolMeta): boolean;
/**
 * Convert a TapDiscoverd event into a ProtocolMetaNfc
 * @param event
 */
export declare function tagToProtocolMetaNFC(tag: NdefTag): ProtocolMetaNfc;
export declare type TapConfigPutValueType<DataType> = (tap: Tap, val: DataType, ...args: any[]) => Promise<TapResponse<any>>;
export declare type TapConfigGetValueType<DataType> = ((tap: Tap, ...args: any[]) => Promise<DataType>);
export interface TapConfigItemAction {
    title: string;
    icon?: string;
    color?: string;
    call: (tap: Tap) => Promise<TapResponse<any>>;
    triggersRefresh?: TapInfo[];
}
export interface TapConfigItem<DataType = any> {
    valueRefreshRequired?: boolean;
    formValidators?: ValidatorFn[];
    title?: string;
    description?: string;
    params?: any[];
    key: TapInfo;
    actions?: TapConfigItemAction[];
    icon?: string;
    resolvedValue?: TapInfoHolder;
    viewFormatter?: (input: DataType) => string;
    editable?: boolean;
    getValue?: TapConfigGetValueType<DataType> | false;
    putValue?: TapConfigPutValueType<DataType>;
    setValue?: TapConfigPutValueType<DataType>;
    editFormatter?: {
        read: (input: string) => DataType;
        write: (input: DataType | undefined) => string | number;
    };
    input?: {
        pattern?: RegExp;
        minLength?: number;
        maxLength?: number;
        min?: number;
        max?: number;
        type?: 'text' | 'number' | 'password' | 'select' | 'toggle' | 'radio';
        options?: {
            key: any;
            text: string;
            icon?: string;
        }[];
        multiple?: boolean;
    };
    init?: (tapService: CurrentDeviceService, config: TapConfigItem<any>) => Promise<void>;
}
export declare class TapServiceError extends Error {
    static illegalArgument(msg: string): void;
    static illegalStateNoTap(): TapServiceError;
}
export declare const TAP_INFO_RESOLVER_CONFIG: InjectionToken<TapConfigItem<any>[]>;
export declare class InfoResolverService {
    infoConfig: TapConfigItem[];
    /**
     * Cache data
     */
    info: Record<string, TapInfoHolder>;
    /**
     * Observables of infos
     */
    private info$;
    private _tap?;
    set tap(tap: Tap);
    get tap(): Tap;
    constructor(infoConfig: TapConfigItem[]);
    clearTap(): void;
    /**
     * Get key configuration or undefined if key does not exist
     * @param key
     */
    getConfig(key: TapInfo): TapConfigItem | undefined;
    /**
     * Clear all cache
     * Do no complete observables
     */
    reset(): void;
    /**
     * Refreh all keys in cache
     */
    refreshKeysInCache(): Promise<void>;
    /**
     * Refresh all keys
     */
    refreshKeys(infos: TapInfo[]): Promise<void>;
    /**
     * Refresh a single key
     * Never throws
     * @param key
     */
    refreshKey<T>(key: TapInfo, params?: any[]): Promise<TapInfoHolder<T>>;
    setKeyError(key: TapInfo, error: Error, params?: any[]): TapInfoHolder;
    setKeyValue(key: TapInfo, value: TapInfoHolder, params?: any[]): TapInfoHolder<any>;
    /**
     * TODO check
     */
    isLoaded(key: TapInfo, params?: any[]): boolean;
    /**
     *
     */
    loadKeyIfNotInCache<T>(key: TapInfo, params?: any[]): Promise<TapInfoHolder<T>>;
    loadKeysIfNotInCache(infos: TapInfo[]): Promise<void>;
    /**
     * Notify new key value
     */
    notifyNewValue(key: TapInfo, value: any, params?: any[]): void;
    /**
     * Notify new key error
     * @param key
     * @param err
     */
    notifyKeyError(key: TapInfo, err: Error, params?: any[]): void;
    /**
     * What if error?
     * If key is not loaded yet, it will trigger a load
     * @param key
     */
    getKeyValue$<T>(key: TapInfo, params?: any[]): Observable<T>;
    getKeyInfo$<T>(key: TapInfo, params?: any[]): Observable<TapInfoHolder<T>>;
    private _createCacheKey;
    /**
     * Get multiples key values
     * If keys are not loaded yet, it will trigger a load
     */
    getKeyValues$<T extends TapInfo>(keys: T[]): Observable<Record<T, any>>;
    /**
     * Get multiples key values and map them according to the given parameter
     * If keys are not loaded yet, it will trigger a load
     */
    getKeyValuesMap$<T extends Record<string, TapInfo>>(mapping: T): Observable<Record<keyof T, any>>;
    clearInfo(key: TapInfo, params?: any[]): void;
    hasInfo(key: TapInfo): boolean;
    /**
     *
     * @param info
     * @param throwOnError
     */
    getInfoValue<T = string>(info: TapInfo, throwOnError?: boolean): Promise<T>;
    /**
     */
    putInfo<ValueType>(key: TapInfo, value: ValueType, params?: any[]): Promise<TapResponse<any>>;
    private _createInfoObservableIfRequired;
}
export declare class CurrentDeviceService {
    private platform;
    private toastCtrl;
    protected router: Router;
    protected protocolFactory: ProtocolFactoryService;
    infoResolver: InfoResolverService;
    private ngZone;
    /**
     * Hack to prevent angular treeshaking from removing loaded extension.
     */
    private _loadedTapExtensions;
    private _sessionStateSubscription?;
    private _connectionStateSubscription?;
    private _tap?;
    /**
     * Any connection state change
     */
    private _connectionState$?;
    /**
     * Only connection lost event
     */
    private _connectionLost$?;
    private _sessionState$;
    listeners: OnTapEvent[];
    meta: {
        isClientConfigured?: boolean;
    };
    _tapConfig?: TapConfiguratorConfig;
    _dataManager?: DataManagerIonic;
    _tapConfig$: BehaviorSubject<TapConfiguratorConfig | undefined>;
    _dataLogger?: IonicDataLogger;
    /**
     * Event trigger when a new Tap is set
     */
    tapChanged: Subject<Tap>;
    /**
     * Event triggered when tap is removed
     */
    tapRemoved: Subject<Tap>;
    private _protocolMeta;
    private _availableProtocols;
    _isManualDisconnection: boolean;
    private _keepAliveEngine?;
    get sessionStateSnapshot(): TapAuth.SessionState;
    get sessionState(): Observable<TapAuth.SessionState>;
    get protocolMeta$(): Observable<ProtocolMeta | undefined>;
    get availableProtocols$(): Observable<ProtocolMeta[]>;
    get protocolMeta(): ProtocolMeta | undefined;
    set protocolMeta(meta: ProtocolMeta | undefined);
    get connectionLost(): Observable<any>;
    get availableProtocols(): ProtocolMeta[];
    get tap(): Tap;
    get hasTap(): boolean;
    set tapConfig(schema: TapConfiguratorConfig | undefined);
    get tapConfig(): TapConfiguratorConfig | undefined;
    get tapConfig$(): Observable<TapConfiguratorConfig | undefined>;
    isSameTag(tag: NdefTag): boolean;
    isSameTap(event: TagDiscoveredEvent): Promise<{
        isSameTag: boolean;
        newTap?: Tap;
    }>;
    /**
     * Use another communicaiton protocol
     * May be rejected
     * @param meta
     * @param disonnectCurrentProtocol if set to true and if tap is already connected with a communication protocol, it will disconnect from it first
     */
    useProtocol(meta: ProtocolMeta, disonnectCurrentProtocol?: boolean, connectToNew?: boolean): Promise<void>;
    set tap(tap: Tap);
    getKeyValue$<T>(key: TapInfo, params?: any[]): Observable<T>;
    getKeyInfo$<T>(key: TapInfo, params?: any[]): Observable<TapInfoHolder<T>>;
    /**
     * Try to get key value.
     * If not, it returns undefined
     */
    tryGetValue<T = string>(key: TapInfo): Promise<T | undefined>;
    /**
     * Get key value and throw error if there is an error fetching the value
     */
    getValue<T = string>(key: TapInfo): Promise<T>;
    putInfo(key: TapInfo, value: any, params?: any[]): Promise<TapResponse<any>>;
    resetInfos(): void;
    refreshAppState(): Promise<void>;
    constructor(platform: Platform, toastCtrl: ToastController, router: Router, protocolFactory: ProtocolFactoryService, infoResolver: InfoResolverService, ngZone: NgZone);
    addProtocolMeta(meta: ProtocolMeta): void;
    /**
     * Parse NDefTag and try to create a ProtocolMeta thanks to record
     * @returns undefined if there is no other protocol in the tag
     */
    registerProtocolsFromTag(tag: NdefTag): Promise<ProtocolMeta | undefined>;
    /**
     * Will register available communication protocols on current tap
     * by asking LWM2M resources.
     * @returns the list of new ProtocolMeta found
     */
    registerProtocolsFromTap(): Promise<ProtocolMeta[]>;
    useProtocolFromMeta(newProtocolMeta: ProtocolMeta, disonnectCurrentProtocol?: boolean): Promise<void>;
    /**
     * Switch from NFC communication protocol to a long range communication
     * @warning this is only available when we are in NFC
     */
    useLongRangeProtocol(): Promise<void>;
    loginAs(username: string): Promise<import("@iotize/tap/auth/iotize-tap-auth").ScramAuth.SessionData>;
    _getPasswordFor(username: string): string;
    /**
     * Connection state events.
     * It works even when tap is changed
     */
    get connectionState(): Observable<ConnectionStateChangeEvent>;
    /**
     * @returns true if user is connected as giver username or one of the given usernames
     */
    isLoggedInAs(username: string | string[]): Promise<boolean>;
    /**
     * @returns true if user is connected as giver username
     */
    isLoggedInAs$(username: string): Observable<boolean>;
    login(username: string, password: string, refreshSessionState?: boolean): Promise<import("@iotize/tap/auth/iotize-tap-auth").ScramAuth.SessionData>;
    logout(throwError?: boolean): Promise<boolean>;
    setTap(newTap: Tap, options?: {
        emit: boolean;
    }): void;
    notifyNewTap(): void;
    setTapFromEvent(event: TapSelectedEvent, options?: {
        emit: boolean;
    }): void;
    /**
     * @warning does not throw errors, even if connect failed...
     * @returns true if connect is successful, false otherwise
     * @param throwError true if errors is thrown, false if promise resolve with false when there is an error
     */
    connect(throwError?: boolean): Promise<boolean>;
    /**
     *
     */
    disconnect(): Promise<void>;
    /**
     * Remove currently used Tap
     * If no Tap was set, do nothing
     */
    remove(): Promise<void>;
    private notifyTapRemoved;
    configureClientIfRequired(): Promise<void>;
    /**
     * Rebuild tap configuration according to data on the Tap
     *
     * TODO handle errors ...
     *
     * throws
     */
    loadConfigFromDevice(): Promise<void>;
    loadTapAppConfigPath(force?: boolean): Promise<void>;
    /**
     * Load tap configuration from a remote location
     */
    set dataManager(v: DataManagerIonic | undefined);
    get dataManager(): DataManagerIonic | undefined;
    get dataLogger(): IonicDataLogger;
    /**
     * Configure client by reading tap device configuration
     * @throws
     */
    configureClient(refresh?: boolean): Promise<void>;
    getCurrentProtocol(): ComProtocol | undefined;
    private setupListeners;
    get keepAliveEngine(): KeepAliveEngine;
    private setupConnectionStateListener;
    _executePendingCalls(): Promise<void>;
    hasProtocol(): boolean;
    registerEventListerner(listener: OnTapEvent): void;
    unregisterEventListener(listener: OnTapEvent): void;
    private onError;
}
