#ifndef PIO_UTIL_
#define PIO_UTIL_

#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <mpi.h>

#ifndef ERROR_H
#include "error.h"
#endif

#define MAXDEBUG 3

#define ddebug 0

#define debugString "#####"

void cdiAbortC_MPI(const char *caller, const char *filename, const char *functionname, int line, const char *errorString,
                   va_list ap) __attribute__((noreturn));

void cdiPioWarning(const char *caller, const char *fmt, va_list ap);

static inline int
callsToMPIAreAllowed()
{
  int init_flag = 0, finished_flag = 0;
  return MPI_Initialized(&init_flag) == MPI_SUCCESS && init_flag && MPI_Finalized(&finished_flag) == MPI_SUCCESS && !finished_flag;
}

static inline int
getMPICommWorldRank()
{
  int rank = -1;
  if (callsToMPIAreAllowed()) MPI_Comm_rank(MPI_COMM_WORLD, &rank);
  return rank;
}

#define xdebug(fmt, ...)                                                                                                      \
  if (ddebug)                                                                                                                 \
    {                                                                                                                         \
      int rank = getMPICommWorldRank();                                                                                       \
      fprintf(stderr, "%s pe%d in %s, %s, line %d: " fmt "\n", debugString, rank, __func__, __FILE__, __LINE__, __VA_ARGS__); \
    }

#define xdebug3(fmt, ...)                                                                                     \
  if (ddebug == MAXDEBUG)                                                                                     \
    {                                                                                                         \
      int rank = getMPICommWorldRank();                                                                       \
      fprintf(stderr, "pe%d in %s, %s, line %d: " fmt "\n", rank, __func__, __FILE__, __LINE__, __VA_ARGS__); \
    }

void pcdiXMPI(int iret, const char *, int);
#define xmpi(ret)                                                        \
  do                                                                     \
    {                                                                    \
      int tmpIRet = (ret);                                               \
      if (tmpIRet != MPI_SUCCESS) pcdiXMPI(tmpIRet, __FILE__, __LINE__); \
    }                                                                    \
  while (0)

void pcdiXMPIStat(int, const char *, int, MPI_Status *);
#define xmpiStat(ret, stat) pcdiXMPIStat(ret, __FILE__, __LINE__, stat)

void pcdiDebugMsg(const char *cdiDebugString, const char *filename, const char *functionname, int line, int tag, int source,
                  int nfinished);
#define xdebugMsg(tag, source, nfinished) \
  if (ddebug) pcdiDebugMsg(debugString, __FILE__, __func__, __LINE__, tag, source, nfinished)

void pcdiDebugMsg2(const char *filename, const char *functionname, int line, int tag, int source, char *text);
#define xdebugMsg2(tag, source, text) \
  if (ddebug) pcdiDebugMsg(__FILE__, __func__, __LINE__, tag, source, text)

static inline int
sum_int(size_t n, int *a)
{
  int sum = 0;
  for (size_t i = 0; i < n; ++i) sum += a[i];
  return sum;
}

void printArray(const char *, const char *, const void *, int, int, const char *, const char *, int);
#define xprintArray(ps, array, n, datatype) \
  if (ddebug) printArray(debugString, ps, array, n, datatype, __func__, __FILE__, __LINE__)

#define xprintArray3(ps, array, n, datatype) \
  if (ddebug == MAXDEBUG) printArray(debugString, ps, array, n, datatype, __func__, __FILE__, __LINE__)

/**
 * @return number of dimensions
 */
int cdiPioQueryVarDims(int varShape[3], int vlistID, int varID);

void cdiPioDeco1D_CCP(size_t n, const size_t weightPfxSums[n], size_t nparts, size_t separators[nparts + 1]);

#endif
/*
 * Local Variables:
 * c-file-style: "Java"
 * c-basic-offset: 2
 * indent-tabs-mode: nil
 * show-trailing-whitespace: t
 * require-trailing-newline: t
 * End:
 */
