/*
 * Copyright (C) 2007-2020 S[&]T, The Netherlands.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef CODA_H
#define CODA_H

/** \file */

/* *INDENT-OFF* */
#ifdef __cplusplus
extern "C"
{
#endif
/* *INDENT-ON* */

#if defined(WIN32) && defined(LIBCODADLL)
#ifdef LIBCODADLL_EXPORTS
#define LIBCODA_API __declspec(dllexport)
#else
#define LIBCODA_API __declspec(dllimport)
#endif
#else
#define LIBCODA_API
#endif

#ifndef CODA_CONFIG_H

/* These are the 'configure' defines that we need to export.   
 * However, we need to assume that the user of coda.h may also be defining
 * some of these values himself. In order to prevent double definitions each
 * define below is encapsulated by a #ifndef - #endif block.
 */

#ifndef HAVE_INTTYPES_H
#cmakedefine HAVE_INTTYPES_H ${HAVE_INTTYPES_H}
#endif
#ifndef HAVE_STDINT_H
#cmakedefine HAVE_STDINT_H ${HAVE_STDINT_H}
#endif
#ifndef HAVE_SYS_TYPES_H
#cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H}
#endif

#ifndef int8_t
#cmakedefine int8_t ${int8_t}
#endif
#ifndef int16_t
#cmakedefine int16_t ${int16_t}
#endif
#ifndef int32_t
#cmakedefine int32_t ${int32_t}
#endif
#ifndef int64_t
#cmakedefine int64_t ${int64_t}
#endif

#ifndef uint8_t
#cmakedefine uint8_t ${uint8_t}
#endif
#ifndef uint16_t
#cmakedefine uint16_t ${uint16_t}
#endif
#ifndef uint32_t
#cmakedefine uint32_t ${uint32_t}
#endif
#ifndef uint64_t
#cmakedefine uint64_t ${uint64_t}
#endif

#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#else
#ifdef HAVE_STDINT_H
#include <stdint.h>
#else
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#endif
#endif

#if defined(WIN32) && (_MSC_VER < 1600) && !defined(__MINGW32__)
/* For Visual Studio > 2010 and MinGW we can use stdint.h
 * For earlier versions of Visual Studio we need to provide our own defines
 */
#ifndef int8_t
#define int8_t  signed char
#endif
#ifndef int16_t
#define int16_t signed short
#endif
#ifndef int32_t
#define int32_t int
#endif
#ifndef int64_t
#define int64_t __int64
#endif

#ifndef uint8_t
#define uint8_t  unsigned char
#endif
#ifndef uint16_t
#define uint16_t unsigned short
#endif
#ifndef uint32_t
#define uint32_t unsigned int
#endif
#ifndef uint64_t
#define uint64_t unsigned __int64
#endif
#endif

#endif /* CODA_CONFIG_H */

#ifndef CODA_INTERNAL

LIBCODA_API extern const char *coda_get_libcoda_version(void);

#define libcoda_version (coda_get_libcoda_version())

LIBCODA_API extern int *coda_get_errno(void);

#define coda_errno (*coda_get_errno())

#endif

#ifndef PRINTF_ATTR
#cmakedefine PRINTF_ATTR ${PRINTF_ATTR}
#ifndef PRINTF_ATTR
#define PRINTF_ATTR
#endif
#endif

/** Maximum number of dimensions of a multidimensional array 
 * \ingroup coda_general
 */
#define CODA_MAX_NUM_DIMS         8

/* Defines for backward compatibility with CODA 1.x interface */
#define coda_ProductFile coda_product
#define coda_Cursor coda_cursor
#define coda_Type coda_type

#define CODA_SUCCESS                                          (0)
#define CODA_ERROR_OUT_OF_MEMORY                             (-1)
#define CODA_ERROR_HDF4                                     (-10)
#define CODA_ERROR_NO_HDF4_SUPPORT                          (-11)
#define CODA_ERROR_HDF5                                     (-12)
#define CODA_ERROR_NO_HDF5_SUPPORT                          (-13)
#define CODA_ERROR_XML                                      (-14)

#define CODA_ERROR_FILE_NOT_FOUND                           (-20)
#define CODA_ERROR_FILE_OPEN                                (-21)
#define CODA_ERROR_FILE_READ                                (-22)
#define CODA_ERROR_FILE_WRITE                               (-23)

#define CODA_ERROR_INVALID_ARGUMENT                        (-100)
#define CODA_ERROR_INVALID_INDEX                           (-101)
#define CODA_ERROR_INVALID_NAME                            (-102)
#define CODA_ERROR_INVALID_FORMAT                          (-103)
#define CODA_ERROR_INVALID_DATETIME                        (-104)
#define CODA_ERROR_INVALID_TYPE                            (-105)
#define CODA_ERROR_ARRAY_NUM_DIMS_MISMATCH                 (-106)
#define CODA_ERROR_ARRAY_OUT_OF_BOUNDS                     (-107)
#define CODA_ERROR_NO_PARENT                               (-108)

#define CODA_ERROR_UNSUPPORTED_PRODUCT                     (-200)

#define CODA_ERROR_PRODUCT                                 (-300)
#define CODA_ERROR_OUT_OF_BOUNDS_READ                      (-301)

#define CODA_ERROR_DATA_DEFINITION                         (-400)
#define CODA_ERROR_EXPRESSION                              (-401)

/** \addtogroup coda_general
 * @{
 */

enum coda_array_ordering_enum
{
    coda_array_ordering_c,                  /**< C array ordering (last dimension is fastest running) */
    coda_array_ordering_fortran             /**< Fortran array ordering (first dimension is fastest running) */
};

enum coda_filefilter_status_enum
{
    coda_ffs_error,                         /**< error: General error (usually file I/O related) */
    coda_ffs_could_not_open_file,           /**< error: Could not open file */
    coda_ffs_could_not_access_directory,    /**< error: Could not recurse into directory */
    coda_ffs_unsupported_file,              /**< File can not be read by CODA */
    coda_ffs_match,                         /**< File matches filter */
    coda_ffs_no_match                       /**< File does not match filter */
};

enum coda_format_enum
{
    coda_format_ascii,                      /**< Data stored in structured ASCII format */
    coda_format_binary,                     /**< Data stored in structured binary format */
    coda_format_xml,                        /**< Data stored in XML format */
    coda_format_hdf4,                       /**< Data stored in HDF4 format */
    coda_format_hdf5,                       /**< Data stored in HDF5 format */
    coda_format_cdf,                        /**< Data stored in CDF format */
    coda_format_netcdf,                     /**< Data stored in NetCDF format */
    coda_format_grib,                       /**< Data stored in GRIB format */
    coda_format_rinex,                      /**< Data stored in RINEX format */
    coda_format_sp3                         /**< Data stored in SP3 format */
};

enum coda_type_class_enum
{
    coda_record_class,                      /**< Class of all record types */
    coda_array_class,                       /**< Class of all array types */
    coda_integer_class,                     /**< Class of all integer types */
    coda_real_class,                        /**< Class of all real (floating point) types */
    coda_text_class,                        /**< Class of all text types */
    coda_raw_class,                         /**< Class of all unformatted types (data that is not interpreted) */
    coda_special_class                      /**< Class of all special data types (such as time and complex) */
};

enum coda_special_type_enum
{
    coda_special_no_data,                   /**< No data (data object is not available) */
    coda_special_vsf_integer,               /**< A compound containing a variable scale factor and an integer.
                                                 The returned double value equals: integer_value x 10^(-scale_factor) */
    coda_special_time,                      /**< Data specifying a date/time value */
    coda_special_complex                    /**< Data consisting of a real and imaginary value */
};

enum coda_native_type_enum
{
    coda_native_type_not_available = -1,    /**< native type value for compound entities that can not be read directly */
    coda_native_type_int8,                  /**< 8 bit signed integer (#coda_integer_class) */
    coda_native_type_uint8,                 /**< 8 bit unsigned integer (#coda_integer_class) */
    coda_native_type_int16,                 /**< 16 bit signed integer (#coda_integer_class) */
    coda_native_type_uint16,                /**< 16 bit unsigned integer (#coda_integer_class) */
    coda_native_type_int32,                 /**< 32 bit signed integer (#coda_integer_class) */
    coda_native_type_uint32,                /**< 32 bit unsigned integer (#coda_integer_class) */
    coda_native_type_int64,                 /**< 64 bit signed integer (#coda_integer_class) */
    coda_native_type_uint64,                /**< 64 bit unsigned integer (#coda_integer_class) */
    coda_native_type_float,                 /**< 32 bit IEEE floating point type (#coda_real_class) */
    coda_native_type_double,                /**< 64 bit IEEE floating point type (#coda_real_class) */
    coda_native_type_char,                  /**< single character (#coda_text_class) */
    coda_native_type_string,                /**< string (#coda_text_class) */
    coda_native_type_bytes                  /**< series of uninterpreted bytes (#coda_raw_class) */
};

/** @} */

enum coda_expression_type_enum
{
    coda_expression_boolean,
    coda_expression_integer,
    coda_expression_float,
    coda_expression_string,
    coda_expression_node,
    coda_expression_void
};

typedef enum coda_array_ordering_enum coda_array_ordering;
typedef enum coda_filefilter_status_enum coda_filefilter_status;
typedef enum coda_format_enum coda_format;
typedef enum coda_type_class_enum coda_type_class;
typedef enum coda_special_type_enum coda_special_type;
typedef enum coda_native_type_enum coda_native_type;
typedef enum coda_expression_type_enum coda_expression_type;

typedef struct coda_product_struct coda_product;
typedef struct coda_cursor_struct coda_cursor;
typedef struct coda_type_struct coda_type;
typedef struct coda_expression_struct coda_expression;

/* CODA General */

LIBCODA_API int coda_init(void);
LIBCODA_API void coda_done(void);

LIBCODA_API int coda_set_definition_path(const char *path);
LIBCODA_API int coda_set_definition_path_conditional(const char *file, const char *searchpath,
                                                     const char *relative_location);

LIBCODA_API int coda_set_option_bypass_special_types(int enable);
LIBCODA_API int coda_get_option_bypass_special_types(void);
LIBCODA_API int coda_set_option_perform_boundary_checks(int enable);
LIBCODA_API int coda_get_option_perform_boundary_checks(void);
LIBCODA_API int coda_set_option_perform_conversions(int enable);
LIBCODA_API int coda_get_option_perform_conversions(void);
LIBCODA_API int coda_set_option_use_fast_size_expressions(int enable);
LIBCODA_API int coda_get_option_use_fast_size_expressions(void);
LIBCODA_API int coda_set_option_use_mmap(int enable);
LIBCODA_API int coda_get_option_use_mmap(void);

LIBCODA_API void coda_free(void *ptr);

LIBCODA_API double coda_NaN(void);
LIBCODA_API int coda_isNaN(double x);
LIBCODA_API double coda_PlusInf(void);
LIBCODA_API double coda_MinInf(void);
LIBCODA_API int coda_isInf(double x);
LIBCODA_API int coda_isPlusInf(double x);
LIBCODA_API int coda_isMinInf(double x);

LIBCODA_API void coda_str64(int64_t a, char *s);
LIBCODA_API void coda_str64u(uint64_t a, char *s);
LIBCODA_API void coda_strfl(double a, char *s);

LIBCODA_API long coda_c_index_to_fortran_index(int num_dims, const long dim[], long index);

LIBCODA_API int coda_match_filefilter(const char *filefilter, int num_filepaths, const char **filepaths,
                                      int (*callbackfunc) (const char *, coda_filefilter_status, const char *, void *),
                                      void *userdata);

/* CODA Time */

LIBCODA_API int coda_time_double_to_parts(double datetime, int *year, int *month, int *day, int *hour, int *minute,
                                          int *second, int *musec);
LIBCODA_API int coda_time_double_to_parts_utc(double datetime, int *year, int *month, int *day, int *hour, int *minute,
                                              int *second, int *musec);
LIBCODA_API int coda_time_parts_to_double(int year, int month, int day, int hour, int minute, int second, int musec,
                                          double *datetime);
LIBCODA_API int coda_time_parts_to_double_utc(int year, int month, int day, int hour, int minute, int second, int musec,
                                              double *datetime);

LIBCODA_API int coda_time_parts_to_string(int year, int month, int day, int hour, int minute, int second, int musec,
                                          const char *format, char *out_str);
LIBCODA_API int coda_time_string_to_parts(const char *format, const char *str, int *year, int *month, int *day,
                                          int *hour, int *minute, int *second, int *musec);

LIBCODA_API int coda_time_double_to_string(double datetime, const char *format, char *out_str);
LIBCODA_API int coda_time_double_to_string_utc(double datetime, const char *format, char *out_str);
LIBCODA_API int coda_time_string_to_double(const char *format, const char *str, double *datetime);
LIBCODA_API int coda_time_string_to_double_utc(const char *format, const char *str, double *datetime);

/* deprecated backward compatible functions */
LIBCODA_API int coda_datetime_to_double(int year, int month, int day, int hour, int minute, int second, int musec,
                                        double *datetime);
LIBCODA_API int coda_double_to_datetime(double datetime, int *year, int *month, int *day, int *hour, int *minute,
                                        int *second, int *musec);
LIBCODA_API int coda_time_to_string(double datetime, char *out_str);
LIBCODA_API int coda_string_to_time(const char *str, double *datetime);

LIBCODA_API int coda_utcdatetime_to_double(int year, int month, int day, int hour, int minute, int secon, int musec,
                                           double *datetime);
LIBCODA_API int coda_double_to_utcdatetime(double datetime, int *year, int *month, int *day, int *hour, int *minute,
                                           int *second, int *musec);
LIBCODA_API int coda_time_to_utcstring(double datetime, char *out_str);
LIBCODA_API int coda_utcstring_to_time(const char *str, double *datetime);

/* CODA Error */

/* *INDENT-OFF* */
LIBCODA_API void coda_set_error(int err, const char *message, ...) PRINTF_ATTR;
/* *INDENT-ON* */
LIBCODA_API const char *coda_errno_to_string(int err);

/* CODA Product */

LIBCODA_API int coda_recognize_file(const char *filename, int64_t *file_size, coda_format *file_format,
                                    const char **product_class, const char **product_type, int *version);

LIBCODA_API int coda_open(const char *filename, coda_product **product);
LIBCODA_API int coda_open_as(const char *filename, const char *product_class, const char *product_type, int version,
                             coda_product **product);
LIBCODA_API int coda_close(coda_product *product);

LIBCODA_API int coda_get_product_filename(const coda_product *product, const char **filename);
LIBCODA_API int coda_get_product_file_size(const coda_product *product, int64_t *file_size);
LIBCODA_API int coda_get_product_format(const coda_product *product, coda_format *format);
LIBCODA_API int coda_get_product_class(const coda_product *product, const char **product_class);
LIBCODA_API int coda_get_product_type(const coda_product *product, const char **product_type);
LIBCODA_API int coda_get_product_version(const coda_product *product, int *version);
LIBCODA_API int coda_get_product_definition_file(const coda_product *product, const char **definition_file);
LIBCODA_API int coda_get_product_root_type(const coda_product *product, coda_type **type);

LIBCODA_API int coda_get_product_variable_value(coda_product *product, const char *variable, long index,
                                                int64_t *value);

/* CODA Types */

LIBCODA_API const char *coda_type_get_format_name(coda_format format);
LIBCODA_API const char *coda_type_get_class_name(coda_type_class type_class);
LIBCODA_API const char *coda_type_get_native_type_name(coda_native_type native_type);
LIBCODA_API const char *coda_type_get_special_type_name(coda_special_type special_type);

LIBCODA_API int coda_type_has_attributes(const coda_type *type, int *has_attributes);

LIBCODA_API int coda_type_get_format(const coda_type *type, coda_format *format);
LIBCODA_API int coda_type_get_class(const coda_type *type, coda_type_class *type_class);
LIBCODA_API int coda_type_get_read_type(const coda_type *type, coda_native_type *read_type);
LIBCODA_API int coda_type_get_string_length(const coda_type *type, long *length);
LIBCODA_API int coda_type_get_bit_size(const coda_type *type, int64_t *bit_size);
LIBCODA_API int coda_type_get_name(const coda_type *type, const char **name);
LIBCODA_API int coda_type_get_description(const coda_type *type, const char **description);
LIBCODA_API int coda_type_get_unit(const coda_type *type, const char **unit);
LIBCODA_API int coda_type_get_fixed_value(const coda_type *type, const char **fixed_value, long *length);
LIBCODA_API int coda_type_get_attributes(const coda_type *type, coda_type **attributes);

LIBCODA_API int coda_type_get_num_record_fields(const coda_type *type, long *num_fields);
LIBCODA_API int coda_type_get_record_field_index_from_name(const coda_type *type, const char *name, long *index);
LIBCODA_API int coda_type_get_record_field_index_from_real_name(const coda_type *type, const char *real_name,
                                                                long *index);
LIBCODA_API int coda_type_get_record_field_type(const coda_type *type, long index, coda_type **field_type);
LIBCODA_API int coda_type_get_record_field_name(const coda_type *type, long index, const char **name);
LIBCODA_API int coda_type_get_record_field_real_name(const coda_type *type, long index, const char **real_name);
LIBCODA_API int coda_type_get_record_field_hidden_status(const coda_type *type, long index, int *hidden);
LIBCODA_API int coda_type_get_record_field_available_status(const coda_type *type, long index, int *available);
LIBCODA_API int coda_type_get_record_union_status(const coda_type *type, int *is_union);

LIBCODA_API int coda_type_get_array_num_dims(const coda_type *type, int *num_dims);
LIBCODA_API int coda_type_get_array_dim(const coda_type *type, int *num_dims, long dim[]);
LIBCODA_API int coda_type_get_array_base_type(const coda_type *type, coda_type **base_type);

LIBCODA_API int coda_type_get_special_type(const coda_type *type, coda_special_type *special_type);
LIBCODA_API int coda_type_get_special_base_type(const coda_type *type, coda_type **base_type);

/* CODA Cursor */

LIBCODA_API int coda_cursor_set_product(coda_cursor *cursor, coda_product *product);

LIBCODA_API int coda_cursor_goto(coda_cursor *cursor, const char *path);

LIBCODA_API int coda_cursor_goto_first_record_field(coda_cursor *cursor);
LIBCODA_API int coda_cursor_goto_next_record_field(coda_cursor *cursor);
LIBCODA_API int coda_cursor_goto_record_field_by_index(coda_cursor *cursor, long index);
LIBCODA_API int coda_cursor_goto_record_field_by_name(coda_cursor *cursor, const char *name);
LIBCODA_API int coda_cursor_goto_available_union_field(coda_cursor *cursor);

LIBCODA_API int coda_cursor_goto_first_array_element(coda_cursor *cursor);
LIBCODA_API int coda_cursor_goto_next_array_element(coda_cursor *cursor);
LIBCODA_API int coda_cursor_goto_array_element(coda_cursor *cursor, int num_subs, const long subs[]);
LIBCODA_API int coda_cursor_goto_array_element_by_index(coda_cursor *cursor, long index);

LIBCODA_API int coda_cursor_goto_attributes(coda_cursor *cursor);

LIBCODA_API int coda_cursor_goto_root(coda_cursor *cursor);
LIBCODA_API int coda_cursor_goto_parent(coda_cursor *cursor);

LIBCODA_API int coda_cursor_use_base_type_of_special_type(coda_cursor *cursor);

LIBCODA_API int coda_cursor_has_ascii_content(const coda_cursor *cursor, int *has_ascii_content);
LIBCODA_API int coda_cursor_has_attributes(const coda_cursor *cursor, int *has_attributes);

LIBCODA_API int coda_cursor_get_string_length(const coda_cursor *cursor, long *length);
LIBCODA_API int coda_cursor_get_bit_size(const coda_cursor *cursor, int64_t *bit_size);
LIBCODA_API int coda_cursor_get_byte_size(const coda_cursor *cursor, int64_t *byte_size);
LIBCODA_API int coda_cursor_get_num_elements(const coda_cursor *cursor, long *num_elements);

LIBCODA_API int coda_cursor_get_product_file(const coda_cursor *cursor, coda_product **product);

LIBCODA_API int coda_cursor_get_depth(const coda_cursor *cursor, int *depth);
LIBCODA_API int coda_cursor_get_index(const coda_cursor *cursor, long *index);

LIBCODA_API int coda_cursor_get_file_bit_offset(const coda_cursor *cursor, int64_t *bit_offset);
LIBCODA_API int coda_cursor_get_file_byte_offset(const coda_cursor *cursor, int64_t *byte_offset);

LIBCODA_API int coda_cursor_get_format(const coda_cursor *cursor, coda_format *format);
LIBCODA_API int coda_cursor_get_type_class(const coda_cursor *cursor, coda_type_class *type_class);
LIBCODA_API int coda_cursor_get_read_type(const coda_cursor *cursor, coda_native_type *read_type);
LIBCODA_API int coda_cursor_get_special_type(const coda_cursor *cursor, coda_special_type *special_type);
LIBCODA_API int coda_cursor_get_type(const coda_cursor *cursor, coda_type **type);

LIBCODA_API int coda_cursor_get_record_field_index_from_name(const coda_cursor *cursor, const char *name, long *index);
LIBCODA_API int coda_cursor_get_record_field_available_status(const coda_cursor *cursor, long index, int *available);
LIBCODA_API int coda_cursor_get_available_union_field_index(const coda_cursor *cursor, long *index);

LIBCODA_API int coda_cursor_get_array_dim(const coda_cursor *cursor, int *num_dims, long dim[]);

LIBCODA_API int coda_cursor_print_path(const coda_cursor *cursor, int (*print) (const char *, ...));

/* read simple-type scalars */

LIBCODA_API int coda_cursor_read_int8(const coda_cursor *cursor, int8_t *dst);
LIBCODA_API int coda_cursor_read_uint8(const coda_cursor *cursor, uint8_t *dst);
LIBCODA_API int coda_cursor_read_int16(const coda_cursor *cursor, int16_t *dst);
LIBCODA_API int coda_cursor_read_uint16(const coda_cursor *cursor, uint16_t *dst);
LIBCODA_API int coda_cursor_read_int32(const coda_cursor *cursor, int32_t *dst);
LIBCODA_API int coda_cursor_read_uint32(const coda_cursor *cursor, uint32_t *dst);
LIBCODA_API int coda_cursor_read_int64(const coda_cursor *cursor, int64_t *dst);
LIBCODA_API int coda_cursor_read_uint64(const coda_cursor *cursor, uint64_t *dst);

LIBCODA_API int coda_cursor_read_float(const coda_cursor *cursor, float *dst);
LIBCODA_API int coda_cursor_read_double(const coda_cursor *cursor, double *dst);

LIBCODA_API int coda_cursor_read_char(const coda_cursor *cursor, char *dst);
LIBCODA_API int coda_cursor_read_string(const coda_cursor *cursor, char *dst, long dst_size);

LIBCODA_API int coda_cursor_read_bits(const coda_cursor *cursor, uint8_t *dst, int64_t bit_offset, int64_t bit_length);
LIBCODA_API int coda_cursor_read_bytes(const coda_cursor *cursor, uint8_t *dst, int64_t offset, int64_t length);

/* read simple-type arrays */

LIBCODA_API int coda_cursor_read_int8_array(const coda_cursor *cursor, int8_t *dst, coda_array_ordering array_ordering);
LIBCODA_API int coda_cursor_read_uint8_array(const coda_cursor *cursor, uint8_t *dst,
                                             coda_array_ordering array_ordering);
LIBCODA_API int coda_cursor_read_int16_array(const coda_cursor *cursor, int16_t *dst,
                                             coda_array_ordering array_ordering);
LIBCODA_API int coda_cursor_read_uint16_array(const coda_cursor *cursor, uint16_t *dst,
                                              coda_array_ordering array_ordering);
LIBCODA_API int coda_cursor_read_int32_array(const coda_cursor *cursor, int32_t *dst,
                                             coda_array_ordering array_ordering);
LIBCODA_API int coda_cursor_read_uint32_array(const coda_cursor *cursor, uint32_t *dst,
                                              coda_array_ordering array_ordering);
LIBCODA_API int coda_cursor_read_int64_array(const coda_cursor *cursor, int64_t *dst,
                                             coda_array_ordering array_ordering);
LIBCODA_API int coda_cursor_read_uint64_array(const coda_cursor *cursor, uint64_t *dst,
                                              coda_array_ordering array_ordering);
LIBCODA_API int coda_cursor_read_float_array(const coda_cursor *cursor, float *dst, coda_array_ordering array_ordering);
LIBCODA_API int coda_cursor_read_double_array(const coda_cursor *cursor, double *dst,
                                              coda_array_ordering array_ordering);
LIBCODA_API int coda_cursor_read_char_array(const coda_cursor *cursor, char *dst, coda_array_ordering array_ordering);

/* read simple-type arrays partially */

LIBCODA_API int coda_cursor_read_int8_partial_array(const coda_cursor *cursor, long offset, long length, int8_t *dst);
LIBCODA_API int coda_cursor_read_uint8_partial_array(const coda_cursor *cursor, long offset, long length, uint8_t *dst);
LIBCODA_API int coda_cursor_read_int16_partial_array(const coda_cursor *cursor, long offset, long length, int16_t *dst);
LIBCODA_API int coda_cursor_read_uint16_partial_array(const coda_cursor *cursor, long offset, long length,
                                                      uint16_t *dst);
LIBCODA_API int coda_cursor_read_int32_partial_array(const coda_cursor *cursor, long offset, long length, int32_t *dst);
LIBCODA_API int coda_cursor_read_uint32_partial_array(const coda_cursor *cursor, long offset, long length,
                                                      uint32_t *dst);
LIBCODA_API int coda_cursor_read_int64_partial_array(const coda_cursor *cursor, long offset, long length, int64_t *dst);
LIBCODA_API int coda_cursor_read_uint64_partial_array(const coda_cursor *cursor, long offset, long length,
                                                      uint64_t *dst);
LIBCODA_API int coda_cursor_read_float_partial_array(const coda_cursor *cursor, long offset, long length, float *dst);
LIBCODA_API int coda_cursor_read_double_partial_array(const coda_cursor *cursor, long offset, long length, double *dst);
LIBCODA_API int coda_cursor_read_char_partial_array(const coda_cursor *cursor, long offset, long length, char *dst);

/* read complex values */

LIBCODA_API int coda_cursor_read_complex_double_pair(const coda_cursor *cursor, double *dst);
LIBCODA_API int coda_cursor_read_complex_double_pairs_array(const coda_cursor *cursor, double *dst,
                                                            coda_array_ordering array_ordering);
LIBCODA_API int coda_cursor_read_complex_double_split(const coda_cursor *cursor, double *dst_re, double *dst_im);
LIBCODA_API int coda_cursor_read_complex_double_split_array(const coda_cursor *cursor, double *dst_re,
                                                            double *dst_im, coda_array_ordering array_ordering);


/* CODA Expression */

LIBCODA_API const char *coda_expression_get_type_name(coda_expression_type type);

LIBCODA_API int coda_expression_from_string(const char *exprstring, coda_expression **expr);
LIBCODA_API void coda_expression_delete(coda_expression *expr);
LIBCODA_API int coda_expression_get_type(const coda_expression *expr, coda_expression_type *type);
LIBCODA_API int coda_expression_is_constant(const coda_expression *expr);
LIBCODA_API int coda_expression_is_equal(const coda_expression *expr1, const coda_expression *expr2);

LIBCODA_API int coda_expression_eval_bool(const coda_expression *expr, const coda_cursor *cursor, int *value);
LIBCODA_API int coda_expression_eval_integer(const coda_expression *expr, const coda_cursor *cursor, int64_t *value);
LIBCODA_API int coda_expression_eval_float(const coda_expression *expr, const coda_cursor *cursor, double *value);
LIBCODA_API int coda_expression_eval_string(const coda_expression *expr, const coda_cursor *cursor, char **value,
                                            long *length);
LIBCODA_API int coda_expression_eval_node(const coda_expression *expr, coda_cursor *cursor);

LIBCODA_API int coda_expression_print(const coda_expression *expr, int (*print) (const char *, ...));


/* DO NOT USE ANY OF THE FIELDS CONTAINED IN THE RECORDS BELOW! */

#ifndef SWIG

#ifdef CODA_INTERNAL
#define CODA_PRIVATE_FIELD(name) name
#else
#define CODA_PRIVATE_FIELD(name) coda_private_field_ ## name
#endif

#define CODA_CURSOR_MAXDEPTH 32

struct coda_cursor_struct
{
    struct coda_product_struct *CODA_PRIVATE_FIELD(product);
    int CODA_PRIVATE_FIELD(n);
    struct
    {
        struct coda_dynamic_type_struct *type;
        long index;
        int64_t bit_offset;
    } CODA_PRIVATE_FIELD(stack)[CODA_CURSOR_MAXDEPTH];
};

#endif /* SWIG */

/* *INDENT-OFF* */
#ifdef __cplusplus
}
#endif
/* *INDENT-ON* */

#endif
