import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
import { EventEmitter, Handler, Subscription } from './emitter';
export { Handler as EventHandler } from './emitter';
export declare type ModelOrModelArray = Model | ModelArray<Model>;
export declare type ObjectId = string;
export interface Deferred<T> {
    promise: Promise<T>;
    resolve: (val?: T) => void;
    reject: (err: Error) => void;
}
export interface ArrayEmitter<T> extends Array<T> {
    $emitter: EventEmitter;
    $subject: BehaviorSubject<ArrayEmitter<T>>;
    on: {
        (name: string, handler: Handler): void;
    };
    off: {
        (name: string, handler: Handler): void;
    };
    listen: {
        (name: string, handler: Handler): Subscription;
    };
    once: {
        (name: string, handler: Handler): void;
    };
    addListener: {
        (name: string, handler: Handler): void;
    };
    removeListener: {
        (name: string, handler: Handler): void;
    };
}
export interface Model {
    _id?: ObjectId;
    $created: boolean;
    $deleted: boolean;
    $promise: Promise<Model>;
    $subject: BehaviorSubject<Model>;
    $resolvedSubject: Subject<Model>;
    $deferred: Deferred<Model>;
    $resolved: boolean;
    $loc: LocalModel;
    $id: string;
    $save: {
        (): Promise<Model>;
    };
    $remove: {
        (noPrompt?: boolean, skipLocal?: boolean): Promise<boolean>;
    };
    $delete: {
        (): Promise<boolean>;
    };
    $type: {
        (): string;
    };
    $reset: {
        (): void;
    };
    $refresh: {
        (): void;
    };
    $toObject: {
        (): any;
    };
    $updateServer: {
        (val: any): void;
    };
}
export interface Resource<T> {
    get?: {
        (id: string, force?: boolean): T;
        (ids: string[], force?: boolean): ModelArray<T>;
        (ids: string | string[], force?: boolean): (ModelArray<T> | T);
    };
    query?: {
        (qry: any, limit?: number): Query<T>;
    };
    chain?: ChainFunction;
    type?: {
        (): string;
    };
    collect?: {
        (seeds: Model | ModelArray<T>, relation: CollectionSearcher): Collection<T>;
    };
    updateOrCreate?: {
        (val: any): T;
    };
    dispose: {
        (): void;
    };
    addListener: {
        (name: string, handler: Handler): void;
    };
    emit: {
        (fnName: string, ...data: any[]): void;
    };
    listen: {
        (name: string, handler: Handler): Subscription;
    };
    off: {
        (name: string, handler: Handler): void;
    };
    on: {
        (name: string, handler: Handler): void;
    };
    once: {
        (name: string, handler: Handler): void;
    };
    removeListener: {
        (name: string, handler: Handler): void;
    };
    new (val?: any, fromLoc?: boolean, lastRequested?: (number | Date)): T;
}
export interface ResourceFactory<T> {
    (url: string, rootKey: string, rootKeyPlural?: string): Resource<T>;
    Chain?: Chain;
}
export interface LocalModel {
    _id?: ObjectId;
    $emitter: EventEmitter;
    $created: boolean;
    $createdAt: number;
    $deleted: boolean;
    $promise: Promise<LocalModel>;
    $deferred: Deferred<LocalModel>;
    $resolved: boolean;
    $resync: any[];
    $dbsync: Promise<void>;
    $saveprom: Promise<any>;
    $mod: Model;
    $id: string;
    $dbresync: boolean;
    $serv: ServerModel;
    $save: {
        (vals: any): Promise<LocalModel>;
    };
    $remove: {
        (skipServer?: boolean): Promise<boolean>;
    };
    $delete: {
        (): Promise<boolean>;
    };
    $refresh: {
        (): void;
    };
    $toObject: {
        (): any;
    };
    $updateServer: {
        (val: any): void;
    };
}
export interface LocalResource {
    (val: any, fromServ?: boolean, mod?: any, lastRequested?: (Date | number)): void;
    get?: {
        (ids: (string[] | string), force?: boolean, transform?: Function): (ModelArray<Model> | Model);
    };
    query?: {
        (qry: any, limit: number, Resource: any): Query<Model>;
    };
    collect?: {
        (Resource: Resource<Model>, seeds: Model | ModelArray<Model>, relation: CollectionSearcher): Collection<Model>;
    };
}
export interface LocalResourceFactory {
    (url: string, rootKey: string, rootKeyPlural: string): LocalResource;
}
export interface ServerModel {
    _id?: ObjectId;
    $id: string;
    $emitter: EventEmitter;
    $deleted: boolean;
    $promise: Promise<ServerModel>;
    $resolved: boolean;
    $fetching: boolean;
    $deferred: Deferred<ServerModel>;
    $save: {
        (patch: JSONPatch): Promise<ServerModel>;
    };
    $remove: {
        (): Promise<boolean>;
    };
    $delete: {
        (): Promise<boolean>;
    };
    $refresh: {
        (): void;
    };
    $toObject: {
        (): any;
    };
    $updateServer: {
        (val: any): void;
    };
    $updateVal: {
        (val: any): void;
    };
}
export interface ServerResource {
    (val?: any, id?: string): void;
    get?: {
        (ids: (string[] | string), force?: boolean, transform?: Function): (any[] | any);
    };
}
export interface ServerResourceFactory {
    (url: string, rootKey: string, rootKeyPlural: string): ServerResource;
}
export interface ModelArray<T> extends Array<T> {
    $promise?: Promise<ModelArray<T>>;
}
export interface Query<T> extends ArrayEmitter<T> {
    $refresh: {
        (force?: boolean): Promise<Query<T>>;
    };
    $promise: Promise<Query<T>>;
    $subject: BehaviorSubject<Query<T>>;
    $resolvedSubject: Subject<Query<T>>;
    $resolved: boolean;
    $Model: any;
    $serverResults?: Query<T>;
    $skip?: number;
    $hasNext: boolean;
    $hasPrev: boolean;
    extend: {
        (obj: any, noSanitize?: boolean, retServer?: boolean): Promise<Query<T>>;
    };
    replace: {
        (qry: any, retServer?: boolean): Promise<Query<T>>;
    };
    get: {
        (...args: any[]): any;
    };
    next: {
        (num?: number): Promise<Query<T>>;
    };
    prev: {
        (num?: number): Promise<Query<T>>;
    };
    chain: {
        (Model: any, qryFn: QueryFunction): Query<Model>;
    };
    transform: Function;
    currentLimit: number;
    currentSkip: number;
    loading: boolean;
    hasNext: boolean;
    hasPrev: boolean;
}
export interface QueryList {
    (qry: any, limit: number, Resource: any, toRes: {
        (id: string): Model;
    }): Query<Model>;
    refresh?: {
        (): any;
    };
}
export interface QueryFactory {
    (url: string, rootKey: string, rootKeyPlural: string, db: Database): QueryList;
}
export declare type QueryFunction = (this: Query<Model>, results: Model[]) => any;
export declare type MultiQueryFunction = (this: Query<Model>, results: Model[][]) => any;
export interface ChainFunction {
    (origQry: ChainableQuery<Model>, modelOrQryFn: (Resource<Model> | QueryFunction), qryFn?: QueryFunction): Query<Model>;
}
export interface Chain extends ChainFunction {
    all?: {
        (origQueries: Array<ChainableQuery<Model>>, Model: Resource<Model>, qryFn: MultiQueryFunction): Query<Model>;
    };
}
export interface ChainableQuery<T> extends Array<T> {
    $emitter: EventEmitter;
    $promise: Promise<T[]>;
}
export interface Seeds extends Array<Model> {
    on?: {
        (name: string, handler: Handler): void;
    };
    removeListener?: {
        (name: string, handler: Handler): void;
    };
}
export interface CollectionFactory<T> {
    (): CollectionStatic<T>;
}
export interface CollectionStatic<T> {
    new (Resource: Resource<T>, seeds: Model | Seeds, searcherOrProp: CollectionSearcher): Collection<T>;
}
export interface Collection<T> extends ArrayEmitter<T> {
    $promise: Promise<Collection<T>>;
    $resolved: boolean;
    chain: {
        (Model: any, qryFn: QueryFunction): Query<T>;
    };
    check: {
        (): void;
    };
}
export interface CollectionSearcher {
    (objs: Model[]): Observable<(Model[] | string[])>;
}
export interface SocketFactory {
    (url: string, rootKey: string, rootKeyPlural?: string): Socket;
}
export interface Socket {
    get: {
        (ids: string[]): Promise<any>;
    };
    query: {
        (query: any): Promise<any>;
    };
    patch: {
        (id: string, patch: JSONPatch): Promise<any>;
    };
    create: {
        (data: any): Promise<any>;
    };
    remove: {
        (id: string): Promise<any>;
    };
}
export interface DatabaseFactory {
    (): Database;
}
export declare abstract class Database {
    abstract update(res: LocalModel): Promise<any>;
    abstract query(qry: any): Promise<string[]>;
    abstract qryIsSimple(qry: any): boolean;
}
export declare type JSONPatch = (OpPatch | OpPatch[]);
export declare type OpPatch = AddPath | RemovePath | ReplacePath | MovePath | CopyPath | TestPath;
export interface Patch {
    op: string;
}
export interface AddPath extends Patch {
    path: string;
    value: any;
}
export interface RemovePath extends Patch {
    path: string;
}
export interface ReplacePath extends Patch {
    path: string;
    value: any;
}
export interface MovePath extends Patch {
    from: string;
    path: string;
}
export interface CopyPath extends Patch {
    from: string;
    path: string;
}
export interface TestPath extends Patch {
    path: string;
    value: any;
}
export interface LocalForage {
    getItem<T>(key: string): Promise<T>;
    getItem<T>(key: string, callback: (err: any, value: T) => void): void;
    setItem<T>(key: string, value: T): Promise<T>;
    setItem<T>(key: string, value: T, callback: (err: any, value: T) => void): void;
    removeItem(key: string): Promise<void>;
    removeItem(key: string, callback: (err: any) => void): void;
    clear(): Promise<void>;
    clear(callback: (err: any) => void): void;
    length(): Promise<number>;
    length(callback: (err: any, numberOfKeys: number) => void): void;
    key(keyIndex: number): Promise<string>;
    key(keyIndex: number, callback: (err: any, key: string) => void): void;
    keys(): Promise<string[]>;
    keys(callback: (err: any, keys: string[]) => void): void;
    iterate(iteratee: (value: any, key: string, iterationNumber: number) => any): Promise<any>;
    iterate(iteratee: (value: any, key: string, iterationNumber: number) => any, callback: (err: any, result: any) => void): void;
    driver(): string;
}
export interface Plugin<T> {
    (Resource: Resource<T>, modelName: string): void;
}
