!*****************
! File Description:  
!   This is the wrapper to work with cuDPP library
! Creator: Hoang-Trong Minh Tuan  (@George Mason University, 2010)
! 
! Rev: 0.1 
! Update: 
!    x.x: 
!*******************/

! NOTE:
! typedef size_t CUDPPHandle;  == INTEGER(c_size_t)
MODULE cudpp
! We need to link with the library libcudpp-x86_64.so
  USE, INTRINSIC ::  iso_c_binding

  ENUM, BIND(C) !CUDPPResuslt
     ENUMERATOR :: CUDPP_SUCCESS = 0, CUDPP_ERROR_INVALID_HANDLE, CUDPP_ERROR_ILLEGAL_CONFIGURATION
     ENUMERATOR :: CUDPP_ERROR_UNKNOWN = 9999
  END ENUM

  ENUM, BIND(C) ! CUDPPOption
     ENUMERATOR ::  CUDPP_OPTION_FORWARD   = Z'1', &
          CUDPP_OPTION_BACKWARD  = Z'2', &
          CUDPP_OPTION_EXCLUSIVE = Z'4', &
          CUDPP_OPTION_INCLUSIVE = Z'8', &
          CUDPP_OPTION_CTA_LOCAL = Z'10', &
          CUDPP_OPTION_KEYS_ONLY = Z'20', &
          CUDPP_OPTION_KEY_VALUE_PAIRS = Z'40'
  END ENUM

  ENUM, BIND(C) ! CUDPPDatatype
     ENUMERATOR ::  CUDPP_CHAR, &
          CUDPP_UCHAR, &
          CUDPP_INT, &
          CUDPP_UINT, &
          CUDPP_FLOAT, &
          CUDPP_DOUBLE
  END ENUM

  ENUM, BIND(C) ! CUDPPOperator
     ENUMERATOR :: CUDPP_ADD, &
          CUDPP_MULTIPLY, &
          CUDPP_MIN, &
          CUDPP_MAX
  END ENUM

  ENUM, BIND(C) !CUDPPAlgorithm
     ENUMERATOR :: CUDPP_SCAN, &
          CUDPP_SEGMENTED_SCAN, &
          CUDPP_COMPACT, &           
          CUDPP_REDUCE,  &
          CUDPP_SORT_RADIX, &
          CUDPP_SPMVMULT,  &
          CUDPP_RAND_MD5,  &
          CUDPP_ALGORITHM_INVALID
  END ENUM

    
!!$  struct CUDPPConfiguration
!!${
!!$    CUDPPAlgorithm algorithm; //!< The algorithm to be used
!!$    CUDPPOperator  op;        //!< The numerical operator to be applied
!!$    CUDPPDatatype  datatype;  //!< The datatype of the input arrays
!!$    unsigned int   options;   //!< Options to configure the algorithm
!!$};
  TYPE, BIND(C) :: CUDPPConfiguration
     !  TYPE  CUDPPConfiguration
     INTEGER(KIND(CUDPP_SEGMENTED_SCAN)) :: algorithm
     INTEGER(KIND(CUDPP_ADD)) :: op
     INTEGER(KIND(CUDPP_CHAR)) :: datatype
     INTEGER(c_int) :: options
  END TYPE CUDPPConfiguration

  INTERFACE
!!$     CUDPPResult cudppCreate(CUDPPHandle* theCudpp);      
     FUNCTION cudppCreate(theCudpp) BIND(C, NAME="cudppCreate") RESULT(res)
       USE, INTRINSIC :: iso_c_binding
       IMPLICIT NONE
       INTEGER(c_size_t) :: theCudpp
       INTEGER(KIND(CUDPP_SUCCESS)) :: res
     END FUNCTION cudppCreate

!!$     CUDPPResult cudppPlan(const CUDPPHandle  cudppHandle,
!!$                      CUDPPHandle        *planHandle, ! can be reused for other data (of the same or smaller size)
!!$                      CUDPPConfiguration config, 
!!$                      size_t             n, ! max. # elements, 
!!$                      size_t             rows,  !# of rows, for 2D
!!$                      size_t             rowPitch); ! distance between two adjacent rows
     FUNCTION cudppPlan(cudppHandle, planHandle, config, n, rows, rowPitch) BIND(C, NAME="cudppPlan") RESULT(res)
       USE, INTRINSIC :: iso_c_binding
       IMPLICIT NONE
       TYPE, BIND(C) :: CUDPPConfiguration
          INTEGER(KIND(CUDPP_SEGMENTED_SCAN)) :: algorithm
          INTEGER(KIND(CUDPP_ADD)) :: op
          INTEGER(KIND(CUDPP_CHAR)) :: datatype
          INTEGER(c_int) :: options
       END TYPE CUDPPConfiguration
       
       INTEGER(c_size_t), INTENT(IN) :: cudppHandle
       INTEGER(c_size_t) :: planHandle
       TYPE(CUDPPConfiguration), INTENT(INOUT) :: config
       INTEGER(c_size_t), VALUE :: n
       INTEGER(c_size_t), VALUE :: rows
       INTEGER(c_size_t), VALUE :: rowPitch
       INTEGER(KIND(CUDPP_SUCCESS)) :: res
     END FUNCTION cudppPlan

!!$     CUDPPResult cudppReduce(const CUDPPHandle planHandle,
!!$                        void              *d_out,
!!$                        const void        *d_in,
!!$                        size_t            numElements);
     FUNCTION cudppReduce(planHandle, d_out, d_in, numElements) BIND(C, NAME="cudppReduce") RESULT(res)
       USE, INTRINSIC :: iso_c_binding
       IMPLICIT NONE
       INTEGER(c_size_t), VALUE :: planHandle
       REAL(c_double), ALLOCATABLE, DIMENSION(:), device :: d_out, d_in
!!$       TYPE(C_PTR), VALUE :: d_out
!!$       TYPE(C_PTR), INTENT(IN) :: d_in
       INTEGER(c_size_t), VALUE :: numElements
       INTEGER(KIND(CUDPP_SUCCESS)) :: res
     END FUNCTION cudppReduce
     
     FUNCTION cudppDestroy(theCudpp) BIND(C, NAME="cudppDestroy")  RESULT(res)
       USE, INTRINSIC :: iso_c_binding
       INTEGER(c_size_t), VALUE :: theCudpp
       INTEGER(KIND(CUDPP_SUCCESS)) :: res
     END FUNCTION cudppDestroy
!!$     CUDPPResult cudppDestroyPlan(CUDPPHandle plan);
     FUNCTION cudppDestroyPlan(plan) BIND(C, NAME="cudppDestroyPlan") RESULT(res)
       USE, INTRINSIC :: iso_c_binding
       IMPLICIT NONE
       INTEGER(c_size_t), VALUE :: plan
       INTEGER(KIND(CUDPP_SUCCESS)) :: res
     END FUNCTION cudppDestroyPlan
  END INTERFACE



CONTAINS


END MODULE cudpp
