! primes_coarrays_nolock.f90 --
!     Determine the first 1000 primes - using coarrays
!
!     Alternative version: image 1 collects all the data
!
!     Example belonging to "Modern Fortran in Practice" by Arjen Markus
!
!     This work is licensed under the Creative Commons Attribution 3.0 Unported License.
!     To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/
!     or send a letter to:
!     Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
!
program primes_coarrays
    implicit none

    integer, dimension(2)                    :: range_priv
    integer, dimension(2), codimension[*]    :: range
    integer, dimension(1000)                 :: prime
    integer                                  :: total_primes
    integer, dimension(100), codimension[*]  :: primes_in_task
    integer, codimension[*]                  :: number_in_task
    logical, codimension[*]                  :: new_results
    logical, codimension[*]                  :: new_task
    logical, codimension[*]                  :: ready

    ready          = .false.
    new_results    = .true.   ! Indicates the image has results available
    new_task       = .false.  ! Indicates a new task has been issued for the image
    number_in_task = 0        ! Number of primes found in task

    range_priv(2) = 0
    total_primes  = 0

    write(*,*) 'Image', this_image(), new_results

    sync all
    write(*,*) 'Image2', this_image(), new_results

    !
    ! Collect the found primes in image 1, create new tasks
    ! for all images
    !
    do while ( .not. ready )
        if ( this_image() == 1 ) then
            call collect_results
            call create_tasks
            sync images(*)
        else
            sync images(1)
        endif

        call get_task
    enddo

    if ( this_image() == 1 ) then
        write(*,*) 'Primes:'
        write(*,'(20i5)') prime
    endif

contains

!
! Subroutine to collect the results from all
! images (run by image 1)
!
subroutine collect_results
    integer :: i
    integer :: np
    integer :: maxindex

    do i = 1,num_images()
        write(*,*) 'Examine', i, new_results[i]
        sync images(i)
        if ( new_results[i] ) then
            np       = number_in_task[i]

            maxindex = min( size(prime) - total_primes, np )
            prime(total_primes+1:total_primes+maxindex) = &
                primes_in_task(1:maxindex)[i]

            write(*,*) 'Got primes:', i, np
            total_primes = total_primes + maxindex
            write(*,*) 'Total:', total_primes
        endif
    enddo

    ready = total_primes >= size(prime)

    if ( ready ) then
        do i = 1,num_images()
            ready[i] = .true.
        enddo
    endif
end subroutine collect_results

!
! Subroutine to post new tasks (consisting of a
! range of integers in which to look for primes)
!
! Loop over the images to see which one wants a
! new task
!
subroutine create_tasks
    integer :: i

    do i = 1,num_images()
        if ( new_results[i] ) then
            new_results[i] = .false.
            range_priv(1)  = range_priv(2) + 1
            range_priv(2)  = range_priv(2) + 100

            range(:)[i]    = range_priv(:)
            new_task[i]    = .true.

            write(*,*) 'Assign', i, range_priv
        endif
    enddo

end subroutine create_tasks

!
! Subroutine to get a task and search for
! primes inside the new range
!
subroutine get_task

    integer                 :: lower
    integer                 :: upper
    logical                 :: isprime
    integer                 :: np
    integer                 :: i
    integer                 :: j
    integer                 :: residue

    if ( new_task ) then
        np = 0
        new_task = .false.
        lower    = range(1)
        upper    = range(2)

        !
        ! Determine what primes we have in this range
        !
        write(*,*) 'Range: ',lower, upper, this_image()
        do i = lower,upper
            isprime = .true.
            do j = 2,int(sqrt(real(i)))
                residue = mod(i,j)
                if ( residue == 0 ) then
                    isprime = .false.
                    exit
                endif
            enddo
            if ( isprime ) then
                np = np + 1
                primes_in_task(np) = i
            endif
        enddo
        write(*,*) this_image(), ' found:', np, ' primes'
        write(*,'(5x,10i5)' ) primes_in_task(1:np)

        number_in_task = np
        new_results    = .true.
    endif

end subroutine get_task

end program primes_coarrays
