import * as tslib_1 from "tslib";
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';
var PagedDataSource = /** @class */ (function () {
    function PagedDataSource(request$, pageSize) {
        if (pageSize === void 0) { pageSize = 50; }
        var _this = this;
        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(function () { return _this.reset(); }), publishReplay(1), refCount());
        var count$ = request$.pipe(tap(function () { return console.log('fetch count'); }), switchMap(function (request) {
            return request
                .limit(Request.INFINITE_LIMIT)
                .exclusiveStartKey(null)
                .execCount();
        }), tap(function (count) { return console.log('got count', count); }), share());
        var data$ = combineLatest(request$, this.nextSubject).pipe(tap(function () { return console.log('request changed or next page was requested, call for data'); }), map(function (values) { return values[0]; }), switchMap(function (request) { return _this.fetchData(request); }), tap(function (data) {
            var _a;
            return (_a = _this.data).push.apply(_a, tslib_1.__spread(data));
        }), share());
        combineLatest(data$, count$)
            .pipe(map(function (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(function (meta) { return _this.metaSubject.next(meta); });
        var hasMore$ = this.meta$.pipe(map(function (meta) {
            return meta.hasMore;
        }), share());
        this.hasMore$ = hasMore$;
        this.count$ = count$;
        // subscribe to get it rolling
        data$.subscribe(function () { return console.log('fetched data'); }, function (error) { return console.error('could not fetch data', error); });
        // fetch the first set of data
        this.next();
    }
    PagedDataSource.prototype.next = function () {
        this.nextSubject.next();
    };
    /**
     * removes the given item if it exists in data set, and updates the counter.
     * @param item
     */
    PagedDataSource.prototype.removeItem = function (item) {
        // FIXME remove any when https://github.com/Microsoft/TypeScript/issues/21592 is fixed
        var index = findIndex(this.data, item);
        if (index !== -1) {
            this.data.splice(index, 1);
            var meta = this.metaSubject.getValue();
            meta.current--;
            meta.total--;
            this.metaSubject.next(meta);
        }
        else {
            console.warn('the given item could not be found');
        }
    };
    PagedDataSource.prototype.addItem = function (item) {
        this.data.unshift(item);
        var 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
     */
    PagedDataSource.prototype.editItem = function (updatedItem, predicate) {
        var index = findIndex(this.data, predicate);
        if (index !== -1) {
            this.data[index] = updatedItem;
        }
        else {
            console.error('could not find the item with predicate «%s»', predicate);
        }
    };
    PagedDataSource.prototype.reset = function () {
        console.log('reset');
        this.data = [];
        this.lastKey = null;
    };
    PagedDataSource.prototype.fetchData = function (request) {
        var _this = this;
        console.log('fetchData()');
        this.loadingSubject.next(true);
        return request
            .exclusiveStartKey(this.lastKey)
            .limit(this.pageSize)
            .execFullResponse()
            .pipe(tap(function (response) {
            console.log(response);
            _this.lastKey = response.LastEvaluatedKey === undefined ? null : response.LastEvaluatedKey;
        }), map(function (response) { return response.Items || []; }), finalize(function () {
            console.log('fetchData(): finally');
            _this.loadingSubject.next(false);
        }));
    };
    return PagedDataSource;
}());
export { PagedDataSource };
//# sourceMappingURL=paged-data-source.js.map