! bst.f90
! Input: a sequence of integer pairs, one integer per line. 
!   The first integer of each pair will encode a binary tree operation (0=delete, 1=insert, 2=contains). 
!   The second integer of each pair will be the integer key for the operation. 
!   After all pairs, a single value of -1 will indicate the end of input.  
! Output: For each delete and contains operation, output 0/1 if the given value is not/is currently contained within the binary tree, respectively.  

program bst
    implicit none
    integer :: op, key
    type bt_node
        integer :: key
        type(bt_node), pointer :: left, right
    end type bt_node
    type(bt_node), pointer :: root => null()
    integer :: found

    ! Read the first operation
    read *, op

    ! Process the operations
    do while (op /= -1)
        read *, key
        if (op == 0) then
            ! if the operation is delete, call delete(root, key) and print 1 if the key is found, 0 otherwise
            found = delete_key(root, key)
            write(*, '(I0)') found
        else if (op == 1) then
            ! if the operation is insert, call insert(root, key)
            call insert_key(root, key)
        else if (op == 2) then
            found = contains_key(root, key)
            write(*, '(I0)') found
        end if
        read *, op
    end do

contains

! find_min - Recursive function to find the minimum key in the binary tree

    recursive function find_min(n) result(min_key)
        type(bt_node), pointer :: n
        integer :: min_key

        if (associated(n%left)) then
            min_key = find_min(n%left)
        else
            min_key = n%key
        end if
    end function find_min

! Recursive function to delete a key from the binary tree, returning whether the key was deleted as a 1=deleted, 0=not deleted

    recursive function delete_key(n, del_key) result(deleted)
        type(bt_node), pointer :: n
        integer, intent(in) :: del_key
        integer :: deleted

        if (.not. associated(n)) then
            deleted = 0
        else if (del_key < n%key) then
            deleted = delete_key(n%left, del_key)
        else if (del_key > n%key) then
            deleted = delete_key(n%right, del_key)
        else
            if (associated(n%left) .and. associated(n%right)) then
                n%key = find_min(n%right)
                deleted = delete_key(n%right, n%key)
            else if (associated(n%left)) then
                n => n%left
                deleted = 1
            else if (associated(n%right)) then
                n => n%right
                deleted = 1
            else
                deallocate(n)
                deleted = 1
            end if
        end if
    end function delete_key

! Recursive function to insert a key into the binary tree

    recursive subroutine insert_key(n, new_key)
        type(bt_node), pointer :: n
        integer, intent(in) :: new_key

        if (.not. associated(n)) then
            allocate(n)
            n%key = new_key
            n%left => null()
            n%right => null()
        else if (new_key < n%key) then
            call insert_key(n%left, new_key)
        else 
            call insert_key(n%right, new_key)
        end if
    end subroutine insert_key

! Recursive function to check if a key is contained within the binary tree, returning whether the key was found as a 1=found, 0=not found

    recursive function contains_key(n, target_key) result(contains)
        type(bt_node), pointer, intent(in) :: n
        integer, intent(in) :: target_key
        integer :: contains

        if (.not. associated(n)) then
            contains = 0
        else if (target_key < n%key) then
            contains = contains_key(n%left, target_key)
        else if (target_key > n%key) then
            contains = contains_key(n%right, target_key)
        else
            contains = 1
        end if
    end function contains_key

end program bst
