import { findIndex } from 'lodash';
import { BehaviorSubject, combineLatest, Subject } from 'rxjs';
import { finalize, map, publishReplay, refCount, share, switchMap, tap } from 'rxjs/operators';
import { Request } from '../request/request.model';
export class PagedDataSource {
    constructor(request$, pageSize = 50) {
        this.pageSize = pageSize;
        this.loadingSubject = new BehaviorSubject(false);
        this.nextSubject = new Subject();
        this.metaSubject = new BehaviorSubject({ current: 0, total: 0, hasMore: false });
        this.data = [];
        this.loading$ = this.loadingSubject.asObservable();
        this.meta$ = this.metaSubject.asObservable();
        request$ = request$.pipe(tap(() => this.reset()), publishReplay(1), refCount());
        const count$ = request$.pipe(tap(() => console.log('fetch count')), switchMap(request => request
            .limit(Request.INFINITE_LIMIT)
            .exclusiveStartKey(null)
            .execCount()), tap(count => console.log('got count', count)), share());
        const data$ = combineLatest(request$, this.nextSubject).pipe(tap(() => console.log('request changed or next page was requested, call for data')), map(values => values[0]), switchMap(request => this.fetchData(request)), tap(data => this.data.push(...data)), share());
        combineLatest(data$, count$)
            .pipe(map(values => {
            console.log('data or count changed -> hasMore', this.data.length < values[1]);
            return {
                current: this.data.length,
                total: values[1],
                hasMore: this.data.length < values[1],
            };
        }), share())
            .subscribe(meta => this.metaSubject.next(meta));
        const hasMore$ = this.meta$.pipe(map(meta => {
            return meta.hasMore;
        }), share());
        this.hasMore$ = hasMore$;
        this.count$ = count$;
        // subscribe to get it rolling
        data$.subscribe(() => console.log('fetched data'), error => console.error('could not fetch data', error));
        // fetch the first set of data
        this.next();
    }
    next() {
        this.nextSubject.next();
    }
    /**
     * removes the given item if it exists in data set, and updates the counter.
     * @param item
     */
    removeItem(item) {
        // FIXME remove any when https://github.com/Microsoft/TypeScript/issues/21592 is fixed
        const index = findIndex(this.data, item);
        if (index !== -1) {
            this.data.splice(index, 1);
            const meta = this.metaSubject.getValue();
            meta.current--;
            meta.total--;
            this.metaSubject.next(meta);
        }
        else {
            console.warn('the given item could not be found');
        }
    }
    addItem(item) {
        this.data.unshift(item);
        const meta = this.metaSubject.getValue();
        meta.current++;
        meta.total++;
        this.metaSubject.next(meta);
    }
    /**
     * will search for the item using _.findIndex(predicate) and replaces the found item with the updatedItem,
     * logs an error if the item to replace could not be found
     */
    editItem(updatedItem, predicate) {
        const index = findIndex(this.data, predicate);
        if (index !== -1) {
            this.data[index] = updatedItem;
        }
        else {
            console.error('could not find the item with predicate «%s»', predicate);
        }
    }
    reset() {
        console.log('reset');
        this.data = [];
        this.lastKey = null;
    }
    fetchData(request) {
        console.log('fetchData()');
        this.loadingSubject.next(true);
        return request
            .exclusiveStartKey(this.lastKey)
            .limit(this.pageSize)
            .execFullResponse()
            .pipe(tap(response => {
            console.log(response);
            this.lastKey = response.LastEvaluatedKey === undefined ? null : response.LastEvaluatedKey;
        }), map(response => response.Items || []), finalize(() => {
            console.log('fetchData(): finally');
            this.loadingSubject.next(false);
        }));
    }
}
//# sourceMappingURL=paged-data-source.js.map