/****************************************************************************
**  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_FILEDESC_H
#define SION_SION_FILEDESC_H

#include <stdint.h>

#include "sion_file.h"

#define _SION_FLAG1_NONE 0 /*!< Flag1 not used */
#define _SION_FLAG2_NONE 0 /*!< Flag2 not used */

#define SION_FILESTATE_UNKNOWN -1 /*!< Unknown file state(error) */
#define SION_FILESTATE_PAROPEN 0 /*!< File opened in parallel */
#define SION_FILESTATE_SEROPEN 1 /*!< File opened in serial */
#define SION_FILESTATE_SEROPENRANK 2 /*!< File opened in serial for a specific rank */
#define SION_FILESTATE_SEROPENMASTER 3 /*!< File opened in serial, master  */
#define SION_FILESTATE_PAROPENMAPPEDMASTER 4 /*!< File opened in parallel with mapping task, master */
#define SION_FILESTATE_PAROPENMAPPEDMANAGED 5 /*!< File opened in parallel with mapping task and managed by this tasks */
#define SION_FILESTATE_PAROPENMAPPED 6 /*!< File opened in parallel with mapping task and managed by other tasks */
#define SION_FILESTATE_CLOSE 10 /*!< File closed */
#define SION_FILEMODE_UNKNOWN -20 /*!< File mode unknown (error) */
#define SION_FILEMODE_READ 20 /*!< File opened for reading */
#define SION_FILEMODE_WRITE 30 /*!< File opened for writing */

#define SION_DESCSTATE_ORIG 200 /*!< data structure is NOT a duplicate of another data structure */
#define SION_DESCSTATE_DUP 201 /*!< data structure is a duplicate of another data structure */
#define SION_DESCSTATE_DUP_SEL_RANK 202 /*!< data structure is a duplicate of another data structure, only for one rank */
#define SION_DESCSTATE_DUP_SEL_RANK_KEY \
  203 /*!< data structure is a duplicate of another data structure, only for one rank and one key */

#define SION_HINTS_TYPE_UNKNOWN 160 /*!< use hints of type UNKNOWN */
#define SION_HINTS_TYPE_LINUX 161 /*!< use hints for Linux filessystem */
#define SION_HINTS_TYPE_GPFS 162 /*!< use hints for GPFS filessystem */

#define SION_CAPABILITY_FULL 50 /*!< Capability of a task in collective mode */
#define SION_CAPABILITY_ONLY_SENDER 51 /*!< Capability of a task in collective mode */
#define SION_CAPABILITY_NONE 52 /*!< Capability of a task in collective mode */

#define _SION_DEBUG_PRINT_ALL 1
#define _SION_DEBUG_PRINT_RECURSIVE 2

struct _sion_filedesc_struct;

/*!
 * @brief SION File Descriptor Alias
 */
typedef struct _sion_filedesc_struct _sion_filedesc;

/*!
 * \struct _sion_filedesc_struct
 * \brief Sion File Descriptor Structure
 *
 * The sion file descriptor structure stores all the properties for the sion file.
 * This properties are the META data of a sion file
 *
 * DO NOT change types of elements, becauses these are directly used to read/write header
 *
 * CHUNK: reserved space for each rank, each rank can have serveral chunks in a file
 *
 * BLOCK: used space in a CHUNK
 */
struct _sion_filedesc_struct {
  /* file pointer and temporary data */
  _sion_fileptr *fileptr; /*!< Pointer to the current sion file */
  void *dataptr; /*!< pointer to data structure for upper layers */
  void *keyvalptr; /*!< pointer to data structure for key-value */
  int32_t debug; /*!< 0 or 1 for debugging */
  int32_t sid; /*!< sid of data structure */
  char *fpbuffer; /*!< buffer for optimizing ANSI C I/O function fwrite/fread */
  int32_t fpbuffer_size; /*!< buffer size */
  int32_t usebuffer; /*!< is set to 1 if data is/should be buffered internally in sion_fwrite/sion_fread */
  char *buffer; /*!< buffer for internal buffering data in sion_fwrite/sion_fread */
  int32_t buffer_size; /*!< buffer size */
  int32_t buffer_ptr; /*!< index of the first free byte in buffer */

  /* current position in file */
  int32_t rank; /*!< Rank of the task writing the file (global rank) */
  int64_t currentpos; /*!< only used if opened  for one rank, reading */
  int32_t currentblocknr; /*!< only used if opened  for one rank, reading */

  /* data for one task  */
  int64_t *blocksizes; /*!< Array of the blocksizes in all chunks of the current task */
  int32_t lastchunknr; /*!< number of last chunk used on this task (0..n) */
  int64_t size; /*!< number of bytes in this logical file */
  int64_t startpos; /*!< Start position for the current task, start of first chunk (fix for task) */

  /* meta header data in file */
  char *fname; /*!< Name of the file */
  int32_t globalrank; /*!< Globalrank of the task given by parameter or implicitly */
  int32_t ntasks; /*!< Number of tasks using the sion file */
  int32_t state; /*!< INTERNAL STATE */
  int32_t mode; /*!< Mode used to open the file(rb/wb) */
  int32_t endianness; /*!< Endianness used. Written symmetric.
                                     First (and last) byte indicates meta data.
                                     Second (and second last) byte indicates
                                     user data. 0 = little, 1 = big */
  int32_t swapbytes; /*!< swapping bytes is needed for this sion file  */
  int32_t filesionversion; /*!< Version number of library which wrote sion file (version*100+sub_version) */
  int32_t filesionpatchlevel; /*!< patch-level of library which wrote sion file */
  int32_t fileversion; /*!< Version number of sion file format */
  int32_t fsblksize; /*!< Filesystem block size */
  int32_t maxchunks; /*!< Max number of chunks per task */
  int64_t flag1; /*!< keyval-mode since file format version 5 */
  int64_t flag2; /*!< placeholder for future flags */
  int64_t chunksize; /*!< chunksize for the current task(From Meta block 1) */
  int64_t chunksize_req; /*!< Requested chunksize for the current task */
  int64_t globalskip; /*!< number of bytes to skip to next block of same rank */
  int64_t end_of_header; /*!< End of META block 1 (beginning of the sion file) */
  int64_t start_of_varheader; /*!< Beginning of the META block 2 (end of the sion file) */
  int64_t start_of_data; /*!< Start of the data in the sion file */
  int32_t nfiles; /*!< Number of files in the set */
  int32_t filenumber; /*!< file number in the set */
  int32_t maxusedchunks; /*!< Max number of chunks per task already used by the tasks */

  /* dupped filedesc */
  int32_t dup_mode; /*!< dup mode; used to indicate if datastructure was duplicated from another one */
  int32_t dup_sel_rank; /*!< Used to indicate if datastructure was duplicated from another one */
  uint64_t dup_sel_key; /*!< Used to indicate if datastructure was duplicated from another one */

  /* mapped files */
  int32_t lrank; /*!< local rank, needed to omit re-computation of mapping */
  int32_t ntotaltasksinfile; /*!< total number of  tasks in this the sion file (mapped-mode) */
  int32_t nlocaltasksinfile; /*!< number of local tasks in this the sion file (mapped-mode) */
  int32_t filemanagedbytask; /*!< task number of managing task of this the sion file (mapped-mode) */

  /* all tasks */
  int64_t *all_chunksizes; /*!< list of all chunk sizes stored in this file */
  int64_t *all_globalranks; /*!< list of all globalranks stored in this file  */
  int64_t *all_localranks; /*!< list of all localranks stored in this file  */
  int64_t *all_startpointers; /*!< list of all start pointers stored in this file  */
  int64_t *all_currentpos; /*!< only used if sion is opened from a single task for read  */
  int64_t *all_currentblocknr; /*!< only used if sion is opened from a single task for read  */
  int32_t *all_coll_collector; /*!< only used on rank 0 if usecoll=1  */
  int32_t *all_coll_collsize; /*!< only used on rank 0 if usecoll=1  */
  int32_t *all_coll_capability; /*!< capability of task (FULL, ONLYSENDER)  */

  void **all_keyvalptr; /*!< keyval data structure for each task */

  /* all tasks, all chunks */
  int64_t *all_blockcount; /*!< size, only used if sion is opened from a single task for read  */
  int64_t *all_blocksizes; /*!< size*maxblocks, only used if sion is opened from a single task for read  */
  int64_t *all_sizes; /*!< numbers of bytes in all logical files */

  /* multi-file */
  int32_t mapping_size; /*!< size of mapping table, -1 if not available */
  int32_t *mapping; /*!< pointer to mapping table if reading multi file */
  _sion_filedesc **multifiles; /*!< pointer to field containing data structures of sion files of a sion multi-file */

  /* compression */
  int32_t compress; /*!< is set to 1 if data should be/is compressed */

  /* Key-value */
  int32_t keyvalmode; /*!< describes if and in which mode keyval will be used  */

  /* collective I/O */
  int32_t usecoll; /*!< is set to 1 if collective operation should be used for I/O */
  int32_t collsize; /*!< number of tasks working together (for this task) */
  int32_t collector; /*!< tasks number of corresponding collector */
  int32_t coll_capability; /*!< capability of task (FULL, ONLYSENDER)  */
  int32_t colldebug; /*!< print debug info on stderr, i level of detail, 0->off  */
  int32_t collcmdused; /*!< indicates if collective call was already performed */
  int32_t collmergemode; /*!< merge data on collector task */

  /* buddy */
  int32_t usebuddy; /*!< is set to 1 if buddy mode is selected */
  int32_t buddylevel; /*!< buddy level (number of copies) */
  int32_t buddynr; /*!< number of buddy file, 0 for original file  */
  void *buddies; /*!< pointer to payload container structure describing buddies */

  /* hints */
  int32_t usehints; /*!< is set to 1 if hints should be applied */
  int32_t hinttype; /*!< type of hints */
};

/*!\brief Allocates memory for internal sion structure
 *
 * @retval      pointer to a new sion_filedesc structure
 */
_sion_filedesc *_sion_alloc_filedesc(void);

/*!\brief Initialize the sion file description
 *
 * @param *sion_filedesc        sion file description struct (_sion_filedesc)
 *
 * @retval      SION_SUCCESS if OK
 */
int _sion_init_filedesc(_sion_filedesc *sion_filedesc);

/*!\brief Print the initialized sion file description
 *
 * @retval      SION_SUCCESS if OK
 */
int _sion_print_filedesc(_sion_filedesc *sion_filedesc, int level, char *desc, int all);
int _sion_free_filedesc(_sion_filedesc *sion_filedesc);

/*!\brief Increase the memory used by the internal sion structure for the blocklist
 *
 * @param  *sion_filedesc                       sion file description struct (_sion_filedesc)
 * @param  maxchunks                            maximum number of chunks written by all tasks
 *
 * @retval      SION_SUCCESS if OK
 */
int _sion_realloc_filedesc_blocklist(_sion_filedesc *sion_filedesc, int32_t maxchunks);

int _sion_alloc_filedesc_all_chunksizes(_sion_filedesc *sion_filedesc);
int _sion_alloc_filedesc_all_sizes(_sion_filedesc *sion_filedesc);
int _sion_alloc_filedesc_all_startpointers(_sion_filedesc *sion_filedesc);
int _sion_alloc_filedesc_all_globalranks(_sion_filedesc *sion_filedesc);
int _sion_alloc_filedesc_all_localranks(_sion_filedesc *sion_filedesc);

/*!\brief Allocate memory for the internal sion arrays
 *
 * @param  *sion_filedesc                       sion file description struct (_sion_filedesc)
 *
 * @retval      SION_SUCCESS if OK
 */
int _sion_alloc_filedesc_arrays(_sion_filedesc *sion_filedesc);
int _sion_alloc_filedesc_all_keyvalptr(_sion_filedesc *sion_filedesc);

/*!\brief free memory for the internal sion arrays
 *
 * @param  *sion_filedesc                       sion file description struct (_sion_filedesc)
 *
 * @retval      SION_SUCCESS if OK
 */
int _sion_free_filedesc_arrays(_sion_filedesc *sion_filedesc);
int _sion_free_filedesc_all_chunksizes(_sion_filedesc *sion_filedesc);
int _sion_free_filedesc_all_sizes(_sion_filedesc *sion_filedesc);
int _sion_free_filedesc_all_globalranks(_sion_filedesc *sion_filedesc);
int _sion_free_filedesc_all_startpointers(_sion_filedesc *sion_filedesc);
int _sion_free_filedesc_all_localranks(_sion_filedesc *sion_filedesc);
int _sion_free_filedesc_all_keyvalptr(_sion_filedesc *sion_filedesc);

/*!\brief Allocate memory for the internal sion structure, fields for all chunksizes of all tasks
 *
 * @param  *sion_filedesc                       sion file description struct (_sion_filedesc)
 *
 * @retval      SION_SUCCESS if OK
 */
int _sion_alloc_filedesc_block_arrays(_sion_filedesc *sion_filedesc);

/*!\brief Allocate memory for the internal sion structure, fields for all chunksizes of all tasks
 *
 * @param  *sion_filedesc                       sion file description struct (_sion_filedesc)
 *
 * @retval      SION_SUCCESS if OK
 */
int _sion_alloc_filedesc_block_arrays_only(_sion_filedesc *sion_filedesc);

/*!\brief Allocate memory for the internal sion arrays
 *
 * @param  *sion_filedesc                       sion file description struct (_sion_filedesc)
 *
 * @retval      SION_SUCCESS if OK
 */
int _sion_alloc_filedesc_coll_arrays(_sion_filedesc *sion_filedesc);

/*!\brief free memory for the internal sion arrays
 *
 * @param  *sion_filedesc                       sion file description struct (_sion_filedesc)
 *
 * @retval      SION_SUCCESS if OK
 */
int _sion_free_filedesc_coll_arrays(_sion_filedesc *sion_filedesc);

int _sion_alloc_filedesc_arrays_mapped(_sion_filedesc *sion_filedesc);
int _sion_alloc_filedesc_block_arrays_mapped(_sion_filedesc *sion_filedesc);

/*!\brief get size of internal data structure sion_filedesc
 *
 * @param  *sion_filedesc   sion file description struct (_sion_filedesc)
 * @param  *numbytes        int, number of bytes allcated for that data structure
 * @param  *numfds          int, number of open file descriptors
 */
int _sion_get_size_of_filedesc(_sion_filedesc *sion_filedesc, int *numbytes, int *numfds);

/*!\brief duplicates a filedesc data structure, not copying/reopen active file pointers
 *
 * @param  *sion_filedesc                       sion file description struct (_sion_filedesc)
 * @retval      ptr to a copy of sion_filedesc, or NULL if fails
 */
_sion_filedesc *_sion_dup_filedesc(_sion_filedesc *sion_filedesc);

#endif

/// \endcond
