/* 
 * ADIOS is freely available under the terms of the BSD license described
 * in the COPYING file in the top level directory of this source distribution.
 *
 * Copyright (c) 2008 - 2009.  UT-BATTELLE, LLC. All rights reserved.
 */

#include "../config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define __INCLUDED_FROM_FORTRAN_API__
#include "public/adios_read.h"
#include "public/adios_error.h"
//#include "core/bp_utils.h"
//#include "core/bp_types.h"
#include "core/common_read.h"
#include "core/futils.h"
#define BYTE_ALIGN 8

#ifdef DMALLOC
#include "dmalloc.h"
#endif

#ifdef __cplusplus
extern "C"  /* prevent C++ name mangling */
#endif

#ifdef BUILD_WITH_CMAKE
  #include "FC.h"
#endif

static enum ADIOS_READ_METHOD lastmethod = ADIOS_READ_METHOD_BP;

extern int adios_errno;

// Re-define the ADIOS_GROUP struct here, because we need to emulate the group view behavior
// of the old read API
typedef struct { 
    uint64_t gh;                /* Group handler                                           */
    int      grpid;             /* group index (0..ADIOS_FILE.groups_count-1)              */
    int      vars_count;        /* Number of variables in this adios group                 */
    char     ** var_namelist;   /* Variable names in a char* array                         */
    int      attrs_count;       /* Number of attributes in this adios group                */
    char     ** attr_namelist;  /* Attribute names in a char* array                        */
    ADIOS_FILE * fp;            /* pointer to the parent ADIOS_FILE struct                 */
} ADIOS_GROUP_V1;

/*********************/
/* FORTRAN INTERFACE */
/*********************/
void FC_FUNC_(adios_errmsg, adios_errmsg) (char *msg, int msg_len)
{
    futils_cstr_to_fstr( adios_get_last_errmsg(), (char *)msg, msg_len);
}

void FC_FUNC_(adios_set_read_method, ADIOS_SET_READ_METHOD) (int *fmethod, int *err)
{
    enum ADIOS_READ_METHOD method = (enum ADIOS_READ_METHOD) *fmethod;
    switch (*fmethod) {
        // Translate from V1 method IDs to the new API's methods
        case 0: //ADIOS_READ_METHOD_BP_V1:
            lastmethod = ADIOS_READ_METHOD_BP;
            break;
        case 1: //ADIOS_READ_METHOD_BP_STAGED_V1:
            lastmethod = ADIOS_READ_METHOD_BP_AGGREGATE;
            break;
        case 7: //ADIOS_READ_METHOD_BP_STAGED1_V1:
            lastmethod = ADIOS_READ_METHOD_BP_AGGREGATE;
            break;
        case 3: //ADIOS_READ_METHOD_DART_V1:
            lastmethod = ADIOS_READ_METHOD_DATASPACES;
            break;
        case 4: //ADIOS_READ_METHOD_DIMES_V1:
            lastmethod = ADIOS_READ_METHOD_DIMES;
            break;

            /* Unsupported methods */
        case 2: //ADIOS_READ_METHOD_HDF5_V1:
        case 5: //ADIOS_READ_METHOD_NSSI_V1:
        case 6: //ADIOS_READ_METHOD_DATATAP_V1:
        default:
            lastmethod = ADIOS_READ_METHOD_BP;
            break;
    }
    *err = 0;
}

void FC_FUNC_(adios_read_init, ADIOS_READ_INIT) (int * fcomm, int * err)
{
    MPI_Comm comm = MPI_Comm_f2c (*((int *) fcomm));
    futils_called_from_fortran_set();
    *err =  common_read_init_method (lastmethod, comm, NULL);
    if (*err)
        fprintf(stderr, "Error: %s\n", adios_get_last_errmsg());
}

void FC_FUNC_(adios_read_finalize, ADIOS_READ_FINALIZE) (int * err)
{
    *err = common_read_finalize_method (lastmethod);
    futils_called_from_fortran_unset();
    if (*err)
        fprintf(stderr, "Error: %s\n", adios_get_last_errmsg());
}

void FC_FUNC_(adios_fopen, ADIOS_FOPEN)
        (int64_t * fp,
         char    * fname,
         void    * fcomm,
         int     * groups_count,
         int     * err,
         int       fname_len)
{
    ADIOS_FILE *afp;
    char *namestr;
    char **group_namelist;
    MPI_Comm comm = MPI_Comm_f2c (*((int *) fcomm));
    futils_called_from_fortran_set();

    namestr = futils_fstr_to_cstr(fname, fname_len);
    if (namestr != NULL) {
        afp = common_read_open_file (namestr, lastmethod, comm);
        if (afp != NULL) {
            *groups_count = common_read_get_grouplist(afp, &group_namelist);
        } else {
            *groups_count = 0;
        }
        *fp = (int64_t) afp;
        free(namestr);
    } else {
        *fp = (int64_t) NULL;
    }
    *err = adios_errno;
    if (*err)
        fprintf(stderr, "Error: %s\n", adios_get_last_errmsg());
}

void FC_FUNC_(adios_reset_dimension_order, ADIOS_RESET_DIMENSION_ORDER)
        (int64_t * fp,
         int * flag)
{
    ADIOS_FILE *afp = (ADIOS_FILE *) *fp;
    common_read_reset_dimension_order(afp, *flag);
}

void FC_FUNC_(adios_fclose, ADIOS_FCLOSE) (int64_t * fp, int * err)
{
    ADIOS_FILE *afp = (ADIOS_FILE *) *fp;
    *err = common_read_close (afp);
    futils_called_from_fortran_unset();
    if (*err)
        fprintf(stderr, "Error: %s\n", adios_get_last_errmsg());
}

void FC_FUNC_(adios_inq_file, ADIOS_INQ_FILE) 
        (int64_t * fp,
         int     * vars_count,
         int     * attrs_count,
         int     * tstart,
         int     * ntsteps,
         void    * gnamelist,
         int     * err,
         int       gnamelist_len)
{
    ADIOS_FILE *afp = (ADIOS_FILE *) *fp;
    int i;
    char **group_namelist;
    int ngroups;
    if (afp != NULL) {
        *vars_count = afp->nvars;
        *attrs_count = afp->nattrs;
        *tstart = 1;
        *ntsteps = afp->last_step-afp->current_step+1;
        ngroups = common_read_get_grouplist(afp, &group_namelist);
        for (i=0;i<ngroups;i++) {
            futils_cstr_to_fstr( group_namelist[i], (char *)gnamelist+i*gnamelist_len, gnamelist_len);
        }
        *err = 0;
    } else {
        *vars_count = 0;
        *attrs_count = 0;
        *tstart = 0;
        *ntsteps = 0;
        *err = 1;
    }
}

void FC_FUNC_(adios_gopen, ADIOS_GOPEN) 
        (int64_t * fp,
         int64_t * gp,
         char    * grpname,
         int     * vars_count, 
         int     * attrs_count, 
         int     * err,
         int       grpname_len)
{
    char *namestr;
    ADIOS_FILE *afp = (ADIOS_FILE *) *fp;
    char **group_namelist;
    int ngroups, grpid;

    namestr = futils_fstr_to_cstr(grpname, grpname_len);
    if (namestr != NULL) {

        // get group list and find the group name 
        ngroups = common_read_get_grouplist(afp, &group_namelist);
        for (grpid=0;grpid<(ngroups);grpid++) {
            if (!strcmp(group_namelist[grpid], namestr))
                break;
        }

        if (grpid < ngroups) {

            // Set group view of file for this group
            common_read_group_view (afp, grpid);

            *vars_count = afp->nvars;
            *attrs_count = afp->nattrs;
            *gp = (int64_t)afp;
        } else {
            adios_error ( err_invalid_group, "Invalid group name %s", grpname);
            *gp = (int64_t) NULL;
        }
        free(namestr);

    } else {
        *gp = (int64_t) NULL;
    }
    *err = adios_errno;
    if (*err)
        fprintf(stderr, "Error: %s\n", adios_get_last_errmsg());
}

void FC_FUNC_(adios_gclose, ADIOS_GCLOSE) (int64_t * gp, int * err)
{
    ADIOS_FILE *afp = (ADIOS_FILE *) *gp;
    // restore full file view
    *err=common_read_group_view (afp, -1);
    if (*err)
        fprintf(stderr, "Error: %s\n", adios_get_last_errmsg());
}

void FC_FUNC_(adios_inq_group, ADIOS_INQ_GROUP)
        (int64_t * gp, 
         void    * vnamelist, 
         void    * anamelist,
         int     * timestep,
         int     * lasttimestep,
         int     * err, 
         int       vnamelist_len, 
         int       anamelist_len) 
{
    ADIOS_FILE *afp = (ADIOS_FILE *) *gp;
    int i;
    if (afp != NULL) {
        for (i=0;i<afp->nvars;i++) {
            futils_cstr_to_fstr( afp->var_namelist[i], (char *)vnamelist+i*vnamelist_len, vnamelist_len);
        } 
        for (i=0;i<afp->nattrs;i++) {
            futils_cstr_to_fstr( afp->attr_namelist[i], (char *)anamelist+i*anamelist_len, anamelist_len);
        } 
        *timestep = 1;
        *lasttimestep = afp->last_step;
        *err = 0;
    } else {
        *err = 1;
    }
}

void FC_FUNC_(adios_inq_var, ADIOS_INQ_VAR) 
        (int64_t  * gp, 
         char     * varname,
         int      * type,
         int      * ndim,
         uint64_t * dims,
         int      * timedim,
         int      * err,
         int        varname_len)
{
    char *varstr;
    int  i;
    ADIOS_FILE *afp = (ADIOS_FILE *) *gp;
    ADIOS_VARINFO *vi = NULL;

    varstr = futils_fstr_to_cstr(varname, varname_len);
    if (varstr != NULL) {
        vi = common_read_inq_var (afp, varstr);
    }
    if (vi != NULL) {
        *type = vi->type;

        /* TIME dimension should be emulated here !!! */  
        int tidx;
        int timed = common_read_is_var_timed(afp, vi->varid);
        if (timed) {
            *ndim = vi->ndim + 1;
            *timedim = vi->ndim;
            dims[0] = vi->nsteps;
            tidx = 1;
        } else {
            *ndim = vi->ndim;
            *timedim = -1;
            tidx = 0;
        }

        for (i=0; i<vi->ndim; i++)
            dims[i+tidx] = vi->dims[i];

        common_read_free_varinfo(vi);

    } else {
        *type = adios_unknown;
        *ndim = 0;
        *timedim = -1;
    }
    *err = adios_errno;
    if (*err < 0)
        fprintf(stderr, "Error: %s\n", adios_get_last_errmsg());
}

void FC_FUNC_(adios_read_var, ADIOS_READ_VAR) 
        (int64_t  * gp,
         char     * varname,
         uint64_t * start,
         uint64_t * count,
         void     * data,
         int64_t  * read_bytes,
         int varname_len)
{
    ADIOS_FILE *afp = (ADIOS_FILE *) *gp;
    char *varstr;
    int i;
    varstr = futils_fstr_to_cstr(varname, varname_len);
    if (varstr != NULL) {
        /* First get the number of dimensions of the variable */
        ADIOS_VARINFO * vi = common_read_inq_var (afp, varstr);
        if (!vi)  {
            *read_bytes = adios_errno;
            return;
        }
        int tidx;
        int from_step = 0, nsteps = 1;
        /* TIME dimension should be emulated here !!! */  
        int timed = common_read_is_var_timed(afp, vi->varid);
        if (timed) {
            from_step = (int) start[vi->ndim];
            nsteps    = (int) count[vi->ndim];
            tidx = 1;
        } else {
            tidx = 0;
        }

        ADIOS_SELECTION * sel = common_read_selection_boundingbox (vi->ndim, start, count);

        common_read_schedule_read (afp, sel, varstr, from_step, nsteps, data);
        int ret = common_read_perform_reads (afp, 1);
        if (ret == err_no_error) {
            /* should return the number of bytes read */
            *read_bytes = (int64_t) common_read_type_size (vi->type, data);
            *read_bytes *= nsteps;
            for (i=0; i<vi->ndim; i++) 
                *read_bytes *= (int64_t) count[i];
        } else {
            *read_bytes = (int64_t) adios_errno;
        }

        common_read_free_varinfo(vi);
        common_read_selection_delete(sel);
        free(varstr);
    } else {
        *read_bytes = adios_errno;
    }
    if (*read_bytes < 0)
        fprintf(stderr, "Error: %s\n", adios_get_last_errmsg());
}

void FC_FUNC_(adios_read_local_var, ADIOS_READ_LOCAL_VAR)
        (int64_t  * gp,
         char     * varname,
         int      * idx,
         uint64_t * start,
         uint64_t * count,
         void     * data,
         int64_t  * read_bytes,
         int varname_len)
{
    ADIOS_FILE *afp = (ADIOS_FILE *) *gp;
    ADIOS_VARINFO *vi = NULL;
    char *varstr;
    int i;
    varstr = futils_fstr_to_cstr(varname, varname_len);
    if (varstr != NULL) {
        /* The new API does not support reading write block with subselection.
           Only complete blocks can be read.
           Here we check if the passed selection equals the whole block.
           Otherwise we return an out of bound error, although it probably should
           be a "within bounds" error

           Version 1: 
           - start/count has no time dimension for the local read
           - idx is for all timesteps, 0...timesteps*blocks
           Version 2:
           - idx is from 0..blocks for each timestep
           - need to say which timestep
         */

        /* First get the number of dimensions of the variable */
        vi = common_read_inq_var (afp, varstr);
    }

    if (vi != NULL) {
        /* get step from the idx, and check validity of idx */
        int step = 0;
        int idx_in_step = *idx;
        step = 0;
        while (step < vi->nsteps && idx_in_step >= vi->nblocks[step]) {
            idx_in_step -= vi->nblocks[step];
            step++;
        }
        if (step == vi->nsteps) {
            adios_error (err_out_of_bound, "ADIOS ERROR: local "
                    "variable %s has only %d blocks in file. "
                    "Requested index %d\n", varstr, vi->sum_nblocks, idx);
            *read_bytes = adios_errno;
            return;
        }
        common_read_inq_var_blockinfo (afp, vi); // get info on each block

        /* check dimensions */
        for (i=0; i<vi->ndim; i++) {
            if (start[i] != 0 || count[i] != vi->blockinfo[*idx].count[i]) {
                adios_error (err_out_of_bound, "ADIOS ERROR: when reading a local "
                        "variable, only the whole block can be requested; subselections "
                        "are not allowed. Variable %s, block %d, dimension %d size is %lld, "
                        "requested %lld from offset %lld\n",
                        varstr, *idx, vi->blockinfo[*idx].count[i], count[i], start[i]);
                *read_bytes = adios_errno;
                return;
            }
        }

        ADIOS_SELECTION * sel = common_read_selection_writeblock (idx_in_step);

        common_read_schedule_read_byid (afp, sel, vi->varid, step, 1, data);
        int ret = common_read_perform_reads (afp, 1);
        if (ret == err_no_error) {
            /* should return the number of bytes read */
            *read_bytes = (int64_t) common_read_type_size (vi->type, data);
            for (i=0; i<vi->ndim; i++)
                *read_bytes *= (int64_t) count[i];
        } else {
            *read_bytes = (int64_t) adios_errno;
        }

        common_read_free_varinfo(vi);
        common_read_selection_delete(sel);
        free(varstr);

    } else {
        // return error from futils or inq_var
        *read_bytes = adios_errno;
    }

    if (*read_bytes < 0)
        fprintf(stderr, "Error: %s\n", adios_get_last_errmsg());
}

/* Specific function for each data type */
void FC_FUNC_(adios_read_var_int1, ADIOS_READ_VAR_INT1) (int64_t * gp, char * varname, uint64_t * start, uint64_t * count, void * data, int64_t * read_bytes, int varname_len) { FC_FUNC_(adios_read_var, ADIOS_READ_VAR) (gp, varname, start, count, data, read_bytes, varname_len); }
void FC_FUNC_(adios_read_var_int2, ADIOS_READ_VAR_INT2) (int64_t * gp, char * varname, uint64_t * start, uint64_t * count, void * data, int64_t * read_bytes, int varname_len) { FC_FUNC_(adios_read_var, ADIOS_READ_VAR) (gp, varname, start, count, data, read_bytes, varname_len); }
void FC_FUNC_(adios_read_var_int4, ADIOS_READ_VAR_INT4) (int64_t * gp, char * varname, uint64_t * start, uint64_t * count, void * data, int64_t * read_bytes, int varname_len) { FC_FUNC_(adios_read_var, ADIOS_READ_VAR) (gp, varname, start, count, data, read_bytes, varname_len); }
void FC_FUNC_(adios_read_var_int8, ADIOS_READ_VAR_INT8) (int64_t * gp, char * varname, uint64_t * start, uint64_t * count, void * data, int64_t * read_bytes, int varname_len) { FC_FUNC_(adios_read_var, ADIOS_READ_VAR) (gp, varname, start, count, data, read_bytes, varname_len); }
void FC_FUNC_(adios_read_var_real4, ADIOS_READ_VAR_REAL4) (int64_t * gp, char * varname, uint64_t * start, uint64_t * count, void * data, int64_t * read_bytes, int varname_len) { FC_FUNC_(adios_read_var, ADIOS_READ_VAR) (gp, varname, start, count, data, read_bytes, varname_len); }
void FC_FUNC_(adios_read_var_real8, ADIOS_READ_VAR_REAL8) (int64_t * gp, char * varname, uint64_t * start, uint64_t * count, void * data, int64_t * read_bytes, int varname_len) { FC_FUNC_(adios_read_var, ADIOS_READ_VAR) (gp, varname, start, count, data, read_bytes, varname_len); }
void FC_FUNC_(adios_read_var_char, ADIOS_READ_VAR_CHAR) (int64_t * gp, char * varname, uint64_t * start, uint64_t * count, void * data, int64_t * read_bytes, int varname_len) { FC_FUNC_(adios_read_var, ADIOS_READ_VAR) (gp, varname, start, count, data, read_bytes, varname_len); }
void FC_FUNC_(adios_read_var_complex8, ADIOS_READ_VAR_COMPLEX8) (int64_t * gp, char * varname, uint64_t * start, uint64_t * count, void * data, int64_t * read_bytes, int varname_len) { FC_FUNC_(adios_read_var, ADIOS_READ_VAR) (gp, varname, start, count, data, read_bytes, varname_len); }
void FC_FUNC_(adios_read_var_complex16, ADIOS_READ_VAR_COMPLEX16) (int64_t * gp, char * varname, uint64_t * start, uint64_t * count, void * data, int64_t * read_bytes, int varname_len) { FC_FUNC_(adios_read_var, ADIOS_READ_VAR) (gp, varname, start, count, data, read_bytes, varname_len); }
void FC_FUNC_(adios_read_var_logical1, ADIOS_READ_VAR_LOGICAL1) (int64_t * gp, char * varname, uint64_t * start, uint64_t * count, void * data, int64_t * read_bytes, int varname_len) { FC_FUNC_(adios_read_var, ADIOS_READ_VAR) (gp, varname, start, count, data, read_bytes, varname_len); }
void FC_FUNC_(adios_read_var_logical2, ADIOS_READ_VAR_LOGICAL2) (int64_t * gp, char * varname, uint64_t * start, uint64_t * count, void * data, int64_t * read_bytes, int varname_len) { FC_FUNC_(adios_read_var, ADIOS_READ_VAR) (gp, varname, start, count, data, read_bytes, varname_len); }
void FC_FUNC_(adios_read_var_logical4, ADIOS_READ_VAR_LOGICAL4) (int64_t * gp, char * varname, uint64_t * start, uint64_t * count, void * data, int64_t * read_bytes, int varname_len) { FC_FUNC_(adios_read_var, ADIOS_READ_VAR) (gp, varname, start, count, data, read_bytes, varname_len); }
void FC_FUNC_(adios_read_var_logical8, ADIOS_READ_VAR_LOGICAL8) (int64_t * gp, char * varname, uint64_t * start, uint64_t * count, void * data, int64_t * read_bytes, int varname_len) { FC_FUNC_(adios_read_var, ADIOS_READ_VAR) (gp, varname, start, count, data, read_bytes, varname_len); }

void FC_FUNC_(adios_get_statistics, ADIOS_GET_STATISTICS) 
        (int64_t * gp,
         char    * varname,
         void    * value,
         void    * gmin,
         void    * gmax,
         double  * gavg,
         double  * gstd_dev,
         void   ** mins,
         void   ** maxs,
         double ** avgs,
         double ** std_devs,
         int     * err,
         int       varname_len)
{
    ADIOS_FILE *afp = (ADIOS_FILE *) *gp;
    ADIOS_VARINFO *vi = NULL;
    char *varstr;
    int i, size;

    varstr = futils_fstr_to_cstr(varname, varname_len);
    if (varstr != NULL) {
        /* First get the number of dimensions of the variable */
        vi = common_read_inq_var (afp, varname);
    }
    if (vi != NULL) {
        size = bp_get_type_size(vi->type, vi->value);
        // get statistics information per each step
        common_read_inq_var_stat (afp, vi, 1, 0); 
        if (vi->type == adios_string) size++;
        if (vi->value) memcpy(value, vi->value, size);

        if (vi->statistics) {
            if (vi->type == adios_complex || vi->type == adios_double_complex) {
                /* For complex numbers, the statistics in ADIOS_VARINFO, like 
                   gmin, gavg, std_devs etc, are of base type double. They also 
                   have an additional dimension that stores the statistics for 
                   the magnitude, the real part, and the imaginary part of the 
                   complex number, individually. For example, gmin[0] holds the 
                   overall minimum value of the magnitude of the complex numbers. 
                   gmin[1] and gmin [2] contain the global minimums for the real 
                   and the imaginary parts, respectively. 
                 */
                if (vi->statistics->min) 
                    memcpy((char *) gmin, (char *) vi->statistics->min, 3*size);
                if (vi->statistics->max) 
                    memcpy(((char *) gmax), (char *) vi->statistics->max, 3*size);
                if (vi->statistics->avg) 
                    memcpy(gavg, vi->statistics->avg, 3*sizeof(double));
                if (vi->statistics->std_dev) 
                    memcpy(gstd_dev, vi->statistics->std_dev, 3*sizeof(double));

                /* FIXME: I do not know if mins is **void and mins[i] is a void * allocated
                   separately, or mins is a continuous array now.
                   Copy content accordingly back to the Fortran client.
                */
                int c;
                double ** v_mins = NULL;
                double ** v_maxs = NULL;
                double ** v_avgs = NULL;
                double ** v_std_devs = NULL;
                if (vi->statistics->steps) {
                    v_mins = (double **) vi->statistics->steps->mins;
                    v_maxs = (double **) vi->statistics->steps->maxs;
                    v_avgs = (double **) vi->statistics->steps->avgs;
                    v_std_devs = (double **) vi->statistics->steps->std_devs;
                }

                for (c = 0; c < 3; c ++)
                {
                    if (v_mins && v_mins[c]) memcpy(((double **) mins)[c], v_mins[c], vi->nsteps * size);
                    if (v_maxs && v_maxs[c]) memcpy(((double **) maxs)[c], v_maxs[c], vi->nsteps * size);
                    if (v_avgs && v_avgs[c]) memcpy(avgs[c], v_avgs[c], vi->nsteps * sizeof(double));
                    if (v_std_devs && v_std_devs[c]) memcpy(std_devs[c], v_std_devs[c], vi->nsteps * sizeof(double));
                }

            } else {
                if (vi->statistics->min) 
                    memcpy((char *) gmin, (char *) vi->statistics->min, size);
                if (vi->statistics->max) 
                    memcpy((char *) gmax, (char *) vi->statistics->max, size);
                if (vi->statistics->avg) 
                    memcpy(gavg, vi->statistics->avg, sizeof(double));
                if (vi->statistics->std_dev) 
                    memcpy(gstd_dev, vi->statistics->std_dev, sizeof(double));

                if (vi->statistics->steps) {
                    if (vi->statistics->steps->mins) 
                        memcpy((char *) mins, (char *) vi->statistics->steps->mins, vi->nsteps * size);
                    if (vi->statistics->steps->maxs) 
                        memcpy((char *) maxs, (char *) vi->statistics->steps->maxs, vi->nsteps * size);
                    if (vi->statistics->steps->avgs) 
                        memcpy(avgs, vi->statistics->steps->avgs, vi->nsteps * sizeof(double));
                    if (vi->statistics->steps->std_devs) 
                        memcpy(std_devs, vi->statistics->steps->std_devs, vi->nsteps * sizeof(double));
                }
            }
        }
        common_read_free_varinfo(vi);
    }
    *err = adios_errno;
    if (*err < 0)
        fprintf(stderr, "Error: %s\n", adios_get_last_errmsg());
}

/* Specific function for each data type */
void FC_FUNC_(adios_get_statistics_int1, ADIOS_GET_STATISTICS_INT1) (int64_t * gp, char * varname, void * value, void * gmin, void * gmax, void * gavg, void * gstd_dev, void * mins, void * maxs, void * avgs, void * std_devs, int * err, int varname_len) { FC_FUNC_(adios_get_statistics, ADIOS_GET_STATISTICS) (gp, varname, value, gmin, gmax, gavg, gstd_dev, mins, maxs, avgs, std_devs, err, varname_len); }
void FC_FUNC_(adios_get_statistics_int2, ADIOS_GET_STATISTICS_INT2) (int64_t * gp, char * varname, void * value, void * gmin, void * gmax, void * gavg, void * gstd_dev, void * mins, void * maxs, void * avgs, void * std_devs, int * err, int varname_len) { FC_FUNC_(adios_get_statistics, ADIOS_GET_STATISTICS) (gp, varname, value, gmin, gmax, gavg, gstd_dev, mins, maxs, avgs, std_devs, err, varname_len); }
void FC_FUNC_(adios_get_statistics_int4, ADIOS_GET_STATISTICS_INT4) (int64_t * gp, char * varname, void * value, void * gmin, void * gmax, void * gavg, void * gstd_dev, void * mins, void * maxs, void * avgs, void * std_devs, int * err, int varname_len) { FC_FUNC_(adios_get_statistics, ADIOS_GET_STATISTICS) (gp, varname, value, gmin, gmax, gavg, gstd_dev, mins, maxs, avgs, std_devs, err, varname_len); }
void FC_FUNC_(adios_get_statistics_int8, ADIOS_GET_STATISTICS_INT8) (int64_t * gp, char * varname, void * value, void * gmin, void * gmax, void * gavg, void * gstd_dev, void * mins, void * maxs, void * avgs, void * std_devs, int * err, int varname_len) { FC_FUNC_(adios_get_statistics, ADIOS_GET_STATISTICS) (gp, varname, value, gmin, gmax, gavg, gstd_dev, mins, maxs, avgs, std_devs, err, varname_len); }
void FC_FUNC_(adios_get_statistics_real4, ADIOS_GET_STATISTICS_REAL4) (int64_t * gp, char * varname, void * value, void * gmin, void * gmax, void * gavg, void * gstd_dev, void * mins, void * maxs, void * avgs, void * std_devs, int * err, int varname_len) { FC_FUNC_(adios_get_statistics, ADIOS_GET_STATISTICS) (gp, varname, value, gmin, gmax, gavg, gstd_dev, mins, maxs, avgs, std_devs, err, varname_len); }
void FC_FUNC_(adios_get_statistics_real8, ADIOS_GET_STATISTICS_REAL8) (int64_t * gp, char * varname, void * value, void * gmin, void * gmax, void * gavg, void * gstd_dev, void * mins, void * maxs, void * avgs, void * std_devs, int * err, int varname_len) { FC_FUNC_(adios_get_statistics, ADIOS_GET_STATISTICS) (gp, varname, value, gmin, gmax, gavg, gstd_dev, mins, maxs, avgs, std_devs, err, varname_len); }
void FC_FUNC_(adios_get_statistics_complex8, ADIOS_GET_STATISTICS_COMPLEX8) (int64_t * gp, char * varname, void * value, void * gmin, void * gmax, void * gavg, void * gstd_dev, void * mins, void * maxs, void * avgs, void * std_devs, int * err, int varname_len) { FC_FUNC_(adios_get_statistics, ADIOS_GET_STATISTICS) (gp, varname, value, gmin, gmax, gavg, gstd_dev, mins, maxs, avgs, std_devs, err, varname_len); }
void FC_FUNC_(adios_get_statistics_complex16, ADIOS_GET_STATISTICS_COMPLEX16) (int64_t * gp, char * varname, void * value, void * gmin, void * gmax, void * gavg, void * gstd_dev, void * mins, void * maxs, void * avgs, void * std_devs, int * err, int varname_len) { FC_FUNC_(adios_get_statistics, ADIOS_GET_STATISTICS) (gp, varname, value, gmin, gmax, gavg, gstd_dev, mins, maxs, avgs, std_devs, err, varname_len); }
void FC_FUNC_(adios_get_statistics_char, ADIOS_GET_STATISTICS_CHAR) (int64_t * gp, char * varname, void * value, void * gmin, void * gmax, void * gavg, void * gstd_dev, void * mins, void * maxs, void * avgs, void * std_devs, int * err, int varname_len) { FC_FUNC_(adios_get_statistics, ADIOS_GET_STATISTICS) (gp, varname, value, gmin, gmax, gavg, gstd_dev, mins, maxs, avgs, std_devs, err, varname_len); }
void FC_FUNC_(adios_get_statistics_logical1, ADIOS_GET_STATISTICS_LOGICAL1) (int64_t * gp, char * varname, void * value, void * gmin, void * gmax, void * gavg, void * gstd_dev, void * mins, void * maxs, void * avgs, void * std_devs, int * err, int varname_len) { FC_FUNC_(adios_get_statistics, ADIOS_GET_STATISTICS) (gp, varname, value, gmin, gmax, gavg, gstd_dev, mins, maxs, avgs, std_devs, err, varname_len); }
void FC_FUNC_(adios_get_statistics_logical2, ADIOS_GET_STATISTICS_LOGICAL2) (int64_t * gp, char * varname, void * value, void * gmin, void * gmax, void * gavg, void * gstd_dev, void * mins, void * maxs, void * avgs, void * std_devs, int * err, int varname_len) { FC_FUNC_(adios_get_statistics, ADIOS_GET_STATISTICS) (gp, varname, value, gmin, gmax, gavg, gstd_dev, mins, maxs, avgs, std_devs, err, varname_len); }
void FC_FUNC_(adios_get_statistics_logical4, ADIOS_GET_STATISTICS_LOGICAL4) (int64_t * gp, char * varname, void * value, void * gmin, void * gmax, void * gavg, void * gstd_dev, void * mins, void * maxs, void * avgs, void * std_devs, int * err, int varname_len) { FC_FUNC_(adios_get_statistics, ADIOS_GET_STATISTICS) (gp, varname, value, gmin, gmax, gavg, gstd_dev, mins, maxs, avgs, std_devs, err, varname_len); }
void FC_FUNC_(adios_get_statistics_logical8, ADIOS_GET_STATISTICS_LOGICAL8) (int64_t * gp, char * varname, void * value, void * gmin, void * gmax, void * gavg, void * gstd_dev, void * mins, void * maxs, void * avgs, void * std_devs, int * err, int varname_len) { FC_FUNC_(adios_get_statistics, ADIOS_GET_STATISTICS) (gp, varname, value, gmin, gmax, gavg, gstd_dev, mins, maxs, avgs, std_devs, err, varname_len); }

void FC_FUNC_(adios_get_attr, ADIOS_GET_ATTR) 
        (int64_t * gp,
         char    * attrname,
         void    * attr,
         int     * err,
         int       attrname_len)
{
    ADIOS_FILE *afp = (ADIOS_FILE *) *gp;
    char *attrstr;
    int i;
    void *data;
    int size;
    enum ADIOS_DATATYPES type;
    attrstr = futils_fstr_to_cstr(attrname, attrname_len);
    if (attrstr != NULL) {
        *err = common_read_get_attr (afp, attrstr, &type, &size, &data);
        if (data) {
            memcpy(attr, data, size);
            free(data);
        }
    } else {
        *err = adios_errno;
    }
    if (*err < 0)
        fprintf(stderr, "Error: %s\n", adios_get_last_errmsg());
}

void FC_FUNC_(adios_inq_attr, ADIOS_INQ_ATTR) 
        (int64_t * gp,
         char    * attrname,
         int     * type,
         int     * size,
         int     * err,
         int       attrname_len)
{
    ADIOS_FILE *afp = (ADIOS_FILE *) *gp;
    char *attrstr;
    int i;
    void *data;
    attrstr = futils_fstr_to_cstr(attrname, attrname_len);
    if (attrstr != NULL) {
        *err = common_read_get_attr (afp, attrstr, (enum ADIOS_DATATYPES *)type, size, &data);
        free(data);
    } else {
        *err = adios_errno;
    }
    if (*err < 0)
        fprintf(stderr, "Error: %s\n", adios_get_last_errmsg());
}

/* Specific function for each data type */
void FC_FUNC_(adios_get_attr_int1, ADIOS_GET_ATTR_INT1) (int64_t * gp, char * attrname, void * attr, int * err, int attrname_len) { FC_FUNC_(adios_get_attr, ADIOS_GET_ATTR) (gp, attrname, attr, err, attrname_len); }
void FC_FUNC_(adios_get_attr_int2, ADIOS_GET_ATTR_INT2) (int64_t * gp, char * attrname, void * attr, int * err, int attrname_len) { FC_FUNC_(adios_get_attr, ADIOS_GET_ATTR) (gp, attrname, attr, err, attrname_len); }
void FC_FUNC_(adios_get_attr_int4, ADIOS_GET_ATTR_INT4) (int64_t * gp, char * attrname, void * attr, int * err, int attrname_len) { FC_FUNC_(adios_get_attr, ADIOS_GET_ATTR) (gp, attrname, attr, err, attrname_len); }
void FC_FUNC_(adios_get_attr_int8, ADIOS_GET_ATTR_INT8) (int64_t * gp, char * attrname, void * attr, int * err, int attrname_len) { FC_FUNC_(adios_get_attr, ADIOS_GET_ATTR) (gp, attrname, attr, err, attrname_len); }
void FC_FUNC_(adios_get_attr_real4, ADIOS_GET_ATTR_REAL4) (int64_t * gp, char * attrname, void * attr, int * err, int attrname_len) { FC_FUNC_(adios_get_attr, ADIOS_GET_ATTR) (gp, attrname, attr, err, attrname_len); }
void FC_FUNC_(adios_get_attr_real8, ADIOS_GET_ATTR_REAL8) (int64_t * gp, char * attrname, void * attr, int * err, int attrname_len) { FC_FUNC_(adios_get_attr, ADIOS_GET_ATTR) (gp, attrname, attr, err, attrname_len); }
void FC_FUNC_(adios_get_attr_complex8, ADIOS_GET_ATTR_COMPLEX8) (int64_t * gp, char * attrname, void * attr, int * err, int attrname_len) { FC_FUNC_(adios_get_attr, ADIOS_GET_ATTR) (gp, attrname, attr, err, attrname_len); }
void FC_FUNC_(adios_get_attr_complex16, ADIOS_GET_ATTR_COMPLEX16) (int64_t * gp, char * attrname, void * attr, int * err, int attrname_len) { FC_FUNC_(adios_get_attr, ADIOS_GET_ATTR) (gp, attrname, attr, err, attrname_len); }
void FC_FUNC_(adios_get_attr_char, ADIOS_GET_ATTR_CHAR) (int64_t * gp, char * attrname, void * attr, int * err, int attrname_len) { FC_FUNC_(adios_get_attr, ADIOS_GET_ATTR) (gp, attrname, attr, err, attrname_len); }
void FC_FUNC_(adios_get_attr_logical1, ADIOS_GET_ATTR_LOGICAL1) (int64_t * gp, char * attrname, void * attr, int * err, int attrname_len) { FC_FUNC_(adios_get_attr, ADIOS_GET_ATTR) (gp, attrname, attr, err, attrname_len); }
void FC_FUNC_(adios_get_attr_logical2, ADIOS_GET_ATTR_LOGICAL2) (int64_t * gp, char * attrname, void * attr, int * err, int attrname_len) { FC_FUNC_(adios_get_attr, ADIOS_GET_ATTR) (gp, attrname, attr, err, attrname_len); }
void FC_FUNC_(adios_get_attr_logical4, ADIOS_GET_ATTR_LOGICAL4) (int64_t * gp, char * attrname, void * attr, int * err, int attrname_len) { FC_FUNC_(adios_get_attr, ADIOS_GET_ATTR) (gp, attrname, attr, err, attrname_len); }
void FC_FUNC_(adios_get_attr_logical8, ADIOS_GET_ATTR_LOGICAL8) (int64_t * gp, char * attrname, void * attr, int * err, int attrname_len) { FC_FUNC_(adios_get_attr, ADIOS_GET_ATTR) (gp, attrname, attr, err, attrname_len); }

