#include <string.h>

#include "MPIWrapper.h"

static MPIWrapper* g_pMPIWrapperInstance = NULL;

MPIWrapper* MPIWrapper_Construct(MPIWrapper* pThis)
{
  return pThis;
}

void MPIWrapper_Destruct(MPIWrapper* pThis)
{
  if(pThis)
  {
    free(pThis);
  }

  g_pMPIWrapperInstance = NULL;
}

MPIWrapper* MPIWrapper_Instance(void)
{
  if(g_pMPIWrapperInstance)
  {
  }
  else
  {
    g_pMPIWrapperInstance = MPIWrapper_Construct(malloc(sizeof(MPIWrapper)));
  }
  return g_pMPIWrapperInstance;
}

int MPIWrapper_Init(MPIWrapper* pThis, int* argc, char*** argv)
{
  int nResult;

  pThis->dummy = 4711;

  nResult = MPI_Init(argc, argv);

  if(nResult == MPI_SUCCESS)
  {
  }
  else
  {
  }

  return nResult;
}

int MPIWrapper_Finalize(MPIWrapper* pThis)
{
  int nResult;

  nResult = MPI_Finalize();

  if(nResult == MPI_SUCCESS)
  {
  }
  else
  {
  }

  return nResult;
}

int MPIWrapper_Bcast(MPIWrapper* pThis, void* buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm)
{
  int nResult;

  nResult = MPI_Bcast(buffer, count, datatype, root, comm);

  return nResult;
}

int MPIWrapper_Comm_rank(MPIWrapper* pThis, MPI_Comm comm, int* rank)
{
  int nResult;

  nResult = MPI_Comm_rank(comm, rank);

  return nResult;
}

int MPIWrapper_Comm_size(MPIWrapper* pThis, MPI_Comm comm, int* size)
{
  int nResult;

  nResult = MPI_Comm_size(comm, size);

  return nResult;
}

int MPIWrapper_Get_processor_name(MPIWrapper* pThis, char* name, int* resultlen)
{
  int nResult;

  nResult = MPI_Get_processor_name(name, resultlen);

  return nResult;
}

int MPIWrapper_Iprobe(MPIWrapper* pThis, int source, int tag, MPI_Comm comm, int* flag, MPI_Status* status)
{
  int nResult;

  nResult = MPI_Iprobe(source, tag, comm, flag, status);
  
  return nResult;
}

int MPIWrapper_Isend(MPIWrapper* pThis, void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request* request)
{
  int nResult;

  nResult = MPI_Isend(buf, count, datatype, dest, tag, comm, request);
  
  return nResult;
}

int MPIWrapper_Probe(MPIWrapper* pThis, int source, int tag, MPI_Comm comm, MPI_Status* status)
{
  int nResult;

  nResult = MPI_Probe(source, tag, comm, status);
  
  return nResult;
}

int MPIWrapper_Wait(MPIWrapper* pThis, MPI_Request* request, MPI_Status* status)
{
  int nResult;

  nResult = MPI_Wait(request, status);
  
  return nResult;
}

int MPIWrapper_Pack(MPIWrapper* pThis, void* inbuf, int incount, MPI_Datatype datatype, void* outbuf, int outsize, int* position, MPI_Comm comm)
{
  int nResult;

  nResult = MPI_Pack(inbuf, incount, datatype, outbuf, outsize, position, comm);
  
  return nResult;
}

int MPIWrapper_Recv(MPIWrapper* pThis, void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status* status)
{
  int nResult;

  nResult = MPI_Recv(buf, count, datatype, source, tag, comm, status);
  
  return nResult;
}

int MPIWrapper_Send(MPIWrapper* pThis, void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
{
  int nResult;

  nResult = MPI_Send(buf, count, datatype, dest, tag, comm);
  
  return nResult;
}

int MPIWrapper_Test(MPIWrapper* pThis, MPI_Request* request, int* flag, MPI_Status* status)
{
  int nResult;

  nResult = MPI_Test(request, flag, status);
  
  return nResult;
}

int MPIWrapper_Unpack(MPIWrapper* pThis, void* inbuf, int insize, int* position, void* outbuf, int outcount, MPI_Datatype datatype, MPI_Comm comm)
{
  int nResult;

  nResult = MPI_Unpack(inbuf, insize, position, outbuf, outcount, datatype, comm);
  
  return nResult;
}

// kh 01.07.04 start extensions
// kh 05.09.06 Pack...
int MPIWrapper_Pack_BOOL(MPIWrapper* pThis, BOOL bIn, void* outbuf, int outsize, int* position, MPI_Comm comm)
{
  int nResult;
  int nFlag;

  if(bIn)
  {
    nFlag = 1;
  }
  else
  {
    nFlag = 0;
  }

  nResult = MPIWrapper_Pack_INT(pThis, 
                                nFlag,
                                outbuf,
                                outsize,
                                position,
                                comm);

  return nResult;
}

int MPIWrapper_Pack_USHORT(MPIWrapper* pThis, uint16 nIn, void* outbuf, int outsize, int* position, MPI_Comm comm)
{
  int nResult;
  nResult = MPIWrapper_Pack(pThis,
                            &nIn,
							              1,
							              MPI_UNSIGNED_SHORT,
							              outbuf,
							              outsize,
							              position,
							              comm);

  return nResult;
}

int MPIWrapper_Pack_INT(MPIWrapper* pThis, int nIn, void* outbuf, int outsize, int* position, MPI_Comm comm)
{
  int nResult;
  nResult = MPIWrapper_Pack(pThis,
                            &nIn,
							              1,
							              MPI_INT,
							              outbuf,
							              outsize,
							              position,
							              comm);

  return nResult;
}

int MPIWrapper_Pack_INT64(MPIWrapper* pThis, sint64 nIn, void* outbuf, int outsize, int* position, MPI_Comm comm)
{
  int nResult;
  nResult = MPIWrapper_Pack(pThis,
                            &nIn,
							              1,
							              MPI_LONG_LONG_INT,
							              outbuf,
							              outsize,
							              position,
							              comm);

  return nResult;
}

int MPIWrapper_Pack_UINT64(MPIWrapper* pThis, uint64 nIn, void* outbuf, int outsize, int* position, MPI_Comm comm)
{
  int nResult;
  nResult = MPIWrapper_Pack(pThis,
                            &nIn,
							              1,
							              MPI_UNSIGNED_LONG_LONG,
							              outbuf,
							              outsize,
							              position,
							              comm);

  return nResult;
}

int MPIWrapper_Pack_DOUBLE(MPIWrapper* pThis, double nIn, void* outbuf, int outsize, int* position, MPI_Comm comm)
{
  int nResult;
  nResult = MPIWrapper_Pack(pThis,
                            &nIn,
							              1,
							              MPI_DOUBLE,
							              outbuf,
							              outsize,
							              position,
							              comm);

  return nResult;
}

int MPIWrapper_Pack_STR(MPIWrapper* pThis, char* sIn, void* outbuf, int outsize, int* position, MPI_Comm comm)
{
  int nResult;
  int nStrLength;

  nStrLength = strlen(sIn);

  nResult = MPIWrapper_Pack_INT(pThis, 
                                nStrLength,
                                outbuf,
                                outsize,
                                position,
                                comm);

  if(nResult == MPI_SUCCESS)
  {
    nResult = MPIWrapper_Pack(pThis, 
                              sIn,
                              nStrLength,
                              MPI_CHAR,
                              outbuf,
                              outsize,
                              position,
                              comm);
  }

  return nResult;
}

int MPIWrapper_Pack_USHORT_ARRAY(MPIWrapper* pThis, int nLength, uint16 nIn[], void* outbuf, int outsize, int* position, MPI_Comm comm)
{
  int nResult;

  nResult = MPIWrapper_Pack_INT(pThis, 
                                nLength,
                                outbuf,
                                outsize,
                                position,
                                comm);

  if(nResult == MPI_SUCCESS)
  {
    nResult = MPIWrapper_Pack(pThis, 
                              nIn,
                              nLength,
                              MPI_UNSIGNED_SHORT,
                              outbuf,
                              outsize,
                              position,
                              comm);
  }

  return nResult;
}


// kh 05.09.06 Unpack...
int MPIWrapper_Unpack_BOOL(MPIWrapper* pThis, void* inbuf, int insize, int* position, BOOL* pbOut, MPI_Comm comm)
{
  int nResult;
  int nFlag;

  nResult = MPIWrapper_Unpack_INT(pThis, 
                                  inbuf,
                                  insize,
                                  position,
                                  &nFlag,
                                  comm);


  *pbOut = (nFlag != 0);

  return nResult;
}

int MPIWrapper_Unpack_USHORT(MPIWrapper* pThis, void* inbuf, int insize, int* position, uint16* pnOut, MPI_Comm comm)
{
  int nResult;
  nResult = MPIWrapper_Unpack(pThis, 
                              inbuf,
                              insize,
                              position,
                              pnOut,
                              1,
                              MPI_UNSIGNED_SHORT,
                              comm);

  return nResult;
}

int MPIWrapper_Unpack_INT(MPIWrapper* pThis, void* inbuf, int insize, int* position, int* pnOut, MPI_Comm comm)
{
  int nResult;
  nResult = MPIWrapper_Unpack(pThis, 
                              inbuf,
                              insize,
                              position,
                              pnOut,
                              1,
                              MPI_INT,
                              comm);

  return nResult;
}

int MPIWrapper_Unpack_INT64(MPIWrapper* pThis, void* inbuf, int insize, int* position, sint64* pnOut, MPI_Comm comm)
{
  int nResult;
  nResult = MPIWrapper_Unpack(pThis, 
                              inbuf,
                              insize,
                              position,
                              pnOut,
                              1,
                              MPI_LONG_LONG_INT,
                              comm);

  return nResult;
}

int MPIWrapper_Unpack_UINT64(MPIWrapper* pThis, void* inbuf, int insize, int* position, uint64* pnOut, MPI_Comm comm)
{
  int nResult;
  nResult = MPIWrapper_Unpack(pThis, 
                              inbuf,
                              insize,
                              position,
                              pnOut,
                              1,
                              MPI_UNSIGNED_LONG_LONG,
                              comm);

  return nResult;
}

int MPIWrapper_Unpack_DOUBLE(MPIWrapper* pThis, void* inbuf, int insize, int* position, double* pnOut, MPI_Comm comm)
{
  int nResult;
  nResult = MPIWrapper_Unpack(pThis, 
                              inbuf,
                              insize,
                              position,
                              pnOut,
                              1,
                              MPI_DOUBLE,
                              comm);

  return nResult;
}

int MPIWrapper_Unpack_STR(MPIWrapper* pThis, void* inbuf, int insize, int* position, char* sOut, MPI_Comm comm)
{
  int nResult;
  int nStrLength;

  nResult = MPIWrapper_Unpack_INT(pThis, 
                                  inbuf,
                                  insize,
                                  position,
                                  &nStrLength,
                                  comm);

  if(nResult == MPI_SUCCESS)
  {
    nResult = MPIWrapper_Unpack(pThis, 
                                inbuf,
                                insize,
                                position,
                                sOut,
                                nStrLength,
                                MPI_CHAR,
                                comm);

    sOut[nStrLength] = '\0';
  }

  return nResult;
}

int MPIWrapper_Unpack_USHORT_ARRAY(MPIWrapper* pThis, void* inbuf, int insize, int* position, int* pnLength, uint16 nOut[], MPI_Comm comm)
{
  int nResult;

  nResult = MPIWrapper_Unpack_INT(pThis, 
                                  inbuf,
                                  insize,
                                  position,
                                  pnLength,
                                  comm);

  if(nResult == MPI_SUCCESS)
  {
    nResult = MPIWrapper_Unpack(pThis, 
                                inbuf,
                                insize,
                                position,
                                nOut,
                                *pnLength,
                                MPI_UNSIGNED_SHORT,
                                comm);
  }

  return nResult;
}
