import EventEmitter = require('tiny-emitter');
import {SortDirection} from '../typings/common';

type Action = 'in';

type SoritngParams = {
    fieldId: string;
    direction: SortDirection;
};

type ItemConverter = Function;

type Field = {
    id: string;
    type: string;
    isPrimaryKey: boolean;
    getter: Function;
    comparator: Function;
    textFilterHandler: Function;
    fieldFilterHandler: Function;
}

type Filter = {
    field: string;
    action: Action;
    value: any;
    inverted: boolean;
}

type ItemsMap<V> = {[key: string]: V};

type BackendResponse<V> = {
    data: V[],
    filteredCount: number,
    totalCount: number
};

type LocalResponse<V> = V[];
type FieldsHashMap = {[key: string]: Field};

export abstract class Store<V> extends EventEmitter {
    primaryKey: string;
    storeType: string;
    data: V[];
    rawData: V[];
    totalCount: number;
    filteredCount: number;
    filteringFields: any[];
    params: {
        sorting: SoritngParams;
        currentPage: number;
        pageSize: number | null;
    };
    stateName: string;
    fields: Field[];

    constructor(params: any);
    clone(): Store<V>;
    register(type: string): void;
    destructor(): void;
    getFieldById(fieldId: Field['id']): Field;
    resetCurrentPage(): void;
    setInitialFieldsFilter(filter: Filter): void;
    setInitialTextFilter(searchString: string): void;
    setTextFilter(searchString: string): void;
    setInitialSorting(fieldId: string, direction: SortDirection): void;
    setInitialPagination(currentPage: number, pageSize: number): void;
    setItems(items: any[], skipConversion: boolean): void;
    getItemsCollection(converter: ItemConverter): {[key: string]: any};
    extendFormState(items: {[key: string]: any}, converter: ItemConverter): {[key: string]: any}; // FIXME add more exact types
    abstract loadWithParams(): Promise<BackendResponse<V>> | void;
    abstract loadAll(): Promise<LocalResponse<V>> | void;
    load(): void;
    protected startLoading(): void;
    protected endLoading(): void;
    protected internalLoad(forced: boolean): void;
    reload(): void;
    convert(data: V[]): V[];
    setFilteringFields(fields: []): void;
    setFilteringFields(fields: string, ...restfields: string[]): void;
    static getDefaultComparator(type: any): ItemConverter;
    static compareStrings(a: string, b: string, direction: SortDirection): number;
    static compareNumbers(a: number, b: number, direction: SortDirection): number;

    static defaultFilter(value: any, callback: Function): void;
    static getDefaultTextFilterHandler(type: any): Function;
    static getDefaultFieldFilterHandler(type: any): Function;
    static getFilterByAction(action: Action, filterValue: any): Function;
    abstract useBackend(): boolean;
    getClientDebounceValue(): number;
    getBackendDebounceValue(): number;
    setFields(fields: Field[] | FieldsHashMap): void;
    private setFieldsFromArray(fields: Field[]): void;
    private setFieldsFromObject(fields: FieldsHashMap): void;
    setCurrentPage(index: number): void;
    setPageSize(size: number): void;
    private writeState(attrs: any): void;
    private readState(): any;
    sortBy(fieldId: Field['id'], direction: SortDirection): void;
    filterByText(searchString: string): void;
    filterByFields(fields: Filter[]): void;
    filterByField(fieldName: string, value: Filter['value']): void;
    filterByField(fieldName: string, action: Filter['action'], value: Filter['value']): void;
    resetFieldFilter(fieldName: string): void;
    getCurrentFilter(excludedFieldName: string): Filter[];
    getFiltered<D = any>(list: D[]): D[];
    getSorted<D = any>(list: D[]): D[];
    getSliced<D = any>(list: D[]): D[];
    validateCurrentPage<D = any>(list: D[]): void;
    calculate(data: any[]): void;
    notifyChanges(hasRawDataChanges): void;
    onChange(handler: Function, context: any): void;
    onDeleteItems(handler: Function, context: any): void;
    getTotalCount(): number;
    getIsLastPage(): boolean;
    getFilteredCount(): number;
    getData(): V[];
    getRawData(): any[];
    getPrimaryKeys(): any[];
    getCount(): number;
    getCurrentPage(): number;
    getPageSize(): number;
    getSorting(): SoritngParams
    getSortingFieldId(): SoritngParams['fieldId'];
    getSortingDirection(): SoritngParams['direction'];
    static searchStringToRegExp(str): RegExp;
    static getHighlightRegExp(str): RegExp;
}