/****************************************************************************
**  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       **
****************************************************************************/

/*!
 * \cond sion_internal
 * \file
 */

#ifndef SION_SION_INTERNAL_H
#define SION_SION_INTERNAL_H

#include <stdint.h>
#include <stdio.h>

#include "sion_common.h"
#include "sion_enums.h"
#include "sion_filedesc.h"
#include "sion_serial.h"

#define _SION_READ_MASTER_ONLY_OF_MULTI_FILES 0
#define _SION_READ_ALL_OF_MULTI_FILES 1

struct sion_rank_options {
  sion_lowlevel_api lowlevel_api; // default: SION_LOWLEVEL_API_C
};

#define SION_RANK_OPTIONS_INIT \
  (sion_rank_options) \
  { \
    .lowlevel_api = SION_LOWLEVEL_API_C, \
  }

struct sion_options {
  int n_chunksizes; // default: 0
  const int64_t *chunksizes; // default: fsblksize
  int32_t fsblksize; // default: auto-detect

  sion_keyval_mode keyval_mode; // default: SION_KEYVAL_MODE_NONE

  sion_lowlevel_api lowlevel_api; // default: SION_LOWLEVEL_API_C

  sion_endianness endianness; // default: SION_ENDIANNESS_HOST
};

#define SION_OPTIONS_INIT \
  (sion_options) \
  { \
    .n_chunksizes = 0, .chunksizes = NULL, .fsblksize = -1, .keyval_mode = SION_KEYVAL_MODE_NONE, \
    .lowlevel_api = SION_LOWLEVEL_API_C, .endianness = SION_ENDIANNESS_HOST, \
  }

/* internal functions for serial open/close, will also be used by parallel APIs */

int _sion_open_write(const char *fname, int n, const sion_options *options);
int _sion_open_read(const char *fname, int read_all, const sion_options *options);
int _sion_open_read_single(const char *fname, const sion_options *options, _sion_filedesc *filedesc);
int _sion_open_read_master(const char *fname, const sion_options *options, _sion_filedesc *filedesc);

int _sion_open_rank(const char *fname, sion_open_mode mode, int rank, const sion_rank_options *options);

int _sion_close_sid(int sid);
int _sion_close(_sion_filedesc *sion_filedesc);

/*!\brief check if a collective operation are already called,
 *
 * @param  *sion_filedesc                       sion file description struct (_sion_filedesc)
 *
 * @retval SION_SUCCESS if OK
 */
int _sion_check_on_collective_mode(_sion_filedesc *sion_filedesc);

/*!\brief generates the multi filename
 *
 * @param  fname                file name
 * @param  filenumber           file number
 *
 * @retval pointer to new filename
 */
char *_sion_get_multi_filename(const char *fname, int filenumber);

/*!\brief Flush the data to the disk for the current task
 *
 * @param  sid          sion file handle
 *
 * @retval SION_SUCCESS if OK
 */
int _sion_flush_file(int sid);

/*!\brief Return endianness including possible choice via flags
 *
 *  return endianness
 */
int32_t _sion_get_endianness_with_flags(int64_t flags);

int32_t _sion_get_endianness_with_override(sion_endianness override);

/* File mode flags */
#define _SION_FMODE_WRITE 1024
#define _SION_FMODE_READ 2048
#define _SION_FMODE_ANSI 1
#define _SION_FMODE_POSIX 2
#define _SION_FMODE_BUFFERED 4
#define _SION_FMODE_COMPRESS 8
#define _SION_FMODE_COLLECTIVE 16
#define _SION_FMODE_COLLECTIVE_MERGE 32
#define _SION_FMODE_KEYVAL 64
#define _SION_FMODE_KEYVAL_INLINE 4096
#define _SION_FMODE_KEYVAL_META 8192
#define _SION_FMODE_KEYVAL_HASH 16384
#define _SION_FMODE_KEYVAL_NONE 32768
#define _SION_FMODE_KEYVAL_UNKNOWN 65536
#define _SION_FMODE_ENDIANNESS_SET 131072
#define _SION_FMODE_ENDIANNESS_BIG 262144
#define _SION_FMODE_BUDDY 524288

/*! encapsulate getenv
 *
 */
char *_sion_getenv(const char *name);

/*!\brief allocates an io_info data structure for nfiles files
 *
 *  return flags
 #   p: pointer to data structure
 */
sion_io_stat_t *_sion_alloc_io_info(int nfiles);

/*!\brief frees an io_info data structure
 *
 *  return flags:
 *    rc
 */
int _sion_free_io_info(sion_io_stat_t *p);

int _sion_move_to_next_chunk(_sion_filedesc *sion_filedesc);
size_t _sion_write_multi_chunk(_sion_filedesc *sion_filedesc, const void *data, int64_t bytes_to_write);
size_t _sion_read_multi_chunk(_sion_filedesc *sion_filedesc, void *data, int64_t bytes_to_read);

/// \brief perform a dry run write
///
/// This function has the same side effects w.r.t. the internal SIONlib datastructures as writing `amount` bytes to the file starting at the current position, i.e. create additional blocks if necessary and modify the `currentpos` and `currentblocknr` field of the file descriptor.
/// This is useful for example for collective I/O, where book keeping is done on the sender side.
///
/// \param[in,out] filedesc a file descriptor of the file to "write" to
/// \param[in] amount how many bytes to "write" to the file
void _sion_write_dry_run(_sion_filedesc *filedesc, int64_t amount);

/// \brief perform a dry run read
///
/// This function has the same side effects w.r.t. the internal SIONlib datastructures as reading `amount` bytes from the file starting at the current position, i.e. modify the `currentpos` and `currentblocknr` field of the file descriptor.
///
/// \param[in,out] filedesc a file descriptor of the file to "read" from
/// \param[in] amount how many bytes to "read" from the file
void _sion_read_dry_run(_sion_filedesc *filedesc, int64_t amount);

#endif

/// \endcond
