/*
 * Copyright 2020 IBM Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { v4 as uuid } from 'uuid';
export default class CircularBuffer {
    constructor(first, capacity = 15) {
        this.entries = new Array(capacity);
        this.activeIdx = 0;
        this.prev = -1;
        this.next = -1;
        this.insertionIdx = 1 % capacity;
        this._length = 1;
        this.entries[0] = this.entry(first, { prev: this.prev, next: this.next });
    }
    entry(asGiven, updatePointer) {
        return Object.assign(asGiven, { key: uuid(), prev: updatePointer.prev, next: updatePointer.next });
    }
    get length() {
        return this._length;
    }
    get key() {
        return this.peek().key;
    }
    findIndex(predicate) {
        return this.entries.findIndex(predicate);
    }
    update(idx, t) {
        if (idx !== this.activeIdx) {
            this.next = -1;
            this.prev = this.activeIdx;
            this.entries[idx] = this.entry(t, { prev: this.prev, next: this.next });
            this.entries[this.prev].next = idx;
        }
        else {
            this.entries[idx] = this.entry(t, { prev: this.entries[idx].prev, next: this.entries[idx].next });
        }
        this.activeIdx = idx;
    }
    /** update at this.activeIdx */
    updateActive(t) {
        this.update(this.activeIdx, t);
    }
    push(entry) {
        this.next = -1;
        this.prev = this.activeIdx;
        const idx = this.insertionIdx;
        this.entries[idx] = this.entry(entry, { prev: this.prev, next: this.next });
        this.entries[this.prev].next = idx;
        this.activeIdx = idx;
        this.insertionIdx = (idx + 1) % this.entries.length;
        this._length = Math.min(this._length + 1, this.entries.length);
    }
    /** pop the entry at idx */
    popAt(idx) {
        while (idx < this._length - 1) {
            const nextEntry = this.entries[idx + 1];
            this.entries[idx] = this.entry(nextEntry, { prev: nextEntry.prev, next: nextEntry.next });
            idx += 1;
        }
        delete this.entries[idx];
        this.activeIdx = idx - 1;
        this.insertionIdx = idx % this.entries.length;
        this._length = this._length - 1;
    }
    before() {
        this.activeIdx = this.prev;
        this.next = this.entries[this.prev].next;
        this.prev = this.entries[this.prev].prev;
        return this.peekAt(this.activeIdx);
    }
    hasBefore() {
        return this.prev >= 0;
    }
    hasAfter() {
        return this.next >= 0;
    }
    hasBuffer() {
        return this.hasBefore() || this.hasAfter();
    }
    after() {
        this.activeIdx = this.next;
        this.prev = this.entries[this.next].prev;
        this.next = this.entries[this.next].next;
        return this.peekAt(this.activeIdx);
    }
    hasLeft() {
        return this.activeIdx > 0;
    }
    peek() {
        return this.peekAt(this.activeIdx);
    }
    peekAt(idx) {
        return this.entries[idx];
    }
}
//# sourceMappingURL=CircularBuffer.js.map