#ifndef Z4C_RHS_CUDA_H
#define Z4C_RHS_CUDA_H

#ifdef __cplusplus
extern "C" {
#endif

enum {
    Z4C_CUDA_STATE_COUNT = 25
};

int z4c_cuda_rk4_substep(void *block_tag,
                         int *ex, double *X, double *Y, double *Z,
                         double **state_host_in,
                         double **state_host_out,
                         const double *propspeed,
                         const double *soa_flat,
                         const double *bbox,
                         double &dT,
                         double &T,
                         int &RK4,
                         int &apply_bam_bc,
                         int &Symmetry,
                         int &Lev,
                         double &eps,
                         int &co,
                         int &keep_resident_state,
                         int &apply_enforce_ga,
                         double &chitiny);

int z4c_cuda_download_resident_state(void *block_tag,
                                     int *ex,
                                     double **state_host_out);

int z4c_cuda_pack_state_region_to_host_buffer(void *block_tag,
                                              int state_index,
                                              double *host_buffer,
                                              int *ex,
                                              int i0, int j0, int k0,
                                              int sx, int sy, int sz);

int z4c_cuda_unpack_state_region_from_host_buffer(void *block_tag,
                                                  int state_index,
                                                  double *host_buffer,
                                                  int *ex,
                                                  int i0, int j0, int k0,
                                                  int sx, int sy, int sz);

int z4c_cuda_pack_state_batch_to_host_buffer(void *block_tag,
                                             int state_count,
                                             double *host_buffer,
                                             int *ex,
                                             int i0, int j0, int k0,
                                             int sx, int sy, int sz);

int z4c_cuda_unpack_state_batch_from_host_buffer(void *block_tag,
                                                 int state_count,
                                                 double *host_buffer,
                                                 int *ex,
                                                 int i0, int j0, int k0,
                                                 int sx, int sy, int sz);

int z4c_cuda_pack_state_batch_to_device_buffer(void *block_tag,
                                               int state_count,
                                               double *device_buffer,
                                               int *ex,
                                               int i0, int j0, int k0,
                                               int sx, int sy, int sz);

int z4c_cuda_unpack_state_batch_from_device_buffer(void *block_tag,
                                                   int state_count,
                                                   double *device_buffer,
                                                   int *ex,
                                                   int i0, int j0, int k0,
                                                   int sx, int sy, int sz);

int z4c_cuda_restrict_state_batch_to_device_buffer(void *block_tag,
                                                   int state_count,
                                                   double *device_buffer,
                                                   int *ex,
                                                   int sx, int sy, int sz,
                                                   int fi0, int fj0, int fk0,
                                                   const double *state_soa);

int z4c_cuda_prolong_state_batch_to_device_buffer(void *block_tag,
                                                  int state_count,
                                                  double *device_buffer,
                                                  int *ex,
                                                  int sx, int sy, int sz,
                                                  int ii0, int jj0, int kk0,
                                                  int lbc_i, int lbc_j, int lbc_k,
                                                  const double *state_soa);

int z4c_cuda_download_state_subset(void *block_tag,
                                   int *ex,
                                   int subset_count,
                                   const int *state_indices,
                                   double **state_host_out);

int z4c_cuda_upload_state_subset(void *block_tag,
                                 int *ex,
                                 int subset_count,
                                 const int *state_indices,
                                 double **state_host_in);

int z4c_cuda_has_resident_state(void *block_tag);

void z4c_cuda_release_step_ctx(void *block_tag);

#ifdef __cplusplus
}
#endif

#endif
