#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
 
struct TreeNode
{
    int data;
    TreeNode* left;
    TreeNode* right;
};
 
 
TreeNode* createNode(int data)
{
    TreeNode *temp = (TreeNode *)malloc(sizeof(TreeNode));
    temp->data = data;
    temp->left = temp->right = NULL;
    return temp;
}
/**
TreeNode* test(TreeNode* root)
{
    root = createNode(5);
    printf("[From TEST] %d\n", (root)->data);
    return root;
}
**/
 
 
TreeNode* insertion(TreeNode *root, int key)
{
    if(root==NULL)
    {
        root = createNode(key);
        return root;
    }
    else
    {
        if(key>root->data)
        {
            root->right = insertion(root->right, key);
        }
        else if(key<root->data)
        {
            root->left = insertion(root->left, key);
        }
        return root;
    }
}
 
bool search_BST(TreeNode* root, int key)
{
    if(root==NULL)
    {
        return false;
    }
    else
    {
        if(root->data == key) return true;
        else if(key>root->data)
        {
            bool friend_answer = search_BST(root->right, key);
            return friend_answer;
        }
        else
        {
            bool friend_answer = search_BST(root->left, key);
            return friend_answer;
        }
    }
}
 
void inorder(TreeNode* root)
{
    if(root==NULL) return;
 
    inorder(root->left);
 
    printf("%d ", root->data);
 
    inorder(root->right);
}
 
int find_minimum(TreeNode* root)
{
    if(root==NULL)
    {
        return -1;
    }
    else if(root->left==NULL)
        return root->data;
    else
    {
        int answer = find_minimum(root->left);
        return answer;
    }
}
 
 
TreeNode* find_minimum_iterative(TreeNode* root)
{
    if(root==NULL)
    {
        return NULL;
    }
 
    TreeNode* temp = root;
    while(temp->left!=NULL)
    {
        temp = temp->left;
    }
    return temp;
}
 
int find_maximum(TreeNode* root)
{
    if(root==NULL)
    {
        return -1;
    }
    else if(root->right==NULL)
        return root->data;
    else
    {
        int answer = find_maximum(root->right);
        return answer;
    }
}
 
TreeNode* find_maximum_iterative(TreeNode* root)
{
    if(root==NULL)
    {
        return NULL;
    }
 
    TreeNode* temp = root;
    while(temp->right!=NULL)
    {
        temp = temp->right;
    }
    return temp;
}
 
void printTree(TreeNode* root, int space = 0)
{
    if (root == NULL)
        return;
 
    // Increase distance between levels
    int COUNT = 5;
    space += COUNT;
 
    // Print right child first
    printTree(root->right, space);
 
    // Print current node after space count
    printf("\n");
    for (int i = COUNT; i < space; i++)
        printf(" ");
    printf("%d\n", root->data);
 
    // Print left child
    printTree(root->left, space);
}
 
TreeNode* delete_BST(TreeNode* root, int key)
{
    if (root == NULL)
    {
        return root;
    }
 
    if (key < root->data)
    {
        root->left = delete_BST(root->left, key);
    }
    else if (key > root->data)
    {
        root->right = delete_BST(root->right, key);
    }
    else
    {
        if (root->left == NULL)
        {
            TreeNode* temp = root->right;
            free(root);
            return temp;
        }
        else if (root->right == NULL)
        {
            TreeNode* temp = root->left;
            free(root);
            return temp;
        }
 
        TreeNode* temp = find_minimum_iterative(root->right);
        root->data = temp->data;
        root->right = delete_BST(root->right, temp->data);
    }
    return root;
}
 
 
 
int main()
{
 
    TreeNode* root = NULL;
 
    root = insertion(root, 15);
    root = insertion(root, 20);
    root = insertion(root, 10);
    root = insertion(root, 25);
    root = insertion(root, 18);
    root = insertion(root, 13);
    root = insertion(root, 5);
 
    /// inorder(root);
 
    printTree(root);
 
    printf("Maximum Value: %d\n", find_maximum(root));
    printf("Minimum Value: %d\n", find_minimum(root));
 
    printf("Root Immediate Previous: %d\n", find_maximum(root->left));
    printf("Root Immediate Next: %d\n", find_minimum(root->right));
 
 
    ///Deleting 5
    root = delete_BST(root, 5);
    printTree(root);
 
    return 0;
}