/****************************************************************************
**  SIONLIB     http://www.fz-juelich.de/jsc/sionlib                       **
*****************************************************************************
**  Copyright (c) 2008-2019                                                **
**  Forschungszentrum Juelich, Juelich Supercomputing Centre               **
**                                                                         **
**  See the file COPYRIGHT in the package base directory for details       **
****************************************************************************/

#define _XOPEN_SOURCE 700

#include <ctype.h>
#include <inttypes.h>
#include <math.h>
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "sion.h"

int main(int argc, char **argv)
{
  int rank, size;

  /* -------------------------- */
  /* PROLOG */
  /* -------------------------- */

  MPI_Init(&argc, &argv);
  MPI_Comm_size(MPI_COMM_WORLD, &size);
  MPI_Comm_rank(MPI_COMM_WORLD, &rank);

  /* ------------------------------------------------------ */
  /* TEST A: write a small file with some different pattern */
  /* ------------------------------------------------------ */
  {
#define BUFSIZE 1000
#define CHUNKSIZE 100
    int sid;
    char buffer[BUFSIZE];
    int64_t bytes_written = -1;
    long sum;
    size_t bwrote;
    int i, b, rc;
    sion_mpi_options *options = sion_mpi_options_new();
    if (!options)
      return 1;

    sion_mpi_options_set_chunksize(options, CHUNKSIZE);
    sion_mpi_options_set_fsblksize(options, 10);
    sion_mpi_options_set_multifile_number(options, 3);

    sid = sion_paropen_mpi("testA.out", SION_OPEN_WRITE, MPI_COMM_WORLD, options);
    sion_mpi_options_delete(options);

    if (sid >= 0) {
      /* test buffer which exact fits */
      for (i = 0; i < BUFSIZE; i++) {
        buffer[i] = 'A' + rank * 3;
      }
      b = 0;
      rc = sion_ensure_free_space(sid, CHUNKSIZE);
      fprintf(stderr, "on rank %d: ensure_free_space (%d) rc = %d\n", rank, CHUNKSIZE, rc);
      bwrote = (rc) ? sion_fwrite(buffer, 1, CHUNKSIZE, sid) : 0;
      bytes_written = sion_get_bytes_written(sid);
      printf("on rank %d: bytes_written=%" PRId64 "\n", rank, bytes_written);
      for (i = 0, sum = 0; i < bwrote; i++) {
        sum = sum + buffer[i];
      }
      printf("on rank %d: block=%d           bwrote=%3d blocksum=%8d \n", rank, b, (int)bwrote, (int)sum);

      /* test half size buffer */
      for (i = 0; i < BUFSIZE; i++) {
        buffer[i] = 'A' + rank * 3 + 1;
      }
      b = 1;
      rc = sion_ensure_free_space(sid, CHUNKSIZE / 2);
      fprintf(stderr, "on rank %d: ensure_free_space (%d) rc = %d\n", rank, CHUNKSIZE / 2, rc);
      bwrote = (rc) ? sion_fwrite(buffer, 1, CHUNKSIZE / 2, sid) : 0;
      bytes_written = sion_get_bytes_written(sid);
      printf("on rank %d: bytes_written=%" PRId64 "\n", rank, bytes_written);
      for (i = 0, sum = 0; i < bwrote; i++) {
        sum = sum + buffer[i];
      }
      printf("on rank %d: block=%d           bwrote=%3d blocksum=%8d \n", rank, b, (int)bwrote, (int)sum);

      /* test buffer which exact fits, leaving gap */
      for (i = 0; i < BUFSIZE; i++) {
        buffer[i] = 'A' + rank * 3 + 2;
      }
      b = 2;
      rc = sion_ensure_free_space(sid, CHUNKSIZE);
      fprintf(stderr, "on rank %d: ensure_free_space (%d) rc = %d\n", rank, CHUNKSIZE, rc);
      bwrote = (rc) ? sion_fwrite(buffer, 1, CHUNKSIZE, sid) : 0;
      bytes_written = sion_get_bytes_written(sid);
      printf("on rank %d: bytes_written=%" PRId64 "\n", rank, bytes_written);
      for (i = 0, sum = 0; i < bwrote; i++) {
        sum = sum + buffer[i];
      }
      printf("on rank %d: block=%d           bwrote=%3d blocksum=%8d \n", rank, b, (int)bwrote, (int)sum);

      sion_parclose_mpi(sid);
    } else {
      fprintf(stderr, "on rank %d: error sid = %d\n", rank, sid);
    }
  }

  fflush(stderr);
  fflush(stdout);
  MPI_Barrier(MPI_COMM_WORLD);
  printf("on rank %d: END of TEST A write\n", rank);
  MPI_Barrier(MPI_COMM_WORLD);

  /* ------------------------------------------------------ */
  /* TEST B: read multi file with serial interface          */
  /* ------------------------------------------------------ */
  {
#define BUFSIZE 1000
#define CHUNKSIZE 100

    if (rank == 0) {
      char *fname = "testA.out";
      int rank = 0, posinblk = 0;
      int fileId = sion_open(fname, SION_OPEN_READ, 0, NULL);
      printf("on rank %d: open(name=\"%s\", \"rb\", &numTasks, "
             "&numFiles, &chunksizes, &blocksize, &ranks, &mainFileptr)==%d\n",
        rank, fname, fileId);
      int success = sion_switch_logical_file(fileId, rank);
      success &= sion_seek_chunk(fileId, 0, SION_SEEK_BEGINNING);
      success &= sion_seek(fileId, posinblk, SION_SEEK_CHUNK_BEGINNING);
      printf("on rank %d: seek_fp(fileId=%d,0,0,0,&fileptr)==%d\n", rank, fileId, success);

      if (fileId >= 0) {
        sion_close(fileId);
      }
    } else {
      fprintf(stderr, "on rank %d: no action\n", rank);
    }
  }

  fflush(stderr);
  fflush(stdout);
  MPI_Barrier(MPI_COMM_WORLD);
  printf("on rank %d: END of TEST A write\n", rank);
  MPI_Barrier(MPI_COMM_WORLD);

  /* -------------------------- */
  /* EPILOG */
  /* -------------------------- */
  MPI_Finalize();

  return 0;
}
