import { ArrayUtil } from '../util/ArrayUtil';
import { NullRecord } from './NullRecord';
import { QueryDirectionEnum } from './types';
/**
 * *********************************
 */
class HasMoreQueryMarker extends NullRecord {
}
HasMoreQueryMarker.singleton = new HasMoreQueryMarker();
class IsEmptyQueryMarker extends NullRecord {
}
IsEmptyQueryMarker.singleton = new IsEmptyQueryMarker();
export var QueryMarkerOption;
(function (QueryMarkerOption) {
    QueryMarkerOption[QueryMarkerOption["None"] = 0] = "None";
    QueryMarkerOption[QueryMarkerOption["IsEmpty"] = 1] = "IsEmpty";
    QueryMarkerOption[QueryMarkerOption["HasMore"] = 2] = "HasMore";
})(QueryMarkerOption || (QueryMarkerOption = {}));
export class QueryScroller {
    constructor(_dialog, _defaultPageSize, _firstRecordId, _markerOptions = []) {
        this._dialog = _dialog;
        this._defaultPageSize = _defaultPageSize;
        this._firstRecordId = _firstRecordId;
        this._markerOptions = _markerOptions;
        this.clear();
    }
    get buffer() {
        return this._buffer;
    }
    get bufferWithMarkers() {
        const result = ArrayUtil.copy(this._buffer);
        if (this.isComplete) {
            if (this._markerOptions.indexOf(QueryMarkerOption.IsEmpty) > -1) {
                if (this.isEmpty) {
                    result.push(IsEmptyQueryMarker.singleton);
                }
            }
        }
        else if (this._markerOptions.indexOf(QueryMarkerOption.HasMore) > -1) {
            if (result.length === 0) {
                result.push(HasMoreQueryMarker.singleton);
            }
            else {
                if (this._hasMoreBackward) {
                    result.unshift(HasMoreQueryMarker.singleton);
                }
                if (this._hasMoreForward) {
                    result.push(HasMoreQueryMarker.singleton);
                }
            }
        }
        return result;
    }
    get dialog() {
        return this._dialog;
    }
    get firstRecordId() {
        return this._firstRecordId;
    }
    get hasMoreBackward() {
        return this._hasMoreBackward;
    }
    get hasMoreForward() {
        return this._hasMoreForward;
    }
    get isComplete() {
        return !this._hasMoreBackward && !this._hasMoreForward;
    }
    get isCompleteAndEmpty() {
        return this.isComplete && this._buffer.length === 0;
    }
    get isEmpty() {
        return this._buffer.length === 0;
    }
    pageBackward(pageSize = this.pageSize) {
        if (!this._hasMoreBackward) {
            return Promise.resolve([]);
        }
        if (this._prevPagePromise) {
            this._prevPagePromise = this._prevPagePromise.then((recordSet) => {
                const fromRecordId = this._buffer.length === 0 ? null : this._buffer[0].id;
                return this._dialog.query(pageSize, QueryDirectionEnum.BACKWARD, fromRecordId);
            });
        }
        else {
            const fromRecordId = this._buffer.length === 0 ? null : this._buffer[0].id;
            this._prevPagePromise = this._dialog.query(pageSize, QueryDirectionEnum.BACKWARD, fromRecordId);
        }
        return this._prevPagePromise.then((queryResult) => {
            this._hasMoreBackward = queryResult.hasMore;
            if (queryResult.records.length > 0) {
                const newBuffer = [];
                for (let i = queryResult.records.length - 1; i > -1; i--) {
                    newBuffer.push(queryResult.records[i]);
                }
                this._buffer.forEach((record) => {
                    newBuffer.push(record);
                });
                this._buffer = newBuffer;
            }
            return queryResult.records;
        });
    }
    pageForward(pageSize = this.pageSize) {
        if (!this._hasMoreForward) {
            return Promise.resolve([]);
        }
        if (this._nextPagePromise) {
            this._nextPagePromise = this._nextPagePromise.then((recordSet) => {
                const fromRecordId = this._buffer.length === 0 ? null : this._buffer[this._buffer.length - 1].id;
                return this._dialog.query(pageSize, QueryDirectionEnum.FORWARD, fromRecordId);
            });
        }
        else {
            const fromRecordId = this._buffer.length === 0 ? null : this._buffer[this._buffer.length - 1].id;
            this._nextPagePromise = this._dialog.query(pageSize, QueryDirectionEnum.FORWARD, fromRecordId);
        }
        return this._nextPagePromise.then((queryResult) => {
            this._hasMoreForward = queryResult.hasMore;
            if (queryResult.records.length > 0) {
                const newBuffer = [];
                this._buffer.forEach((record) => {
                    newBuffer.push(record);
                });
                queryResult.records.forEach((record) => {
                    newBuffer.push(record);
                });
                this._buffer = newBuffer;
            }
            return queryResult.records;
        });
    }
    get pageSize() {
        return this._defaultPageSize;
    }
    refresh(numRows = this.pageSize) {
        if (this._refreshPromise) {
            this._refreshPromise = this._refreshPromise.then((records) => {
                this.clear();
                return this.pageForward(numRows);
            });
        }
        else {
            this.clear();
            this._refreshPromise = this.pageForward(numRows);
        }
        return this._refreshPromise.then((records) => {
            if (records.length > 0) {
                this._firstResultRecordId = records[0].id;
            }
            return records;
        });
    }
    trimFirst(n) {
        const newBuffer = [];
        for (let i = n; i < this._buffer.length; i++) {
            newBuffer.push(this._buffer[i]);
        }
        this._buffer = newBuffer;
        this._hasMoreBackward = true;
    }
    trimLast(n) {
        const newBuffer = [];
        for (let i = 0; i < this._buffer.length - n; i++) {
            newBuffer.push(this._buffer[i]);
        }
        this._buffer = newBuffer;
        this._hasMoreForward = true;
    }
    clear() {
        this._hasMoreBackward = !!this._firstRecordId;
        this._hasMoreForward = true;
        this._buffer = [];
        this._firstResultRecordId = null;
    }
}
