/***************************************************

Binary Search Tree (BST) Implementation

***************************************************/

class CBST
{
        CBST    *left;
        CBST    *right;
        I64              value;
};

CBST *BSTInit()
{
        return CAlloc(sizeof(CBST));
}

U0 BSTAdd(CBST *node, CBST *tree)
{ // using temp and last allows avoiding recursion and non-growing stack issues.
        CBST *temp_tree = tree;
        CBST *last_tree = temp_tree;

        while (temp_tree)
        { // loop ends when temp_tree hits a NULL node.
                if (node->value < temp_tree->value)
                { // if node smaller, go left
                        last_tree = temp_tree;
                        temp_tree = temp_tree->left;
                }
                else
                { // if node equal or larger, go right
                        last_tree = temp_tree;
                        temp_tree = temp_tree->right;
                }
        }
        // once while loop ends, this results in last_tree
        // being the resulting tree to store the node inside of.

        // recompute the direction and set.
        if (node->value < last_tree->value)// if node smaller, go left
                last_tree->left = node;
        else // if node equal or larger, go right
                last_tree->right = node;
}

CBST *BSTParamAdd(I64 value, CBST *tree)
{ // add a node using params, return pointer to the node
        CBST *result = BSTInit;

        result->value = value;

        BSTAdd(result, tree);

        return result;
}

CBST *BSTParamInit(I64 value)
{
        CBST *result = BSTInit;

        result->value = value;

        return result;
}

CBST *BSTFind(I64 value, CBST *tree)
{
        CBST *temp_tree = tree;

        while (temp_tree)
        {
                if (value < temp_tree->value) // if value smaller, go left
                        temp_tree = temp_tree->left;
                else if (value > temp_tree->value) // if value larger, go right
                        temp_tree = temp_tree->right;
                else // if value equal, match found.
                        break;
        }
        return temp_tree; // ! NULL if not found.
}

CBST *BSTPop(I64 value, CBST *tree)
{ // mimics TreeNodeFind. pops whole sub-tree, original tree loses whole branch.
        CBST    *parent_tree    = tree;
        CBST    *temp_tree              = parent_tree;
        Bool     is_left                = FALSE;
        Bool     is_right               = FALSE;

        while (temp_tree)
        {
                if (value < temp_tree->value)
                {
                        parent_tree     = temp_tree;
                        temp_tree       = temp_tree->left;
                        is_right        = FALSE;
                        is_left         = TRUE;
                }
                else if (value > temp_tree->value)
                {
                        parent_tree     = temp_tree;
                        temp_tree       = temp_tree->right;
                        is_right        = TRUE;
                        is_left         = FALSE;
                }
                else // if value equal, match found.
                        break;  
        }

        if (temp_tree)
        { //if we found it, clear its parents link to the node
                if (is_left)
                {
                        parent_tree->left = NULL;
                }
                else if (is_right)
                {
                        parent_tree->right = NULL;
                }
        }

        return temp_tree; // NULL if not found.
}

CBST *BSTSinglePop(I64 value, CBST *tree)
{       // pop a tree off, then add back in its sub-trees to main tree.
        // original node sub-trees are cleared.

        CBST *node      = BSTPop(value, tree);
        CBST *left      = node->left;
        CBST *right     = node->right;

        if (node)
        {
                if (left)
                { // if node has left tree, add the tree
                        BSTAdd(left, tree);
                        node->left = NULL;
                }
                if (right)
                { // if node has right tree, add the tree.
                        BSTAdd(right, tree);
                        node->right = NULL;
                }
        }

        return node;
}