"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const lodash_1 = require("lodash");
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const request_model_1 = require("../request/request.model");
class PagedDataSource {
    constructor(request$, pageSize = 50) {
        this.pageSize = pageSize;
        this.loadingSubject = new rxjs_1.BehaviorSubject(false);
        this.nextSubject = new rxjs_1.Subject();
        this.metaSubject = new rxjs_1.BehaviorSubject({ current: 0, total: 0, hasMore: false });
        this.data = [];
        this.loading$ = this.loadingSubject.asObservable();
        this.meta$ = this.metaSubject.asObservable();
        request$ = request$.pipe(operators_1.tap(() => this.reset()), operators_1.publishReplay(1), operators_1.refCount());
        const count$ = request$.pipe(operators_1.tap(() => console.log('fetch count')), operators_1.switchMap(request => request
            .limit(request_model_1.Request.INFINITE_LIMIT)
            .exclusiveStartKey(null)
            .execCount()), operators_1.tap(count => console.log('got count', count)), operators_1.share());
        const data$ = rxjs_1.combineLatest(request$, this.nextSubject).pipe(operators_1.tap(() => console.log('request changed or next page was requested, call for data')), operators_1.map(values => values[0]), operators_1.switchMap(request => this.fetchData(request)), operators_1.tap(data => this.data.push(...data)), operators_1.share());
        rxjs_1.combineLatest(data$, count$)
            .pipe(operators_1.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],
            };
        }), operators_1.share())
            .subscribe(meta => this.metaSubject.next(meta));
        const hasMore$ = this.meta$.pipe(operators_1.map(meta => {
            return meta.hasMore;
        }), operators_1.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 = lodash_1.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 = lodash_1.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(operators_1.tap(response => {
            console.log(response);
            this.lastKey = response.LastEvaluatedKey === undefined ? null : response.LastEvaluatedKey;
        }), operators_1.map(response => response.Items || []), operators_1.finalize(() => {
            console.log('fetchData(): finally');
            this.loadingSubject.next(false);
        }));
    }
}
exports.PagedDataSource = PagedDataSource;
//# sourceMappingURL=paged-data-source.js.map