import { RBNode } from './rbNode';
import { RBColor } from './rbColor';
// import {Assert} from './../../utils/assert'
export class RBTree {
    constructor(comparer) {
        this.comparer = comparer;
        this.count = 0;
        this.root = this.nil = new RBNode(RBColor.Black);
    }
    [Symbol.iterator]() {
        return this.allNodes();
    }
    clear() {
        this.root = this.nil = new RBNode(RBColor.Black);
    }
    toNull(y) {
        return y != this.nil ? y : null;
    }
    isEmpty() {
        return this.root == this.nil;
    }
    getComparer() {
        return this.comparer;
    }
    getRoot() {
        return this.root;
    }
    find(i, x = this.root) {
        let compareResult;
        while (x != this.nil && (compareResult = this.comparer(i, x.item)) != 0)
            x = compareResult < 0 ? x.left : x.right;
        return this.toNull(x);
    }
    findFirst(predicate, n = this.root) {
        if (n == this.nil)
            return null;
        let good = null;
        while (n != this.nil) {
            n = predicate(n.item) ? (good = n).left : n.right;
        }
        return good;
    }
    findLast(predicate, n = this.root) {
        if (n == this.nil)
            return null;
        let good = null;
        while (n != this.nil)
            n = predicate(n.item) ? (good = n).right : n.left;
        return good;
    }
    treeMinimum(x = this.root) {
        while (x.left != this.nil)
            x = x.left;
        return this.toNull(x);
    }
    treeMaximum(x = this.root) {
        while (x.right != this.nil)
            x = x.right;
        return this.toNull(x);
    }
    next(x) {
        if (x.right != this.nil)
            return this.treeMinimum(x.right);
        let y = x.parent;
        while (y != this.nil && x == y.right) {
            x = y;
            y = y.parent;
        }
        return this.toNull(y);
    }
    previous(x) {
        if (x.left != this.nil)
            return this.treeMaximum(x.left);
        let y = x.parent;
        while (y != this.nil && x == y.left) {
            x = y;
            y = y.parent;
        }
        return this.toNull(y);
    }
    leftRotate(x) {
        const y = x.right;
        x.right = y.left;
        if (y.left != this.nil)
            y.left.parent = x;
        y.parent = x.parent;
        if (x.parent == this.nil)
            this.root = y;
        else if (x == x.parent.left)
            x.parent.left = y;
        else
            x.parent.right = y;
        y.left = x;
        x.parent = y;
    }
    rightRotate(x) {
        const y = x.left;
        x.left = y.right;
        if (y.right != this.nil)
            y.right.parent = x;
        y.parent = x.parent;
        if (x.parent == this.nil)
            this.root = y;
        else if (x == x.parent.right)
            x.parent.right = y;
        else
            x.parent.left = y;
        y.right = x;
        x.parent = y;
    }
    deleteFixup(x) {
        while (x != this.root && x.color == RBColor.Black) {
            if (x == x.parent.left) {
                let w = x.parent.right;
                if (w.color == RBColor.Red) {
                    w.color = RBColor.Black;
                    x.parent.color = RBColor.Red;
                    this.leftRotate(x.parent);
                    w = x.parent.right;
                }
                if (w.left.color == RBColor.Black && w.right.color == RBColor.Black) {
                    w.color = RBColor.Red;
                    x = x.parent;
                }
                else {
                    if (w.right.color == RBColor.Black) {
                        w.left.color = RBColor.Black;
                        w.color = RBColor.Red;
                        this.rightRotate(w);
                        w = x.parent.right;
                    }
                    w.color = x.parent.color;
                    x.parent.color = RBColor.Black;
                    w.right.color = RBColor.Black;
                    this.leftRotate(x.parent);
                    x = this.root;
                }
            }
            else {
                let w = x.parent.left;
                if (w.color == RBColor.Red) {
                    w.color = RBColor.Black;
                    x.parent.color = RBColor.Red;
                    this.rightRotate(x.parent);
                    w = x.parent.left;
                }
                if (w.right.color == RBColor.Black && w.left.color == RBColor.Black) {
                    w.color = RBColor.Red;
                    x = x.parent;
                }
                else {
                    if (w.left.color == RBColor.Black) {
                        w.right.color = RBColor.Black;
                        w.color = RBColor.Red;
                        this.leftRotate(w);
                        w = x.parent.left;
                    }
                    w.color = x.parent.color;
                    x.parent.color = RBColor.Black;
                    w.left.color = RBColor.Black;
                    this.rightRotate(x.parent);
                    x = this.root;
                }
            }
        }
        x.color = RBColor.Black;
    }
    deleteSubTree(z) {
        //Assert.assert(z != nil);
        /*Assert.assert(z != this.nil, 'root of subtree to delete must not be null.')*/
        let y;
        if (z.left == this.nil || z.right == this.nil) {
            /* y has a nil node as a child */
            y = z;
        }
        else {
            /* find tree successor with a nilnode as a child */
            y = z.right;
            while (y.left != this.nil)
                y = y.left;
        }
        /* x is y's only child */
        const x = y.left != this.nil ? y.left : y.right;
        x.parent = y.parent;
        if (y.parent == this.nil)
            this.root = x;
        else {
            if (y == y.parent.left)
                y.parent.left = x;
            else
                y.parent.right = x;
        }
        if (y != z)
            z.item = y.item;
        if (y.color == RBColor.Black)
            this.deleteFixup(x);
        return this.toNull(z);
    }
    deleteNodeInternal(x) {
        this.count--;
        this.deleteSubTree(x);
    }
    remove(i) {
        const n = this.find(i);
        if (n != null) {
            this.count--;
            return this.deleteSubTree(n);
        }
        return null;
    }
    insert(v) {
        const x = this.treeInsert(v);
        this.insertPrivate(x);
        return this.toNull(x);
    }
    treeInsert(z) {
        let y = this.nil;
        let x = this.root;
        let compareRes = 0;
        while (x != this.nil) {
            y = x;
            //#if SHARPKIT //https://code.google.com/p/sharpkit/issues/detail?id=368
            // compareRes = Comparer.Compare(z, x.Item);
            // x = compareRes < 0 ? x.left : x.right;
            compareRes = this.comparer(z, x.item);
            x = compareRes < 0 ? x.left : x.right;
            // #else
            //     x = (compareRes = Comparer.Compare(z, x.Item)) < 0 ? x.left : x.right;
            // #endif
        }
        const nz = new RBNode(RBColor.Black, z, y, this.nil, this.nil);
        if (y == this.nil)
            this.root = nz;
        else if (compareRes < 0)
            y.left = nz;
        else
            y.right = nz;
        return this.toNull(nz);
    }
    insertPrivate(x) {
        this.count++;
        x.color = RBColor.Red;
        while (x != this.root && x.parent.color == RBColor.Red) {
            if (x.parent == x.parent.parent.left) {
                const y = x.parent.parent.right;
                if (y.color == RBColor.Red) {
                    x.parent.color = RBColor.Black;
                    y.color = RBColor.Black;
                    x.parent.parent.color = RBColor.Red;
                    x = x.parent.parent;
                }
                else {
                    if (x == x.parent.right) {
                        x = x.parent;
                        this.leftRotate(x);
                    }
                    x.parent.color = RBColor.Black;
                    x.parent.parent.color = RBColor.Red;
                    this.rightRotate(x.parent.parent);
                }
            }
            else {
                const y = x.parent.parent.left;
                if (y.color == RBColor.Red) {
                    x.parent.color = RBColor.Black;
                    y.color = RBColor.Black;
                    x.parent.parent.color = RBColor.Red;
                    x = x.parent.parent;
                }
                else {
                    if (x == x.parent.left) {
                        x = x.parent;
                        this.rightRotate(x);
                    }
                    x.parent.color = RBColor.Black;
                    x.parent.parent.color = RBColor.Red;
                    this.leftRotate(x.parent.parent);
                }
            }
        }
        this.root.color = RBColor.Black;
    }
    *allNodes() {
        if (this.isEmpty())
            return;
        let c = this.treeMinimum();
        while (c != null) {
            yield c.item;
            c = this.next(c);
        }
        return;
    }
    toString() {
        let ret = '{';
        let i = 0;
        for (const node of this.allNodes()) {
            ret += node.toString();
            if (i != this.count - 1) {
                ret += '\n';
            }
            i++;
        }
        return ret + '}';
    }
}
//# sourceMappingURL=rbTree.js.map