MODULE transfert_request_unst_mod
   USE read_pmesh_mod, ONLY: t_pmesh
   USE field_mod, ONLY: t_field, field_T, field_U, field_Z
   USE transfert_types_mod, ONLY: t_request, t_submessage
   IMPLICIT NONE
   PRIVATE

   PUBLIC :: init_all_requests_unst

CONTAINS

   ! Initialize all transfer requests when grid is unstructured
   ! We assume that a single domain is managed by each MPI rank
   ! This routine is called inside an OMP MASTER section
   SUBROUTINE init_all_requests_unst(pmesh)
      USE transfert_types_mod, ONLY: &
         req_i0, req_e0_vect, req_e0_scal, &
         req_i1, req_e1_vect, req_e1_scal, req_z1_scal
      TYPE(t_pmesh), INTENT(IN) :: pmesh
      CALL init_requests(field_T, pmesh, req_i0)
      CALL init_requests(field_T, pmesh, req_i1)
      CALL init_requests(field_U, pmesh, req_e0_vect)
      CALL init_requests(field_U, pmesh, req_e0_scal)
      CALL init_requests(field_U, pmesh, req_e1_vect)
      CALL init_requests(field_U, pmesh, req_e1_scal)
      CALL init_requests(field_Z, pmesh, req_z1_scal)
   END SUBROUTINE init_all_requests_unst

   SUBROUTINE init_requests(field_type, pmesh, req)
      INTEGER, INTENT(IN)  :: field_type
      TYPE(t_pmesh), INTENT(IN)  :: pmesh
      TYPE(t_request), POINTER, INTENT(OUT) :: req(:)
      ALLOCATE (req(1))
      CALL init_request(field_type, pmesh, req(1))
   END SUBROUTINE init_requests

   SUBROUTINE init_request(field_type, pmesh, req)
      INTEGER, INTENT(IN)  :: field_type
      TYPE(t_pmesh), INTENT(IN)  :: pmesh
      TYPE(t_request), INTENT(OUT) :: req
      req%has_message = .TRUE.
      req%vector = .FALSE. ! even for vector data, we never need to change signs
      req%field_type = field_type
      ALLOCATE (req%message_local(0)) ! we never have local halo exchanges

      SELECT CASE (field_type)
      CASE (field_T)
         CALL init_message_inout(pmesh%primal_recv, req%message_in)
         CALL init_message_inout(pmesh%primal_send, req%message_out)
      CASE (field_U)
         CALL init_message_inout(pmesh%edge_recv, req%message_in)
         CALL init_message_inout(pmesh%edge_send, req%message_out)
      CASE (field_Z)
         CALL init_message_inout(pmesh%dual_recv, req%message_in)
         CALL init_message_inout(pmesh%dual_send, req%message_out)
      END SELECT
   END SUBROUTINE init_request

   SUBROUTINE init_message_inout(halo, message)
      INTEGER, DIMENSION(:), INTENT(IN) :: halo
      TYPE(t_submessage), DIMENSION(:), ALLOCATABLE, INTENT(OUT) :: message
      ! halo exchange descriptor stucture (see Python/test/py/gen_mpi_mesh_info.py) :
      !     halo(1) is the number of subsequent chunks
      !     halo(2:N+3) is the first chunk, received from MPI rank halo(2) with N=halo(3) the size of the chunk
      !     halo(i+3) (i=1,...N) is the local index of the cell sent/received to/from rank halo(2)
      !     the next chunk start at N+4
      INTEGER :: nchunk, npoints, pos, i, icell
      pos = 1
      nchunk = next()
      ALLOCATE (message(nchunk))
      DO i = 1, nchunk
         message(i)%ind_loc = 1
         message(i)%remote_ind_glo = 1
         message(i)%remote_rank = next()
         npoints = next()
         message(i)%npoints = npoints
         ALLOCATE (message(i)%displs(npoints))
         ALLOCATE (message(i)%sign(npoints))
         DO icell = 1, npoints
            message(i)%sign(icell) = 1
            message(i)%displs(icell) = next()
         END DO
      END DO

   CONTAINS

      FUNCTION next() RESULT(val)
         INTEGER :: val
         val = halo(pos)
         pos = pos + 1
      END FUNCTION next

   END SUBROUTINE init_message_inout

END MODULE transfert_request_unst_mod
