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

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;
}