/*
文件名:RedBlackTreeClass.nut
路径:Dps_A/BaseClass/RedBlackTreeClass/RedBlackTreeClass.nut
创建日期:2024-09-19	12:42
文件用途:红黑树类
*/
// 红黑树节点类
class RBTreeNode {
    key = null;
    time = null;
    left = null;
    right = null;
    parent = null;
    color = null;
    Info = null;
    constructor(key, func_info) {
        this.key = key;
        this.time = key;
        this.Info = func_info;
        this.left = null;
        this.right = null;
        this.parent = null;
        this.color = "red";
    }

    function _tyoeof() {
        return "RBTreeNode";
    }
}

// 红黑树类
class RedBlackTree {
    nil = null;
    root = null;
    size = 0;

    function _tyoeof() {
        return "RedBlackTree";
    }

    constructor() {
        this.nil = RBTreeNode(null, null);
        this.root = this.nil;
    }

    function insert(key, func_info) {
        local z = RBTreeNode(key, func_info);
        local y = this.nil;
        local x = this.root;
        while (x != this.nil) {
            y = x;
            if (z.key< x.key) {
                x = x.left;
            } else {
                x = x.right;
            }
        }
        z.parent = y;
        if (y == this.nil) {
            this.root = z;
        } else if (z.key< y.key) {
            y.left = z;
        } else {
            y.right = z;
        }
        z.left = this.nil;
        z.right = this.nil;
        z.color = "red";
        this.insertFixup(z);
        this.size++;
    }

    function insertFixup(z) {
        while (z.parent.color == "red") {
            if (z.parent.parent && z.parent == z.parent.parent.left) {
                local y = z.parent.parent.right;
                if (y.color == "red") {
                    z.parent.color = "black";
                    y.color = "black";
                    z.parent.parent.color = "red";
                    z = z.parent.parent;
                } else {
                    if (z == z.parent.right) {
                        z = z.parent;
                        this.leftRotate(z);
                    }
                    z.parent.color = "black";
                    z.parent.parent.color = "red";
                    this.rightRotate(z.parent.parent);
                }
            } else {
                if (z.parent.parent && z.parent.parent.left.color == "red") {
                    z.parent.color = "black";
                    z.parent.parent.left.color = "black";
                    z.parent.parent.color = "red";
                    z = z.parent.parent;
                } else {
                    if (z == z.parent.left) {
                        z = z.parent;
                        this.rightRotate(z);
                    }
                    z.parent.color = "black";
                    if (z.parent.parent) z.parent.parent.color = "red";
                    this.leftRotate(z.parent.parent);
                }
            }
        }
        this.root.color = "black";
    }

    function leftRotate(x) {
        if (!x) return;
        local 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;
    }

    function rightRotate(x) {
        local 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.left) {
            x.parent.left = y;
        } else {
            x.parent.right = y;
        }
        y.right = x;
        x.parent = y;
    }


    function minimum(...) {
        local node = this.root;
        if (vargv.len() > 0) node = vargv[0];
        while (node.left != this.nil) {
            node = node.left;
        }
        return node;
    }

    function transplant(u, v) {
        if (u.parent == this.nil) {
            this.root = v;
        } else if (u == u.parent.left) {
            u.parent.left = v;
        } else {
            u.parent.right = v;
        }
        v.parent = u.parent;
    }

    function deleteFixup(x) {
        while (x != this.root && x.color == "black") {
            if (x == x.parent.left) {
                local w = x.parent.right;
                if (w.color == "red") {
                    w.color = "black";
                    x.parent.color = "red";
                    this.leftRotate(x.parent);
                    w = x.parent.right;
                }
                if (w.left.color == "black" && w.right.color == "black") {
                    w.color = "red";
                    x = x.parent;
                } else {
                    if (w.right.color == "black") {
                        w.left.color = "black";
                        w.color = "red";
                        this.rightRotate(w);
                        w = x.parent.right;
                    }
                    w.color = x.parent.color;
                    x.parent.color = "black";
                    w.right.color = "black";
                    this.leftRotate(x.parent);
                    x = this.root;
                }
            } else {
                local w = x.parent.left;
                if (w.color == "red") {
                    w.color = "black";
                    x.parent.color = "red";
                    this.rightRotate(x.parent);
                    w = x.parent.left;
                }
                if (w.right.color == "black" && w.left.color == "black") {
                    w.color = "red";
                    x = x.parent;
                } else {
                    if (w.left.color == "black") {
                        w.right.color = "black";
                        w.color = "red";
                        this.leftRotate(w);
                        w = x.parent.left;
                    }
                    w.color = x.parent.color;
                    x.parent.color = "black";
                    w.left.color = "black";
                    this.rightRotate(x.parent);
                    x = this.root;
                }
            }
        }
        x.color = "black";
    }

    function deleteNode(z) {
        local y = z;
        local yOriginalColor = y.color;
        local x;
        if (z.left == this.nil) {
            x = z.right;
            this.transplant(z, z.right);
        } else if (z.right == this.nil) {
            x = z.left;
            this.transplant(z, z.left);
        } else {
            y = this.minimum(z.right);
            yOriginalColor = y.color;
            x = y.right;
            if (y.parent == z) {
                x.parent = y;
            } else {
                this.transplant(y, y.right);
                y.right = z.right;
                y.right.parent = y;
            }
            this.transplant(z, y);
            y.left = z.left;
            y.left.parent = y;
            y.color = z.color;
        }
        if (yOriginalColor == "black") {
            this.deleteFixup(x);
        }
        this.size--;
    }

    function inorderTraversal(...) {
        local node = this.root;
        if (vargv.len() > 0) node = vargv[0];
        if (node == this.nil) {
            return;
        }
        this.inorderTraversal(node.left);
        print(node.key + "(" + node.color + ") ");
        this.inorderTraversal(node.right);
    }

    function getSize() {
        return this.size;
    }

    function pop() {
        if (this.size <= 0) return null;
        local z = this.minimum();
        if (z != this.nil) {
            this.deleteNode(z);
            return z;
        }
        return null;
    }

    function GetPop() {
        if (this.size <= 0) return null;
        local z = this.minimum();
        if (z != this.nil) {
            return z;
        }
        return null;
    }
}