#include "avltree.h"
#include <stdint.h>
#include <stdio.h>

// #define AVL_DEBUG

#ifdef AVL_DEBUG
#define avl_debug(...) printf(__VA_ARGS__)
#else
#define avl_debug(...)
#endif

static void __avl_rotate_right(struct avl_node *node, struct avl_root *root);
static void __avl_rotate_left(struct avl_node *node, struct avl_root *root);

static int __avl_balance_right(struct avl_node *node, struct avl_root *root);
static int __avl_balance_left(struct avl_node *node, struct avl_root *root);

static int __left_hand_insert_track_back(struct avl_node *node, struct avl_root *root);
static int __right_hand_insert_track_back(struct avl_node *node, struct avl_root *root);

#define __left_hand_delete_track_back(node, root)  __right_hand_insert_track_back(node, root)
#define __right_hand_delete_track_back(node, root) __left_hand_insert_track_back(node, root)

/**
 * @brief    __avl_rotate_right
 *           对 node 节点进行单右旋处理
 * @param    node        二叉树节点
 * @param    root        二叉树根
 * @return
 */
static void __avl_rotate_right(struct avl_node *node, struct avl_root *root)
{
    // 对以*node为根的二叉树作右旋转处理，处理之后node指向新的树根结点
    // 即旋转处理之前的左子树的根结点
    struct avl_node *left   = node->avl_left;
    struct avl_node *parent = avl_parent(node);

    if ((node->avl_left = left->avl_right))
        avl_set_parent(left->avl_right, node);

    left->avl_right = node;

    avl_set_parent(left, parent);

    if (parent)
    {
        if (node == parent->avl_right)
            parent->avl_right = left;
        else
            parent->avl_left = left;
    }
    else
        root->avl_node = left;

    avl_set_parent(node, left);
}

/**
 * @brief    __avl_rotate_left
 *           对 node 节点进行单左旋处理
 * @param    node        二叉树节点
 * @param    root        二叉树根
 * @return
 */
static void __avl_rotate_left(struct avl_node *node, struct avl_root *root)
{
    struct avl_node *right  = node->avl_right;
    struct avl_node *parent = avl_parent(node);

    if ((node->avl_right = right->avl_left))
        avl_set_parent(right->avl_left, node);

    right->avl_left = node;

    avl_set_parent(right, parent);

    if (parent)
    {
        if (node == parent->avl_left)
            parent->avl_left = right;
        else
            parent->avl_right = right;
    }
    else
        root->avl_node = right;

    avl_set_parent(node, right);
}

/**
 * @brief    __avl_balance_left
 *           当 node 节点左子树高于右子树， 对 node 节点进行左平衡处理并更新平衡因子
 * @param    node        二叉树节点
 * @param    root        二叉树根
 * @return   对于原 node 所在位置，经过平衡处理使树的高度降低了返回 -1，否则返回0
 */
static int __avl_balance_left(struct avl_node *node, struct avl_root *root)
{
    int              retl = 0;
    int              left_right_child_scale;
    struct avl_node *left_child = node->avl_left;
    struct avl_node *left_left_child;
    struct avl_node *left_right_child;

    if (left_child)
    {
        left_left_child  = left_child->avl_left;
        left_right_child = left_child->avl_right;

        switch (avl_scale(left_child))
        {
        case AVL_BALANCED: // 只有在删除的时候会出现这种情况，情况非常复杂，需小心处理
            left_right_child_scale = avl_scale(left_right_child);
            __avl_rotate_left(node->avl_left, root); // 对*node的左子树作左平衡处理
            __avl_rotate_right(node, root);          // 对*node作右平衡处理
            avl_set_tilt_left(left_child);
            avl_set_tilt_left(left_right_child);

            if (left_right_child_scale == AVL_BALANCED)
                avl_set_balanced(node);
            else if (left_right_child_scale == AVL_TILT_LEFT)
                avl_set_tilt_right(node);
            else
            {
                int left_left_child_scale = avl_scale(left_left_child);
                avl_set_balanced(node);
                retl = __avl_balance_left(left_child, root); // 这种情况需递归,并需要根据递归结果更新平衡因子
                if ((retl < 0) || (left_left_child_scale != AVL_BALANCED))
                    avl_set_balanced(left_right_child);
            }
            avl_debug("L_R\r\n");
            break;

        case AVL_TILT_LEFT:
            __avl_rotate_right(node, root);
            avl_set_balanced(node);
            avl_set_balanced(left_child);
            retl = -1; // 高度变低了
            avl_debug("R\r\n");
            break;

        case AVL_TILT_RIGHT:
            __avl_rotate_left(node->avl_left, root); // 对*node的左子树作左平衡处理
            __avl_rotate_right(node, root);          // 对*node作右平衡处理

            switch (avl_scale(left_right_child))
            {
            case AVL_BALANCED:
                avl_set_balanced(node);
                avl_set_balanced(left_child);
                break;
            case AVL_TILT_RIGHT:
                avl_set_balanced(node);
                avl_set_tilt_left(left_child);
                break;
            case AVL_TILT_LEFT:
                avl_set_balanced(left_child);
                avl_set_tilt_right(node);
                break;
            }

            avl_set_balanced(left_right_child);
            retl = -1; // 高度变低

            avl_debug("L_R\r\n");
            break;
        }
    }

    return retl;
}

/**
 * @brief    __avl_balance_right
 *           当 node 节点右子树高于左子树， 对 node 节点进行左平衡处理并更新平衡因子
 * @param    node        二叉树节点
 * @param    root        二叉树根
 * @return   对于原 node 所在树的位置，经过平衡处理使树的高度降低了返回 -1，否则返回0
 */
static int __avl_balance_right(struct avl_node *node, struct avl_root *root)
{
    int              ret = 0;
    int              right_left_child_scale;
    struct avl_node *right_child       = node->avl_right;
    struct avl_node *right_left_child  = right_child->avl_left;
    struct avl_node *right_right_child = right_child->avl_right;

    if (right_child)
    {
        switch (avl_scale(right_child))
        {
        case AVL_BALANCED: // 删除的时候会出现这种情况，需要特别注意
            right_left_child_scale = avl_scale(right_left_child);

            __avl_rotate_right(node->avl_right, root);
            __avl_rotate_left(node, root);
            avl_set_tilt_right(right_left_child);
            avl_set_tilt_right(right_child);

            if (right_left_child_scale == AVL_BALANCED)
                avl_set_balanced(node);
            else if (right_left_child_scale == AVL_TILT_RIGHT)
                avl_set_tilt_left(node);
            else
            {
                int right_right_child_scale = avl_scale(right_right_child);
                avl_set_balanced(node);
                ret = __avl_balance_right(right_child, root); // 需递归一次
                if ((ret < 0) || (right_right_child_scale != AVL_BALANCED))
                    avl_set_balanced(right_left_child);
            }
            avl_debug("R_L\r\n");
            break;

        case AVL_TILT_RIGHT:
            avl_debug("L\r\n");
            __avl_rotate_left(node, root);
            avl_set_balanced(node);
            avl_set_balanced(right_child);
            ret = -1; // 高度变低了//
            break;

        case AVL_TILT_LEFT:
            __avl_rotate_right(node->avl_right, root);
            __avl_rotate_left(node, root);

            avl_debug("R_L\r\n");
            switch (avl_scale(right_left_child)) // 旋转后要更新平衡因子
            {
            case AVL_TILT_LEFT:
                avl_set_tilt_right(right_child);
                avl_set_balanced(node);
                break;
            case AVL_BALANCED:
                avl_set_balanced(node);
                avl_set_balanced(right_child);
                break;
            case AVL_TILT_RIGHT:
                avl_set_balanced(right_child);
                avl_set_tilt_left(node);
                break;
            }

            avl_set_balanced(right_left_child);
            ret = -1; //
            break;
        }
    }

    return ret;
}

/**
 * @brief    __left_hand_insert_track_back
 *           在 node 节点的左子树进行了插入，更新平衡因子，如失衡则作平衡处理
 * @param    node        二叉树节点
 * @param    root        二叉树根
 * @return   对于原 node 所在树的位置，经过平衡处理使树的高度降低了返回 -1，否则返回0
 */
static int __left_hand_insert_track_back(struct avl_node *node, struct avl_root *root)
{
    switch (avl_scale(node))
    {
    case AVL_BALANCED:
        avl_set_tilt_left(node);
        return 0;

    case AVL_TILT_RIGHT:
        avl_set_balanced(node);
        return -1;

    case AVL_TILT_LEFT:
        return __avl_balance_left(node, root);
    }

    return 0;
}

/**
 * @brief    __left_hand_insert_track_back
 *           在 node 节点的右子树进行了插入，更新平衡因子，如失衡则作平衡处理
 * @param    node        二叉树节点
 * @param    root        二叉树根
 * @return   对于原 node 所在树的位置，插入并平衡后高度降低了返回 -1，否则返回0
 */
static int __right_hand_insert_track_back(struct avl_node *node, struct avl_root *root)
{
    switch (avl_scale(node))
    {
    case AVL_BALANCED:
        avl_set_tilt_right(node); // 父节点右倾
        return 0;                 // 以 node 为根的树高度被改变，但未失衡

    case AVL_TILT_LEFT:
        avl_set_balanced(node); // 父节点平衡
        return -1;              // 以 node 为根的树高度不改变

    case AVL_TILT_RIGHT:                        // 以 node 为根的树已失衡，作平衡处理
        return __avl_balance_right(node, root); //
    }

    return 0;
}

void avl_insert(
    struct avl_root  *root,
    struct avl_node  *insertnode,
    struct avl_node  *parent,
    struct avl_node **avl_link)
{
    int taller = 1;

    struct avl_node *gparent = NULL;

    uint8_t parent_gparent_path = 0;
    uint8_t backtrack_path      = 0;

    insertnode->avl_parent = (unsigned long)parent;
    insertnode->avl_left = insertnode->avl_right = NULL;

    *avl_link = insertnode;

    if (root->avl_node == insertnode)
        return;

    if (AVL_BALANCED != avl_scale(parent))
    {
        avl_set_balanced(parent); // 父节点平衡
        return;                   // 树没长高返回
    }

    backtrack_path = (insertnode == parent->avl_left) ? AVL_TILT_LEFT : AVL_TILT_RIGHT;

    // 树长高了，需要回溯平衡
    while (taller && parent)
    {
        // 回溯平衡过程会改变树的结构，先记录祖父节点和对应的回溯路径方向
        if ((gparent = avl_parent(parent))) // 先赋值再判断
            parent_gparent_path = (parent == gparent->avl_right) ? AVL_TILT_RIGHT : AVL_TILT_LEFT;

        if (backtrack_path == AVL_TILT_RIGHT)
            taller += __right_hand_insert_track_back(parent, root);
        else
            taller += __left_hand_insert_track_back(parent, root);

        backtrack_path = parent_gparent_path; // 回溯
        parent         = gparent;
    }
}

#if 1
void avl_delete(struct avl_root *root, struct avl_node *node)
{
    struct avl_node *child, *parent;
    struct avl_node *gparent = NULL;
    int              lower   = 1;

    uint8_t parent_gparent_path = 0;
    uint8_t backtrack_path      = 0;

    if (!node->avl_left) // 如果被删节点不存在左子树
    {
        child = node->avl_right; // 把右子树接入父节点中

        parent = avl_parent(node);

        if (child)
            avl_set_parent(child, parent);

        if (parent)
        {
            if (parent->avl_left == node)
            {
                parent->avl_left = child;
                backtrack_path   = AVL_TILT_LEFT;
            }
            else
            {
                parent->avl_right = child;
                backtrack_path    = AVL_TILT_RIGHT;
            }
        }
        else
        {
            root->avl_node = child;
            if (child)
                avl_set_balanced(child);
            return;
        }
    }
    else if (!node->avl_right) // 如果被删节点存在左子树，不存在右子树
    {
        child = node->avl_left;

        parent = avl_parent(node);

        avl_set_parent(child, parent);

        if (parent)
        {
            if (parent->avl_left == node)
            {
                parent->avl_left = child;
                backtrack_path   = AVL_TILT_LEFT;
            }
            else
            {
                parent->avl_right = child;
                backtrack_path    = AVL_TILT_RIGHT;
            }
        }
        else
        {
            root->avl_node = child;
            if (child)
                avl_set_balanced(child);
            return;
        }
    }
    else // 被删节点即存在左子树，也存在右子树
    {
        struct avl_node *old = node, *left;

        node = node->avl_right;

        while ((left = node->avl_left) != NULL)
            node = left; // 找到右子树下最小的替代点

        if (avl_parent(old)) // 旧点所在父节点
        {
            if (avl_parent(old)->avl_left == old)
                avl_parent(old)->avl_left = node;
            else
                avl_parent(old)->avl_right = node;
        }
        else
            root->avl_node = node;

        child  = node->avl_right;  // 最小的替代点的右节点
        parent = avl_parent(node); // 最小的替代点的父节点

        if (parent == old) // 要删除的节点的右子树没有左子树，替代点(1)没有右节点,(2)存在一个右节点
        {
            backtrack_path = AVL_TILT_RIGHT;

            parent           = node;
            node->avl_parent = old->avl_parent;
            node->avl_left   = old->avl_left;
            avl_set_parent(old->avl_left, node);
        }
        else // 要删除的节点的右子树有左子树
        {
            backtrack_path = AVL_TILT_LEFT;

            parent->avl_left = child; // 最小的替代点的右节点的父节点
            node->avl_right  = old->avl_right;
            avl_set_parent(old->avl_right, node);

            node->avl_parent = old->avl_parent;
            node->avl_left   = old->avl_left;
            avl_set_parent(old->avl_left, node);

            if (child)
                avl_set_parent(child, parent); // 要删除的节点的右子树的左子树末尾点存在右节点
        }
    }

    // 树低了，需要回溯平衡，直到回溯到根节点
    while (lower && parent)
    {
        if ((gparent = avl_parent(parent))) //(parent && (gparent = avl_parent(parent)))//先赋值再判断
            parent_gparent_path = (parent == gparent->avl_right) ? AVL_TILT_RIGHT : AVL_TILT_LEFT;

        if (backtrack_path == AVL_TILT_RIGHT) // 经过回溯调整会改变树的结构，所以先记录 gparent 和回溯路径
            lower = __right_hand_delete_track_back(parent, root);
        else
            lower = __left_hand_delete_track_back(parent, root);

        backtrack_path = parent_gparent_path;
        parent         = gparent;
    }
}

#endif

/*
 * This function returns the first node (in sort oright_left_childer) of the tree.
 */
struct avl_node *avl_first(const struct avl_root *root)
{
    struct avl_node *n;

    n = root->avl_node;
    if (!n)
        return NULL;
    while (n->avl_left)
        n = n->avl_left;
    return n;
}

struct avl_node *avl_last(const struct avl_root *root)
{
    struct avl_node *n;

    n = root->avl_node;
    if (!n)
        return NULL;
    while (n->avl_right)
        n = n->avl_right;
    return n;
}

struct avl_node *avl_next(const struct avl_node *node)
{
    struct avl_node *parent;

    if (avl_parent(node) == node)
        return NULL;

    /* If we have a right-hand child, go down and then left as far
       as we can. */
    if (node->avl_right)
    {
        node = node->avl_right;
        while (node->avl_left)
            node = node->avl_left;
        return (struct avl_node *)node;
    }

    /* No right-hand children.  Everything down and left is
       smaller than us, so any 'next' node must be in the general
       direction of our parent. Go up the tree; any time the
       ancestor is a right-hand child of its parent, keep going
       up. First time it's a left-hand child of its parent, said
       parent is our 'next' node. */
    while ((parent = avl_parent(node)) && node == parent->avl_right)
        node = parent;

    return parent;
}

struct avl_node *avl_prev(const struct avl_node *node)
{
    struct avl_node *parent;

    if (avl_parent(node) == node)
        return NULL;

    /* If we have a left-hand child, go down and then right as far
       as we can. */
    if (node->avl_left)
    {
        node = node->avl_left;
        while (node->avl_right)
            node = node->avl_right;
        return (struct avl_node *)node;
    }

    /* No left-hand children. Go up till we find an ancestor which
       is a right-hand child of its parent */
    while ((parent = avl_parent(node)) && node == parent->avl_left)
        node = parent;

    return parent;
}

void avl_replace_node(struct avl_node *victim, struct avl_node *new,
                      struct avl_root *root)
{
    struct avl_node *parent = avl_parent(victim);

    /* Set the surrounding nodes to point to the replacement */
    if (parent)
    {
        if (victim == parent->avl_left)
            parent->avl_left = new;
        else
            parent->avl_right = new;
    }
    else
    {
        root->avl_node = new;
    }
    if (victim->avl_left)
        avl_set_parent(victim->avl_left, new);
    if (victim->avl_right)
        avl_set_parent(victim->avl_right, new);

    /* Copy the pointers/colour from the victim to the replacement */
    *new = *victim;
}
