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

#ifndef SION_SION_SERIAL_H
#define SION_SION_SERIAL_H

/// \defgroup serial Serial API
/// @{
/// \brief Open (and close) SIONlib files from a single task

#include <stdint.h>

#include "sion_enums.h"

#ifdef __cplusplus
extern "C" {
#endif

/// \brief Holds non-essential arguments for `sion_open()`.
///
/// These are:
/// - the sizes of chunks for each logical file,
/// - the size of a file system block to assume,
/// - whether and in what mode to use SIONlib's key-value mechanism,
/// - what low-level API to use for file system access,
/// - the endianness of user data in the file.
typedef struct sion_options sion_options;

/// \brief Holds non-essential arguments for `sion_open_rank()`.
///
/// Currently, only the low-level API to use for file system access can be selected.
typedef struct sion_rank_options sion_rank_options;

/// \brief Open a SIONlib container in serial mode.
///
/// This function opens all logical files of a SIONlib container in serial mode. The
/// meta-data of all logical files will be loaded into memory, which allows
/// accessing different logical files by using `sion_switch_logical_file()`.
/// Default position of the file pointer is in front of the first byte of the first
/// logical file
///
/// In the case of multi-file containers `sion_open()` internally opens each
/// physical file with `sion_open()` recursively. For each physical file
/// SIONlib manages an individual file descriptor and data structure.
///
/// \param[in] fname name of the container to open
/// \param[in] mode mode in which to open the container
/// \param[in] n number of logical files in the container (only significant upon container creation)
/// \param[in] options provide additional options, or `NULL`
///
/// \returns a handle to the open file or -1 in case an error occurred
int sion_open(const char *fname, sion_open_mode mode, int n, const sion_options *options);

/// \brief Open a single logical file in a SIONlib container
///
/// This function opens single logical file in a container. It can be used to
/// open the container independently from each task (e.g. if no MPI is
/// available or only a subset of tasks need access).
///
/// Using this function the meta data at the beginning of the container is
/// read by each task instead of just once and distributed (`sion_paropen_XYZ`).
/// `sion_open_rank()` only reads the meta data that pertains to the
/// selected logical file.
///
/// \warning Only read operations are currently supported.
///
/// \param[in] fname name of the container to open
/// \param[in] mode mode in which to open the container
/// \param[in] rank number of logical file to open in the container
/// \param[in] options provide additional options, or `NULL`
///
/// \returns a handle to the open file or -1 in case an error occurred
int sion_open_rank(const char *fname, sion_open_mode mode, int rank, const sion_rank_options *options);

/// \brief Close a SIONlib file.
///
/// This function closes a SIONlib file which was opened in serial mode with
/// `sion_open()` or `sion_open_rank()`. In write mode this function will
/// also save all meta data to the meta data block of the SIONlib file.
///
/// The function is a task local function, which can be called
/// independently from other MPI tasks.
///
/// \param[in] sid SIONlib file handle
///
/// \returns SION_SUCCESS if close is ok
int sion_close(int sid);

/// \brief Allocates and initializes an instance of `sion_options`
///
/// \returns a pointer to the new instance or `NULL` if allocation failed
sion_options *sion_options_new(void);

/// \brief Delete an instance of `sion_options`
///
/// \param[in] options a pointer to the instance to delete
void sion_options_delete(sion_options *options);

/// \brief Set the chunk sizes of all logical files in the container
///
/// \param[in,out] options an options object
/// \param[in] n number of logical files in the container
/// \param[in] chunksizes chunk sizes for all logical files in the container
void sion_options_set_chunksizes(sion_options *options, int n, const int64_t chunksizes[]);

/// \brief Set the file system block size to assume.
///
/// \param[in,out] options an options object
/// \param[in] fsblksize the file system block size
void sion_options_set_fsblksize(sion_options *options, int32_t fsblksize);

/// \brief Set the key-value mode to use for a container.
///
/// \param[in,out] options an options object
/// \param[in] keyval_mode the key-value mode to use
void sion_options_set_keyval_mode(sion_options *options, sion_keyval_mode keyval_mode);

/// \brief Set the low-level API to use for opening a container.
///
/// \param[in,out] options an options object
/// \param[in] lowlevel_api the low-level API to use
void sion_options_set_lowlevel_api(sion_options *options, sion_lowlevel_api lowlevel_api);

/// \brief Set the endianness for the contents of a container
///
/// \param[in,out] options an options object
/// \param[in] endianness the endianness of the contents
void sion_options_set_endianness(sion_options *options, sion_endianness endianness);

/// \brief Allocates and initializes an instance of `sion_rank_options`
///
/// \returns a pointer to the new instance or `NULL` if allocation failed
sion_rank_options *sion_rank_options_new(void);

/// \brief Delete an instance of `sion_rank_options`
///
/// \param[in] options a pointer to the instance to delete
void sion_rank_options_delete(sion_rank_options *options);

/// \brief Set the low-level API to use for opening a container.
///
/// \param[in,out] options an options object
/// \param[in] lowlevel_api the low-level API to use
void sion_rank_options_set_lowlevel_api(sion_rank_options *options, sion_lowlevel_api lowlevel_api);

#ifdef __cplusplus
}
#endif

/// @}

#endif
