"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.List = exports.ListMakeHead = exports.ListRemoveEntry = void 0;
/**
 * @deprecated  for internal use only. public export will be removed.
 * @internal
 */
function ListRemoveEntry(entry) {
    if (entry === undefined) {
        return undefined;
    }
    else if (entry.isHead) {
        return undefined;
    }
    else {
        entry.next.prev = entry.prev;
        entry.prev.next = entry.next;
        entry.next = deadhead;
        entry.prev = deadhead;
    }
    return (entry);
}
exports.ListRemoveEntry = ListRemoveEntry;
function ListMakeEntry(data) {
    return new List(false, data);
}
/**
 * @deprecated  for internal use only. public export will be removed.
 * @internal
 */
function ListMakeHead() {
    return new List(true, undefined);
}
exports.ListMakeHead = ListMakeHead;
/**
 * @deprecated  for internal use only. public export will be removed.
 * @internal
 */
class List {
    constructor(isHead, data) {
        this.isHead = isHead;
        this.data = data;
        this.prev = this;
        this.next = this;
    }
    clear() {
        if (this.isHead) {
            this.prev = this;
            this.next = this;
        }
    }
    add(data) {
        const entry = ListMakeEntry(data);
        this.prev.next = entry;
        entry.next = this;
        entry.prev = this.prev;
        this.prev = entry;
        return (entry);
    }
    dequeue() {
        if (!this.empty()) {
            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
            const removedEntry = ListRemoveEntry(this.next);
            return removedEntry.data;
        }
    }
    enqueue(data) {
        return this.add(data);
    }
    pop() {
        const removedEntry = ListRemoveEntry(this.prev);
        return removedEntry ? removedEntry.data : undefined;
    }
    walk(fn) {
        for (let entry = this.next; !(entry.isHead); entry = entry.next) {
            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
            fn(entry.data, entry);
        }
    }
    some(fn, rev) {
        const rtn = [];
        const start = rev ? this.prev : this.next;
        for (let entry = start; !(entry.isHead); entry = rev ? entry.prev : entry.next) {
            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
            const data = entry.data;
            if (fn(data, entry)) {
                if (rev) {
                    // preserve list order when in reverse
                    rtn.unshift(data);
                }
                else {
                    rtn.push(data);
                }
            }
        }
        return rtn;
    }
    count() {
        let entry;
        let i;
        entry = this.next;
        for (i = 0; !(entry.isHead); i++) {
            entry = entry.next;
        }
        return (i);
    }
    first() {
        if (!this.empty()) {
            return (this.next.data);
        }
    }
    last() {
        if (!this.empty()) {
            return (this.prev.data);
        }
    }
    empty() {
        return (this.next === this);
    }
    unshift(data) {
        const entry = ListMakeEntry(data);
        entry.data = data;
        entry.isHead = false;
        entry.next = this.next;
        entry.prev = this;
        this.next = entry;
        entry.next.prev = entry;
    }
    [Symbol.iterator]() {
        let node = this.next;
        const iterator = {
            next() {
                while (node && node.isHead === false) {
                    const value = node.data;
                    node = node.next;
                    if (value !== undefined) {
                        return { value, done: false };
                    }
                }
                return { value: undefined, done: true };
            },
            [Symbol.iterator]() {
                return this;
            },
        };
        return iterator;
    }
}
exports.List = List;
const deadhead = ListMakeHead();
//# sourceMappingURL=list.js.map