import java.util.Scanner;

// Node class representing each element in the Binary Search Tree (BST)
class Node {
    int value;
    Node left, right;

    // Constructor to initialize a node with a given value
    public Node(int item) {
        value = item;
        left = right = null;
    }
}

// BinarySearchTree class that implements the BST operations
class BinarySearchTree {
    Node root;

    // Method to create a balanced BST from a sorted array
    public void createBalancedBST(int[] sortedValues) {
        root = buildBalancedBST(sortedValues, 0, sortedValues.length - 1);
    }

    // Helper method to recursively build a balanced BST
    private Node buildBalancedBST(int[] arr, int start, int end) {
        if (start > end)
            return null;

        int mid = (start + end) / 2; // Find the middle index
        Node node = new Node(arr[mid]); // Create a new node with the middle value

        // Recursively build left and right subtrees
        node.left = buildBalancedBST(arr, start, mid - 1);
        node.right = buildBalancedBST(arr, mid + 1, end);

        return node;
    }

    // Method to insert a new value into the BST
    public void insert(int value) {
        root = insertNode(root, value);
    }

    // Helper method to recursively insert a new value
    private Node insertNode(Node root, int value) {
        if (root == null)
            return new Node(value);

        if (value < root.value)
            root.left = insertNode(root.left, value);
        else if (value > root.value)
            root.right = insertNode(root.right, value);

        return root;
    }

    // Method to delete a value from the BST
    public void delete(int value) {
        root = deleteNode(root, value);
    }

    // Helper method to recursively delete a value
    private Node deleteNode(Node root, int value) {
        if (root == null)
            return null;

        if (value < root.value)
            root.left = deleteNode(root.left, value);
        else if (value > root.value)
            root.right = deleteNode(root.right, value);
        else {
            // If the node to delete has no children or one child
            if (root.left == null)
                return root.right;
            else if (root.right == null)
                return root.left;

            // If the node has two children, replace with the minimum value in the right subtree
            root.value = minValue(root.right);
            root.right = deleteNode(root.right, root.value);
        }

        return root;
    }

    private int minValue(Node root) {
        int min = root.value;
        while (root.left != null) {
            min = root.left.value;
            root = root.left;
        }
        return min;
    }

    // Method to print the BST in InOrder traversal (Left -> Root -> Right)
    public void printInOrder() {
        System.out.print("InOrder: ");
        inOrder(root);
        System.out.println();
    }

    // Method to print the BST in PreOrder traversal (Root -> Left -> Right)
    public void printPreOrder() {
        System.out.print("PreOrder: ");
        preOrder(root);
        System.out.println();
    }

    // Method to print the BST in PostOrder traversal (Left -> Right -> Root)
    public void printPostOrder() {
        System.out.print("PostOrder: ");
        postOrder(root);
        System.out.println();
    }

    // Helper method for InOrder traversal
    private void inOrder(Node root) {
        if (root != null) {
            inOrder(root.left);
            System.out.print(root.value + " ");
            inOrder(root.right);
        }
    }

    // Helper method for PreOrder traversal
    private void preOrder(Node root) {
        if (root != null) {
            System.out.print(root.value + " ");
            preOrder(root.left);
            preOrder(root.right);
        }
    }

    // Helper method for PostOrder traversal
    private void postOrder(Node root) {
        if (root != null) {
            postOrder(root.left);
            postOrder(root.right);
            System.out.print(root.value + " ");
        }
    }
}

// Main application class to run the BST program
public class BinarySearchTreeApp {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        BinarySearchTree bst = new BinarySearchTree();

        while (true) {
            System.out.println("\n--- Binary Search Tree Menu ---");
            System.out.println("1. Create a binary search tree");
            System.out.println("2. Add a node");
            System.out.println("3. Delete a node");
            System.out.println("4. Print nodes by InOrder");
            System.out.println("5. Print nodes by PreOrder");
            System.out.println("6. Print nodes by PostOrder");
            System.out.println("7. Exit program");
            System.out.print("Enter your choice: ");

            int choice = -1;
            try {
                choice = Integer.parseInt(scanner.nextLine());
            } catch (Exception ignored) {
            }

            switch (choice) {
                case 1:
                    // Create a balanced BST from a sorted array
                    int[] data = {1, 2, 3, 4, 5, 6, 7};
                    bst.createBalancedBST(data);
                    System.out.println("Binary search tree created.");
                    break;

                case 2:
                    // Insert a new node into the BST
                    System.out.print("Enter value to insert: ");
                    int valueToInsert = Integer.parseInt(scanner.nextLine());
                    bst.insert(valueToInsert);
                    System.out.println("Node inserted.");
                    break;

                case 3:
                    // Delete a node from the BST
                    System.out.print("Enter value to delete: ");
                    int valueToDelete = Integer.parseInt(scanner.nextLine());
                    bst.delete(valueToDelete);
                    System.out.println("Node deleted (if it existed).");
                    break;

                case 4:
                    // Print the BST in InOrder traversal
                    bst.printInOrder();
                    break;

                case 5:
                    // Print the BST in PreOrder traversal
                    bst.printPreOrder();
                    break;

                case 6:
                    // Print the BST in PostOrder traversal
                    bst.printPostOrder();
                    break;

                case 7:
                    // Exit the program
                    System.out.println("Exiting program.");
                    scanner.close();
                    return;

                default:
                    System.out.println("Invalid choice. Please try again.");
            }
        }
    }
}
