MODULE transfert_mod
#ifdef CPP_USING_MPI

#if defined(CPP_USING_MPI_NEW)
#warning("Using new transfert_mpi (not default, not working with req_z1_scal)")
   ! transfert_mpi using manual pack/unpack (default)
   USE transfert_mpi_mod, ONLY: t_message, t_request, &
                                req_i1, req_e1_scal, req_e1_vect, &
                                req_i0, req_e0_scal, req_e0_vect, &
                                req_z1_scal, &
                                init_transfert, &
                                init_message, &
                                finalize_message, &
                                send_message, &
                                wait_message, &
                                test_message

#else
   use transfert_mpi_legacy_mod, only: t_message, t_request, &
                                       req_i1, req_e1_scal, req_e1_vect, &
                                       req_i0, req_e0_scal, req_e0_vect, &
                                       req_z1_scal, &
                                       init_transfert, &
                                       init_message => init_message_mpi, &
                                       finalize_message => finalize_message_mpi, &
                                       send_message => send_message_mpi, &
                                       wait_message => wait_message_mpi, &
                                       test_message => test_message_mpi
#endif
#else
#warning("Using transfert_seq (unmaintained)")
   use transfert_mpi_legacy_mod, only: t_message, t_request, &
                                       req_i1, req_e1_scal, req_e1_vect, &
                                       req_i0, req_e0_scal, req_e0_vect, &
                                       req_z1_scal, &
                                       init_transfert, &
                                       init_message => init_message_seq, &
                                       finalize_message => finalize_message_seq, &
                                       send_message => send_message_seq, &
                                       wait_message => wait_message_seq, &
                                       test_message => test_message_seq
#endif
   USE transfert_mpi_collectives_mod, ONLY: gather_field, scatter_field, bcast_field, bcast_mpi
   USE transfert_omp_mod, ONLY: bcast_omp

   IMPLICIT NONE
   PRIVATE
   PUBLIC :: t_message, t_request, &
             req_i1, req_e1_scal, req_e1_vect, &
             req_i0, req_e0_scal, req_e0_vect, &
             req_z1_scal, &
             init_transfert, &
             init_message, &
             finalize_message, &
             send_message, &
             wait_message, &
             test_message, &
             transfert_request, &
             transfert_message, &
             gather_field, scatter_field, bcast_field, bcast, bcast_omp

   INTERFACE bcast
      MODULE PROCEDURE bcast_c, &
         bcast_i, bcast_i1, bcast_i2, bcast_i3, bcast_i4, &
         bcast_r, bcast_r1, bcast_r2, bcast_r3, bcast_r4, &
         bcast_l, bcast_l1, bcast_l2, bcast_l3, bcast_l4
   END INTERFACE

CONTAINS

   SUBROUTINE transfert_message(field, message)
      USE field_mod, ONLY: t_field
      TYPE(t_field), POINTER :: field(:)
      TYPE(t_message) :: message

      CALL send_message(field, message)
      CALL wait_message(message)
   END SUBROUTINE

   SUBROUTINE transfert_request(field, request)
      USE field_mod, ONLY: t_field
      USE grid_param
      TYPE(t_field), POINTER :: field(:)
      TYPE(t_request), POINTER :: request(:)
      TYPE(t_message), SAVE :: message ! Save because shared between threads

      IF (grid_type == grid_unst) RETURN

      CALL init_message(field, request, message)
      CALL transfert_message(field, message)
      CALL finalize_message(message)
   END SUBROUTINE

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! Definition des Broadcast --> 4D   !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

!! -- Les chaine de charact�re -- !!

   SUBROUTINE bcast_c(var)
      IMPLICIT NONE
      CHARACTER(LEN=*), INTENT(INOUT) :: Var

!$OMP MASTER
      CALL bcast_mpi(Var)
!$OMP END MASTER
      CALL bcast_omp(Var)

   END SUBROUTINE bcast_c

!! -- Les entiers -- !!

   SUBROUTINE bcast_i(var)
      IMPLICIT NONE
      INTEGER, INTENT(INOUT) :: Var
!$OMP MASTER
      CALL bcast_mpi(Var)
!$OMP END MASTER
      CALL bcast_omp(Var)

   END SUBROUTINE bcast_i

   SUBROUTINE bcast_i1(var)
      IMPLICIT NONE
      INTEGER, INTENT(INOUT) :: Var(:)

!$OMP MASTER
      CALL bcast_mpi(Var)
!$OMP END MASTER
      CALL bcast_omp(Var)

   END SUBROUTINE bcast_i1

   SUBROUTINE bcast_i2(var)
      IMPLICIT NONE
      INTEGER, INTENT(INOUT) :: Var(:, :)

!$OMP MASTER
      CALL bcast_mpi(Var)
!$OMP END MASTER
      CALL bcast_omp(Var)

   END SUBROUTINE bcast_i2

   SUBROUTINE bcast_i3(var)
      IMPLICIT NONE
      INTEGER, INTENT(INOUT) :: Var(:, :, :)

!$OMP MASTER
      CALL bcast_mpi(Var)
!$OMP END MASTER
      CALL bcast_omp(Var)

   END SUBROUTINE bcast_i3

   SUBROUTINE bcast_i4(var)
      IMPLICIT NONE
      INTEGER, INTENT(INOUT) :: Var(:, :, :, :)

!$OMP MASTER
      CALL bcast_mpi(Var)
!$OMP END MASTER
      CALL bcast_omp(Var)

   END SUBROUTINE bcast_i4

!! -- Les reels -- !!

   SUBROUTINE bcast_r(var)
      IMPLICIT NONE
      REAL, INTENT(INOUT) :: Var

!$OMP MASTER
      CALL bcast_mpi(Var)
!$OMP END MASTER
      CALL bcast_omp(Var)

   END SUBROUTINE bcast_r

   SUBROUTINE bcast_r1(var)
      IMPLICIT NONE
      REAL, INTENT(INOUT) :: Var(:)

!$OMP MASTER
      CALL bcast_mpi(Var)
!$OMP END MASTER
      CALL bcast_omp(Var)

   END SUBROUTINE bcast_r1

   SUBROUTINE bcast_r2(var)
      IMPLICIT NONE
      REAL, INTENT(INOUT) :: Var(:, :)

!$OMP MASTER
      CALL bcast_mpi(Var)
!$OMP END MASTER
      CALL bcast_omp(Var)

   END SUBROUTINE bcast_r2

   SUBROUTINE bcast_r3(var)
      IMPLICIT NONE
      REAL, INTENT(INOUT) :: Var(:, :, :)

!$OMP MASTER
      CALL bcast_mpi(Var)
!$OMP END MASTER
      CALL bcast_omp(Var)

   END SUBROUTINE bcast_r3

   SUBROUTINE bcast_r4(var)
      IMPLICIT NONE
      REAL, INTENT(INOUT) :: Var(:, :, :, :)

!$OMP MASTER
      CALL bcast_mpi(Var)
!$OMP END MASTER
      CALL bcast_omp(Var)

   END SUBROUTINE bcast_r4

!! -- Les booleens -- !!

   SUBROUTINE bcast_l(var)
      IMPLICIT NONE
      LOGICAL, INTENT(INOUT) :: Var
!$OMP MASTER
      CALL bcast_mpi(Var)
!$OMP END MASTER
      CALL bcast_omp(Var)

   END SUBROUTINE bcast_l

   SUBROUTINE bcast_l1(var)
      IMPLICIT NONE
      LOGICAL, INTENT(INOUT) :: Var(:)

!$OMP MASTER
      CALL bcast_mpi(Var)
!$OMP END MASTER
      CALL bcast_omp(Var)

   END SUBROUTINE bcast_l1

   SUBROUTINE bcast_l2(var)
      IMPLICIT NONE
      LOGICAL, INTENT(INOUT) :: Var(:, :)

!$OMP MASTER
      CALL bcast_mpi(Var)
!$OMP END MASTER
      CALL bcast_omp(Var)

   END SUBROUTINE bcast_l2

   SUBROUTINE bcast_l3(var)
      IMPLICIT NONE
      LOGICAL, INTENT(INOUT) :: Var(:, :, :)

!$OMP MASTER
      CALL bcast_mpi(Var)
!$OMP END MASTER
      CALL bcast_omp(Var)

   END SUBROUTINE bcast_l3

   SUBROUTINE bcast_l4(var)
      IMPLICIT NONE
      LOGICAL, INTENT(INOUT) :: Var(:, :, :, :)

!$OMP MASTER
      CALL bcast_mpi(Var)
!$OMP END MASTER
      CALL bcast_omp(Var)

   END SUBROUTINE bcast_l4

END MODULE transfert_mod
