/****************************************************************************
**  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_FILE_H
#define SION_SION_FILE_H

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

#define SION_FILE_FLAG_ANSI 1 /*!< ANSI fileptr available */
#define SION_FILE_FLAG_POSIX 4 /*!< POSIX file pointer available */
#define SION_FILE_FLAG_CREATE 8 /*!< create file */
#define SION_FILE_FLAG_WRITE 16 /*!< write mode */
#define SION_FILE_FLAG_READ 32 /*!< read mode */

struct _sion_fileptr_s {
  unsigned int flags;
  FILE *fileptr;
  int fd;
};
typedef struct _sion_fileptr_s _sion_fileptr;

/* open/close */
/*!\brief Create and open a new file for writing
 *
 * @param  fname               filename to use
 * @param  flags               flags
 * @param  addflags            optional additional flags
 *
 * @return file handle, or `NULL` on error
 */
_sion_fileptr *_sion_file_open(const char *fname, unsigned int flags, unsigned int addflags);

/*!\brief Close file and destroys fileptr structure
 *
 * @param[in,out]  sion_fileptr  file handle
 *
 * @return `SION_SUCCESS` if success
 */
int _sion_file_close(_sion_fileptr *sion_fileptr);

/* write/read */
/*!\brief Write data to file
 *
 * @param  data                 pointer to data
 * @param  bytes                number of bytes to write
 * @param  sion_fileptr         file handle
 *
 * @return returns `bytes` if the requested amount could be written, otherwise `-1`
 */
int64_t _sion_file_write(const void *data, int64_t bytes, _sion_fileptr *sion_fileptr);

/*!\brief Read data from file
 *
 * @param  data                 pointer to data
 * @param  bytes                number of bytes to write
 * @param  sion_fileptr         file handle
 *
 * @return returns `bytes` if the requested amount could be read,
 *         on EOF, returns `n` with `0 <= n < bytes`,
 *         otherwise `-1`
 */
int64_t _sion_file_read(void *data, int64_t bytes, _sion_fileptr *sion_fileptr);

/* utility */
/*!\brief Get optional file system block size for a file
 *
 * @param  fileptr  fileptr
 *
 * @return blocksize or `-1` if not defined
 */
long _sion_file_get_opt_blksize(_sion_fileptr *fileptr);

/*!\brief Check if file exists  (LARGE_FILE support on BlueGene)
 *
 * @param  *fname               filename to use
 *
 * @return `0` or `1`
 */
int _sion_file_stat_file(const char *fname);

/*!\brief Set new position in file
 *
 * @param  fileptr         fileptr
 * @param  startpointer         new position
 *
 * @return new position in file or `-1` on failure
 */
int64_t _sion_file_set_position(_sion_fileptr *fileptr, int64_t startpointer);

/*!\brief Get new position in file
 *
 * @param  fileptr  fileptr
 *
 * @return position in file or `-1` on failure
 */
int64_t _sion_file_get_position(_sion_fileptr *fileptr);

/*!\brief Flush data to file
 *
 * @param  fileptr  fileptr
 *
 * @return  `SION_SUCCESS` if ok
 */
int _sion_file_flush(_sion_fileptr *fileptr);

/*!\brief Set buffer of fp.
 *
 * @param  *fileptr        file handle
 * @param  *buffer              pointer buffer
 * @param  *buffer_size         buffer size
 *
 * @retval `SION_SUCCESS` if OK
 */
int _sion_file_set_buffer(_sion_fileptr *fileptr, char *buffer, int32_t buffer_size);

/*!\brief Utility function: Get POSIX fp
 *
 * @param  sion_fileptr         file handle
 *
 * @return a POSIX file descriptor or `SION_ID_UNDEF` on failure
 */
int _sion_file_get_fd(_sion_fileptr *sion_fileptr);

/* ********************************************************************************************** */
/* *** Internal INTERFACE Functions (ANSI, POSIX)                                                 */
/* ********************************************************************************************** */
/*!\brief ANSI: Create and open a new file for writing
 *
 * @param  *fname               filename to use
 * @param  addflags             optional additional flags
 *
 * @return file handle or `NULL`
 */
FILE *_sion_file_open_ansi_write_create(const char *fname, unsigned int addflags);

/*!\brief ANSI: Open a new file for writing
 *
 * @param  *fname               filename to use
 * @param  addflags             optional additional flags
 *
 * @return file handle or `NULL`
 */
FILE *_sion_file_open_ansi_write_existing(const char *fname, unsigned int addflags);

/*!\brief ANSI: Open a file for reading
 *
 * @param  *fname               filename to use
 * @param  addflags             optional additional flags
 *
 * @return file handle or `NULL`
 */
FILE *_sion_file_open_ansi_read(const char *fname, unsigned int addflags);

/*!\brief ANSI: Close a file
 *
 * @param  *fileptr             ANSI file pointer
 *
 * @return `SION_SUCCESS` or `SION_NOT_SUCCESS`
 */
int _sion_file_close_ansi(FILE *fileptr);

/*!\brief ANSI: Get optional file system block size for a file
 *
 * @param  fileptr  fileptr
 *
 * @return  blocksize or `-1` if not defined
 */
long _sion_file_get_opt_blksize_ansi(FILE *fileptr);

/*!\brief ANSI: Set the start position for the current task
 *
 * @param  *fileptr                     file handle
 * @param  startpointer         the position for the current task
 *
 * @return  new position in file, `-1` on failure
 */
int64_t _sion_file_set_position_ansi(FILE *fileptr, int64_t startpointer);

/*!\brief ANSI: Get the current position in file
 *
 * @param  *fileptr                     file handle
 *
 * @retval position in file, `-1` on failure
 */
int64_t _sion_file_get_position_ansi(FILE *fileptr);

/*!\brief ANSI: Flush the data to the disk
 *
 * @param  *fileptr             file handle
 *
 * @retval `SION_SUCCESS` if OK
 */
int _sion_file_flush_ansi(FILE *fileptr);

/*!\brief ANSI: set buffer of fp
 *
 * @param  *fileptr             file handle
 * @param  *buffer              pointer buffer
 * @param  *buffer_size         buffer size
 *
 * @retval `SION_SUCCESS` if OK
 */
int _sion_file_set_buffer_ansi(FILE *fileptr, char *buffer, int32_t buffer_size);

/*!\brief ANSI: Write data to file
 *
 * @param  data                 pointer to data
 * @param  bytes                number of bytes to write
 * @param  fileptr              file handle
 *
 * @return returns `bytes` if the requested amount could be written, otherwise `-1`
 */
int64_t _sion_file_write_ansi(const void *data, int64_t bytes, FILE *fileptr);

/*!\brief ANSI: Read data from file
 *
 * @param  data                 pointer to data
 * @param  bytes                number of bytes to read
 * @param  fileptr              file handle
 *
 * @return returns `bytes` if the requested amount could be read,
 *         on EOF, returns `n` with `0 <= n < bytes`,
 *         otherwise `-1`
 */
int64_t _sion_file_read_ansi(void *data, int64_t bytes, FILE *fileptr);

/*!\brief POSIX: Create and open a new file for writing
 *
 * @param  *fname               filename to use
 * @param  addflags             optional additional flags
 *
 * @return file handle or `-1` on failure
 */
int _sion_file_open_posix_write_create(const char *fname, unsigned int addflags);

/*!\brief POSIX: Open a new file for writing
 *
 * @param  *fname               filename to use
 * @param  addflags             optional additional flags
 *
 * @return file handle or `-1` on failure
 */
int _sion_file_open_posix_write_existing(const char *fname, unsigned int addflags);

/*!\brief POSIX: Open a file for reading
 *
 * @param  *fname               filename to use
 * @param  addflags             optional additional flags
 *
 * @return file handle or `-1` on failure
 */
int _sion_file_open_posix_read(const char *fname, unsigned int addflags);

/*!\brief POSIX: Close a file
 *
 * @param  fd                   POSIX file pointer
 *
 * @return `SION_SUCCESS` or `SION_NOT_SUCCESS`
 */
int _sion_file_close_posix(int fd);

/*!\brief POSIX: Get optional file system block size for a file
 *
 * @param  fd  file descriptor
 *
 * @return  blocksize or `-1` if not defined
 */
long _sion_file_get_opt_blksize_posix(int fd);

/*!\brief POSIX: Set the start position for the current task
 *
 * @param  fd                   file descriptor
 * @param  startpointer         the position for the current task
 *
 * @return  new position in file, `-1` on failure
 */
int64_t _sion_file_set_position_posix(int fd, int64_t startpointer);

/*!\brief POSIX: Get the current position in file
 *
 * @param  fd                           file handle
 *
 * @retval position in file or `-1` on failure
 */
int64_t _sion_file_get_position_posix(int fd);

/*!\brief POSIX: Flush the data to the disk
 *
 * @param  fd  file descriptor
 *
 * @retval `SION_SUCCESS` if OK
 */
int _sion_file_flush_posix(int fd);

/*!\brief POSIX: set buffer of fd
 *
 * @param  fd                   file descriptor
 * @param  *buffer              pointer buffer
 * @param  *buffer_size         buffer size
 *
 * @retval `SION_SUCCESS` if OK
 */
int _sion_file_set_buffer_posix(int fd, char *buffer, int32_t buffer_size);

/*!\brief POSIX: Write data to file
 *
 * @param  data                 pointer to data
 * @param  bytes                number of bytes to write
 * @param  fd                   file handle
 *
 * @return returns `bytes` if the requested amount could be written, otherwise `-1`
 */
int64_t _sion_file_write_posix(const void *data, int64_t bytes, int fd);

/*!\brief POSIX: Read data from file
 *
 * @param  data                 pointer to data
 * @param  bytes                number of bytes to read
 * @param  fd                   file handle
 *
 * @return returns `bytes` if the requested amount could be read,
 *         on EOF, returns `n` with `0 <= n < bytes`,
 *         otherwise `-1`
 */
int64_t _sion_file_read_posix(void *data, int64_t bytes, int fd);

/* ********************************************************************************************** */
/* *** Internal Utility Functions                                                                 */
/* ********************************************************************************************** */
_sion_fileptr *_sion_file_alloc_and_init_sion_fileptr(void);
char *_sion_get_fileptr_desc(_sion_fileptr *sion_fileptr);

#endif

/// \endcond
