! +++++++++++++++++++++++++++++++++
! DON'T ADD ANYTHING TO THIS MODULE
! +++++++++++++++++++++++++++++++++
module module_bigdft_mpi
  use wrapper_MPI

  implicit none

  public

  type(mpi_environment), save :: bigdft_mpi !< Contains all data needed for MPI processes
  integer, parameter :: mpidtypd = MPI_DOUBLE_PRECISION
  integer, parameter :: mpidtypw = MPI_DOUBLE_PRECISION

contains

  subroutine bigdft_mpi_init(mpi_info, mpi_groupsize, ierr)
    implicit none

    integer, dimension(4), intent(out) :: mpi_info
    integer, intent(in) :: mpi_groupsize
    integer, intent(out) :: ierr
    !local variables
    integer :: iproc,nproc,ngroup_size

    call wmpi_init_thread(ierr)
    if (ierr /= MPI_SUCCESS) return

    !here wrappers for MPI should be used
    call MPI_COMM_RANK(MPI_COMM_WORLD,iproc,ierr)
    call MPI_COMM_SIZE(MPI_COMM_WORLD,nproc,ierr)
    if (ierr /= MPI_SUCCESS) return

    !if the taskgroup size is not a divisor of nproc do not create taskgroups
    ngroup_size=nproc
    if (nproc >1 .and. mpi_groupsize > 0 .and. mpi_groupsize < nproc) then
       !nest this check because if mpi_groupsize is zero mod(X,0) will crash
       if (mod(nproc,mpi_groupsize)==0) then
          ngroup_size=mpi_groupsize
       end if
    end if

    call mpi_environment_set(bigdft_mpi,iproc,nproc,MPI_COMM_WORLD,ngroup_size)

    !final values
    mpi_info(1)=bigdft_mpi%iproc
    mpi_info(2)=bigdft_mpi%nproc
    mpi_info(3)=bigdft_mpi%igroup
    mpi_info(4)=bigdft_mpi%ngroup
  end subroutine bigdft_mpi_init

  subroutine bigdft_mpi_release()
    implicit none
    
    !here a routine to free the environment should be called
    call fmpi_barrier() !over comm world
    !call MPI_BARRIER(MPI_COMM_WORLD,ierr)
    call release_mpi_environment(bigdft_mpi)
    !wait all processes before finalisation
    call fmpi_barrier() !over comm world
    call mpifinalize()
  end subroutine bigdft_mpi_release

end module module_bigdft_mpi
