// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
/** This module is browser compatible. */ import { ascend, BinarySearchTree } from "./binary_search_tree.ts";
import { RedBlackNode } from "./red_black_node.ts";
export * from "./_comparators.ts";
/**
 * A red-black tree. This is a kind of self-balancing binary search tree.
 * The values are in ascending order by default,
 * using JavaScript's built in comparison operators to sort the values.
 */ export class RedBlackTree extends BinarySearchTree {
    constructor(compare = ascend){
        super(compare);
    }
    static from(collection, options) {
        let result;
        let unmappedValues = [];
        if (collection instanceof RedBlackTree) {
            result = new RedBlackTree(options?.compare ?? collection.compare);
            if (options?.compare || options?.map) {
                unmappedValues = collection;
            } else {
                const nodes = [];
                if (collection.root) {
                    result.root = RedBlackNode.from(collection.root);
                    nodes.push(result.root);
                }
                while(nodes.length){
                    const node = nodes.pop();
                    const left = node.left ? RedBlackNode.from(node.left) : null;
                    const right = node.right ? RedBlackNode.from(node.right) : null;
                    if (left) {
                        left.parent = node;
                        nodes.push(left);
                    }
                    if (right) {
                        right.parent = node;
                        nodes.push(right);
                    }
                }
            }
        } else {
            result = options?.compare ? new RedBlackTree(options.compare) : new RedBlackTree();
            unmappedValues = collection;
        }
        const values = options?.map ? Array.from(unmappedValues, options.map, options.thisArg) : unmappedValues;
        for (const value of values)result.insert(value);
        return result;
    }
    removeFixup(parent, current) {
        while(parent && !current?.red){
            const direction = parent.left === current ? "left" : "right";
            const siblingDirection = direction === "right" ? "left" : "right";
            let sibling = parent[siblingDirection];
            if (sibling?.red) {
                sibling.red = false;
                parent.red = true;
                this.rotateNode(parent, direction);
                sibling = parent[siblingDirection];
            }
            if (sibling) {
                if (!sibling.left?.red && !sibling.right?.red) {
                    sibling.red = true;
                    current = parent;
                    parent = current.parent;
                } else {
                    if (!sibling[siblingDirection]?.red) {
                        sibling[direction].red = false;
                        sibling.red = true;
                        this.rotateNode(sibling, siblingDirection);
                        sibling = parent[siblingDirection];
                    }
                    sibling.red = parent.red;
                    parent.red = false;
                    sibling[siblingDirection].red = false;
                    this.rotateNode(parent, direction);
                    current = this.root;
                    parent = null;
                }
            }
        }
        if (current) current.red = false;
    }
    /**
   * Adds the value to the binary search tree if it does not already exist in it.
   * Returns true if successful.
   */ insert(value) {
        let node = this.insertNode(RedBlackNode, value);
        if (node) {
            while(node.parent?.red){
                let parent = node.parent;
                const parentDirection = parent.directionFromParent();
                const uncleDirection = parentDirection === "right" ? "left" : "right";
                const uncle = parent.parent[uncleDirection] ?? null;
                if (uncle?.red) {
                    parent.red = false;
                    uncle.red = false;
                    parent.parent.red = true;
                    node = parent.parent;
                } else {
                    if (node === parent[uncleDirection]) {
                        node = parent;
                        this.rotateNode(node, parentDirection);
                        parent = node.parent;
                    }
                    parent.red = false;
                    parent.parent.red = true;
                    this.rotateNode(parent.parent, uncleDirection);
                }
            }
            this.root.red = false;
        }
        return !!node;
    }
    /**
   * Removes node value from the binary search tree if found.
   * Returns true if found and removed.
   */ remove(value) {
        const node = this.removeNode(value);
        if (node && !node.red) {
            this.removeFixup(node.parent, node.left ?? node.right);
        }
        return !!node;
    }
}
//# sourceMappingURL=data:application/json;base64,[encoded data, 14056 characters]