program ba

    use omp_lib
    implicit none

    integer(8), parameter :: NUM_ACCOUNTS = 2
    integer(8), parameter :: NUM_TRANSACTION = 10
    integer(8), parameter :: INIT_BALANCE = 0
    integer(8), dimension(0:NUM_TRANSACTION - 1), parameter :: transaction = (/&
    &               10, 20, 30, -40, -50, 80, -10, -50, 100, 90  &
    &             /)
    integer(8), dimension(0:NUM_ACCOUNTS - 1)   :: balance = (INIT_BALANCE, INIT_BALANCE)
    integer(8), dimension(0:NUM_ACCOUNTS - 1)   :: balance_ser = (INIT_BALANCE, INIT_BALANCE)

    integer(8)            :: i
    double precision      :: start_time, final_time


    ! This part of the code is run in serial to get the correct result.
    ! We will use this result to check with our multithreaded solution.
    ! even indexed (including 0) transaction goes to account 0,
    ! odd indexed transaction goes to account 1

    do i = 0, NUM_TRANSACTION - 1
        balance_ser(mod(i, 2)) = balance_ser(mod(i, 2)) + transaction(i)
    end do

    start_time = omp_get_wtime()

    ! Parallelized version
    ! @TODO: parallelize this account balance update part.
    ! Make sure the the upadate does not have race condition
    do i = 0, NUM_TRANSACTION - 1
        balance(mod(i, 2)) = balance(mod(i, 2)) + transaction(i)
    end do

    final_time = omp_get_wtime() - start_time

    write (*, '(A,f14.10)') 'Total time:  ', final_time
    write (*, *) 'Final account balance is following...'
    do i = 0, NUM_ACCOUNTS - 1
        write (*, '(A,I4,A,I4,A,I4)') 'Account No. =', i,  &
        ', actual balance =', balance(i), &
        ', correct balance should be =', balance_ser(i)
    end do

end program ba
