"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class SortedArray {
    constructor(comparator) {
        this.comparator = comparator;
        this.ary = [];
    }
    [Symbol.iterator]() {
        // We only need to sort when we are iterating
        this.ary.sort(this.comparator);
        return this.ary[Symbol.iterator]();
    }
    add(item) {
        const index = this.indexOf(item);
        if (index < 0) {
            this.ary.push(item);
        }
    }
    delete(theItem) {
        const index = this.indexOf(theItem);
        if (index >= 0) {
            this.ary.splice(index, 1);
        }
    }
    size() {
        return this.ary.length;
    }
    // Unused
    // public has(item: T) {
    //     return this.indexOf(item) >= 0
    // }
    // public isEmpty() {
    //     return this.ary.length === 0
    // }
    // public clear() {
    //     this.ary = []
    // }
    indexOf(theItem) {
        return this.ary.indexOf(theItem);
    }
}
exports.SortedArray = SortedArray;
class ListItem {
    constructor(item, previous, next) {
        this.item = item;
        this.previous = previous;
        this.next = next;
    }
}
class IteratorResultDone {
    constructor() {
        this.done = true;
        this.value = {}; // tslint:disable-line:no-object-literal-type-assertion
    }
}
class ListIteratorResult {
    constructor(value) {
        this.done = false;
        this.value = value;
    }
}
class ListIterator {
    constructor(listHead) {
        this.listHead = listHead;
        this.current = null;
    }
    next(value) {
        if (this.listHead) {
            this.current = this.listHead;
            this.listHead = null;
        }
        else if (this.current) {
            // increment right before we return the item, not earlier because folks could have add items in
            this.current = this.current.next;
        }
        if (this.current) {
            return new ListIteratorResult(this.current.item);
        }
        else {
            return new IteratorResultDone();
        }
    }
}
class SortedList {
    constructor(comparator) {
        this.comparator = comparator;
    }
    [Symbol.iterator]() {
        return new ListIterator(this.head);
    }
    add(newItem) {
        let prev = null;
        let current = this.head;
        while (current) {
            // check if the current node is less than the new node
            const cmp = current.item === newItem ? 0 : this.comparator(current.item, newItem);
            if (cmp === 0) {
                return false; // item already exists in our list
            }
            else if (cmp > 0) {
                break; // add here
            }
            prev = current;
            current = current.next;
        }
        // Cases:
        // - add to middle of list (current and prev) add just before current
        // - add to end of list (!current and prev)
        // - add to beginning of list (current and !prev)
        // - empty list (!current and !prev)
        if (prev && current) {
            // insert before the prev
            const node = new ListItem(newItem, prev, current);
            prev.next = node;
            current.previous = node;
            // this.head = node
        }
        else if (prev) {
            // same as previous case except we don't repoint current.previous
            const node = new ListItem(newItem, prev, current);
            prev.next = node;
            // current.previous = node
            // this.head = node
        }
        else if (current) {
            // insert before the prev
            const node = new ListItem(newItem, prev, current);
            // prev.next = node
            current.previous = node;
            this.head = node;
        }
        else {
            const node = new ListItem(newItem, prev, current);
            // prev.next = node
            // current.previous = node
            this.head = node;
        }
        return true; // added
    }
    delete(item) {
        const node = this.findNode(item);
        if (node) {
            // detach
            if (node.previous) {
                node.previous.next = node.next;
            }
            else if (this.head === node) {
                this.head = node.next;
            }
            else {
                throw new Error(`BUG: Invariant violation`);
            }
            if (node.next) {
                node.next.previous = node.previous;
            }
            return true;
        }
        else {
            throw new Error(`BUG: Item was not in the list`);
            // return false
        }
    }
    // Unused
    // public has(item: T) {
    //     return !!this.findNode(item)
    // }
    isEmpty() {
        return !this.head;
    }
    size() {
        let size = 0;
        for (const _item of this) {
            size++;
        }
        return size;
    }
    // Unused
    // public clear() {
    //     this.head = null
    // }
    // Unused
    // public first() {
    //     if (this.head) {
    //         return this.head.item
    //     } else {
    //         throw new Error(`BUG: List was empty so cannot get first cell`)
    //     }
    // }
    findNode(item) {
        let current = this.head;
        while (current) {
            if (current.item === item || this.comparator(current.item, item) === 0) {
                return current;
            }
            current = current.next;
        }
        return null;
    }
}
exports.SortedList = SortedList;
//# sourceMappingURL=sortedList.js.map