/*
* Copyright (C) 2015-2023 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 HARP_H
#define HARP_H

#include <stdarg.h>

/** \file */

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

#if defined(WIN32) && defined(LIBHARPDLL)
#ifdef LIBHARPDLL_EXPORTS
#define LIBHARP_API __declspec(dllexport)
#else
#define LIBHARP_API __declspec(dllimport)
#endif
#else
#define LIBHARP_API
#endif

#ifndef HARP_CONFIG_H

/* These are the 'configure' defines that we need to export.
 * However, we need to assume that the user of harp.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
#undef HAVE_INTTYPES_H
#endif
#ifndef HAVE_STDINT_H
#undef HAVE_STDINT_H
#endif
#ifndef HAVE_SYS_TYPES_H
#undef HAVE_SYS_TYPES_H
#endif

#ifndef int8_t
#undef int8_t
#endif
#ifndef int16_t
#undef int16_t
#endif
#ifndef int32_t
#undef int32_t
#endif
#ifndef int64_t
#undef int64_t
#endif

#ifndef uint8_t
#undef uint8_t
#endif
#ifndef uint16_t
#undef uint16_t
#endif
#ifndef uint32_t
#undef uint32_t
#endif
#ifndef uint64_t
#undef 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

#endif /* HARP_CONFIG_H */

/* *CFFI-ON* */

LIBHARP_API extern const char *libharp_version;

/** Maximum number of dimensions of a multidimensional array. */
#define HARP_MAX_NUM_DIMS       (8)

LIBHARP_API extern int harp_errno;

#define HARP_SUCCESS                                           (0)
#define HARP_ERROR_OUT_OF_MEMORY                              (-1)

#define HARP_ERROR_HDF4                                     (-100)
#define HARP_ERROR_NO_HDF4_SUPPORT                          (-101)
#define HARP_ERROR_HDF5                                     (-102)
#define HARP_ERROR_NO_HDF5_SUPPORT                          (-103)
#define HARP_ERROR_NETCDF                                   (-104)
#define HARP_ERROR_CODA                                     (-105)

#define HARP_ERROR_FILE_NOT_FOUND                           (-200)
#define HARP_ERROR_FILE_OPEN                                (-201)
#define HARP_ERROR_FILE_CLOSE                               (-202)
#define HARP_ERROR_FILE_READ                                (-203)
#define HARP_ERROR_FILE_WRITE                               (-204)

#define HARP_ERROR_INVALID_ARGUMENT                         (-300)
#define HARP_ERROR_INVALID_INDEX                            (-301)
#define HARP_ERROR_INVALID_NAME                             (-302)
#define HARP_ERROR_INVALID_FORMAT                           (-303)
#define HARP_ERROR_INVALID_DATETIME                         (-304)
#define HARP_ERROR_INVALID_TYPE                             (-305)
#define HARP_ERROR_INVALID_PRODUCT                          (-306)
#define HARP_ERROR_INVALID_VARIABLE                         (-307)
#define HARP_ERROR_ARRAY_NUM_DIMS_MISMATCH                  (-308)
#define HARP_ERROR_ARRAY_OUT_OF_BOUNDS                      (-309)
#define HARP_ERROR_VARIABLE_NOT_FOUND                       (-310)

#define HARP_ERROR_UNIT_CONVERSION                          (-400)

#define HARP_ERROR_OPERATION                                (-500)
#define HARP_ERROR_OPERATION_SYNTAX                         (-501)

#define HARP_ERROR_IMPORT                                   (-600)
#define HARP_ERROR_EXPORT                                   (-601)

#define HARP_ERROR_INGESTION                                (-700)
#define HARP_ERROR_INGESTION_OPTION_SYNTAX                  (-701)
#define HARP_ERROR_INVALID_INGESTION_OPTION                 (-702)
#define HARP_ERROR_INVALID_INGESTION_OPTION_VALUE           (-703)

#define HARP_ERROR_UNSUPPORTED_PRODUCT                      (-800)

#define HARP_ERROR_NO_DATA                                  (-900)

/* *CFFI-OFF* */

/** Default units used in HARP */
#define HARP_UNIT_ACCELERATION "m/s2"
#define HARP_UNIT_AEROSOL_EXTINCTION "1/m"
#define HARP_UNIT_AEROSOL_EXTINCTION_SQUARED "(1/m)2"
#define HARP_UNIT_ANGLE "degree"
#define HARP_UNIT_AREA "m2"
#define HARP_UNIT_COLUMN_MASS_DENSITY "kg/m2"
#define HARP_UNIT_COLUMN_MASS_DENSITY_SQUARED "(kg/m2)2"
#define HARP_UNIT_COLUMN_NUMBER_DENSITY "molec/m2"
#define HARP_UNIT_COLUMN_NUMBER_DENSITY_SQUARED "(molec/m2)2"
#define HARP_UNIT_DATETIME "s since 2000-01-01"
#define HARP_UNIT_DIMENSIONLESS ""
#define HARP_UNIT_FREQUENCY "Hz"
#define HARP_UNIT_GEOPOTENTIAL "m2/s2"
#define HARP_UNIT_IRRADIANCE "W/m2"
#define HARP_UNIT_LATITUDE "degree_north"
#define HARP_UNIT_LENGTH "m"
#define HARP_UNIT_LONGITUDE "degree_east"
#define HARP_UNIT_MASS_DENSITY "kg/m3"
#define HARP_UNIT_MASS_MIXING_RATIO "kg/kg"
#define HARP_UNIT_MASS_MIXING_RATIO_SQUARED "(kg/kg)2"
#define HARP_UNIT_MOLAR_MASS "g/mol"
#define HARP_UNIT_NUMBER_DENSITY "molec/m3"
#define HARP_UNIT_NUMBER_DENSITY_SQUARED "(molec/m3)2"
#define HARP_UNIT_PERCENT "%"
#define HARP_UNIT_PRESSURE "Pa"
#define HARP_UNIT_RADIANCE "W/(sr m2)"
#define HARP_UNIT_SPEED "m/s"
#define HARP_UNIT_TEMPERATURE "K"
#define HARP_UNIT_TIME "s"
#define HARP_UNIT_VOLUME_MIXING_RATIO "ppv"
#define HARP_UNIT_VOLUME_MIXING_RATIO_SQUARED "(ppv)2"
#define HARP_UNIT_WAVELENGTH "m"
#define HARP_UNIT_WAVENUMBER "1/m"

/* *CFFI-ON* */

/** \addtogroup harp_general
 * @{
 */

enum harp_data_type_enum
{
    harp_type_int8,     /**< BYTE */
    harp_type_int16,    /**< INTEGER */
    harp_type_int32,    /**< LONG */
    harp_type_float,    /**< FLOAT */
    harp_type_double,   /**< DOUBLE */
    harp_type_string    /**< STRING */
};
typedef enum harp_data_type_enum harp_data_type;

#define HARP_NUM_DATA_TYPES (6)

union harp_scalar_union
{
    int8_t int8_data;
    int16_t int16_data;
    int32_t int32_data;
    float float_data;
    double double_data;
};
typedef union harp_scalar_union harp_scalar;

union harp_array_union
{
    int8_t *int8_data;
    int16_t *int16_data;
    int32_t *int32_data;
    float *float_data;
    double *double_data;
    char **string_data;
    void *ptr;
};
typedef union harp_array_union harp_array;

enum harp_dimension_type_enum
{
    harp_dimension_independent = -1,
    harp_dimension_time,
    harp_dimension_latitude,
    harp_dimension_longitude,
    harp_dimension_vertical,
    harp_dimension_spectral
};
typedef enum harp_dimension_type_enum harp_dimension_type;

#define HARP_NUM_DIM_TYPES  (5)

/** @} */

/** \addtogroup harp_variable
 * @{
 */

/** HARP Variable struct */
struct harp_variable_struct
{
    char *name; /**< name of variable */
    harp_data_type data_type; /**< storage type of the data */
    int num_dimensions; /**< number of array dimensions */
    harp_dimension_type dimension_type[HARP_MAX_NUM_DIMS]; /**< type of each of the array dimensions */
    long dimension[HARP_MAX_NUM_DIMS];  /**< length of each of the array dimensions */
    long num_elements;  /**< total number of elements (equals product of array dimensions) */
    harp_array data;    /**< array data of the variable */
    /* special attributes - the harp_scalar attributes are only valid if data_type != harp_type_string */
    char *description;  /**< corresponds to netCDF long_name */
    char *unit; /**< corresponds to netCDF units */
    harp_scalar valid_min;      /**< corresponds to netCDF valid_min or valid_range[0] */
    harp_scalar valid_max;      /**< corresponds to netCDF valid_max or valid_range[1] */
    int num_enum_values;        /**< number of enumeration values (which map to values 0..N-1 in 'data') */
    char **enum_name;           /**< name of each enumeration value */
};

/** HARP Variable typedef */
typedef struct harp_variable_struct harp_variable;

/** @} */

/** \addtogroup harp_product
 * @{
 */

/** HARP Product struct */
struct harp_product_struct
{
    long dimension[HARP_NUM_DIM_TYPES]; /**< length of each dimension (0 for unused dimensions) */
    int num_variables;  /**< number of variables in this product */
    harp_variable **variable;   /**< pointers to the variables */
    char *source_product; /**< identifier of the product the HARP product originates from */
    char *history;  /**< value for the 'history' global attribute */
};

/** HARP Product typedef */
typedef struct harp_product_struct harp_product;

/** @} */

/** \addtogroup harp_product_metadata
 * @{
 */

/** HARP Product Metadata struct */
struct harp_product_metadata_struct
{
    char *filename;
    double datetime_start;
    double datetime_stop;
    long dimension[HARP_NUM_DIM_TYPES];
    char *format;
    char *source_product;
    char *history;
};

/** HARP Product Metadata typedef */
typedef struct harp_product_metadata_struct harp_product_metadata;

/** @} */

/** \addtogroup harp_dataset
 * @{
 */

/** HARP Dataset struct */
struct harp_dataset_struct
{
    struct hashtable_struct *product_to_index;  /* maps source_product names to indices */
    char **source_product;      /* set of source products - every source appears only once */
    long *sorted_index; /* indices of products sorted by source_product name */
    long num_products;
    harp_product_metadata **metadata;   /* stores metadata for source in source_product */
};

/** HARP Dataset typedef */
typedef struct harp_dataset_struct harp_dataset;

/** @} */

/** \addtogroup harp_collocation
 * @{
 */

/** Entry for a single matched pair for a collocation between a dataset A and dataset B */
struct harp_collocation_pair_struct
{
    long collocation_index;
    long product_index_a;       /* index into dataset_a of associated collocation result */
    long sample_index_a;
    long product_index_b;       /* index into dataset_b of associated collocation result */
    long sample_index_b;
    int num_differences;
    double *difference;
};

typedef struct harp_collocation_pair_struct harp_collocation_pair;

/** HARP Collocation result */
struct harp_collocation_result_struct
{
    harp_dataset *dataset_a;
    harp_dataset *dataset_b;
    int num_differences;
    char **difference_variable_name;
    char **difference_unit;
    long num_pairs;
    harp_collocation_pair **pair;
};
typedef struct harp_collocation_result_struct harp_collocation_result;

/** @} */


/* General */
LIBHARP_API int harp_init(void);
LIBHARP_API void harp_done(void);

LIBHARP_API int harp_isfinite(double x);
LIBHARP_API int harp_isnan(double x);
LIBHARP_API double harp_nan(void);
LIBHARP_API int harp_isinf(double x);
LIBHARP_API int harp_isplusinf(double x);
LIBHARP_API int harp_ismininf(double x);
LIBHARP_API double harp_plusinf(void);
LIBHARP_API double harp_mininf(void);

LIBHARP_API const char *harp_basename(const char *path);

LIBHARP_API long harp_get_size_for_type(harp_data_type data_type);

LIBHARP_API harp_scalar harp_get_fill_value_for_type(harp_data_type data_type);
LIBHARP_API harp_scalar harp_get_valid_min_for_type(harp_data_type data_type);
LIBHARP_API harp_scalar harp_get_valid_max_for_type(harp_data_type data_type);
LIBHARP_API int harp_is_fill_value_for_type(harp_data_type data_type, harp_scalar value);
LIBHARP_API int harp_is_valid_min_for_type(harp_data_type data_type, harp_scalar value);
LIBHARP_API int harp_is_valid_max_for_type(harp_data_type data_type, harp_scalar value);

LIBHARP_API const char *harp_get_data_type_name(harp_data_type data_type);
LIBHARP_API const char *harp_get_dimension_type_name(harp_dimension_type dimension_type);

LIBHARP_API int harp_parse_dimension_type(const char *str, harp_dimension_type *dimension_type);

LIBHARP_API int harp_set_coda_definition_path(const char *path);
LIBHARP_API int harp_set_coda_definition_path_conditional(const char *file, const char *searchpath,
                                                          const char *relative_location);
LIBHARP_API int harp_set_udunits2_xml_path(const char *path);
LIBHARP_API int harp_set_udunits2_xml_path_conditional(const char *file, const char *searchpath,
                                                       const char *relative_location);

LIBHARP_API int harp_set_option_create_collocation_datetime(int enable);
LIBHARP_API int harp_get_option_create_collocation_datetime(void);
LIBHARP_API int harp_set_option_enable_aux_afgl86(int enable);
LIBHARP_API int harp_get_option_enable_aux_afgl86(void);
LIBHARP_API int harp_set_option_enable_aux_usstd76(int enable);
LIBHARP_API int harp_get_option_enable_aux_usstd76(void);
LIBHARP_API int harp_set_option_hdf5_compression(int level);
LIBHARP_API int harp_get_option_hdf5_compression(void);
LIBHARP_API int harp_set_option_propagate_uncertainty(int method);
LIBHARP_API int harp_get_option_propagate_uncertainty(void);
LIBHARP_API int harp_set_option_regrid_out_of_bounds(int method);
LIBHARP_API int harp_get_option_regrid_out_of_bounds(void);

LIBHARP_API int harp_convert_unit(const char *from_unit, const char *to_unit, long num_values, double *value);

/* Generated documentation */
LIBHARP_API int harp_doc_list_conversions(const harp_product *product, const char *variable_name,
                                          int (*print)(const char *, ...));
LIBHARP_API int harp_doc_export_ingestion_definitions(const char *path);

/* Geometry */
LIBHARP_API int harp_geometry_get_point_distance(double latitude_a, double longitude_a, double latitude_b,
                                                 double longitude_b, double *distance);
LIBHARP_API int harp_geometry_get_area(int num_vertices, double *latitude_bounds, double *longitude_bounds,
                                       double *area);
LIBHARP_API int harp_geometry_has_point_in_area(double latitude_point, double longitude_point, int num_vertices,
                                                double *latitude_bounds, double *longitude_bounds, int *in_area);
LIBHARP_API int harp_geometry_has_area_overlap(int num_vertices_a, double *latitude_bounds_a,
                                               double *longitude_bounds_a, int num_vertices_b,
                                               double *latitude_bounds_b, double *longitude_bounds_b, int *has_overlap,
                                               double *fraction);

/* Error */
LIBHARP_API void harp_set_error(int err, const char *message, ...);
LIBHARP_API void harp_add_error_message(const char *message, ...);
LIBHARP_API const char *harp_errno_to_string(int err);
LIBHARP_API int harp_report_warning(const char *message, ...);

/* *CFFI-OFF* */
LIBHARP_API int harp_get_warning_handler(int (**print)(const char *, va_list ap));
LIBHARP_API int harp_set_warning_handler(int (*print)(const char *, va_list ap));

/* *CFFI-ON* */

/* Variables */
LIBHARP_API int harp_variable_new(const char *name, harp_data_type data_type, int num_dimensions,
                                  const harp_dimension_type *dimension_type, const long *dimension,
                                  harp_variable **new_variable);
LIBHARP_API void harp_variable_delete(harp_variable *variable);
LIBHARP_API int harp_variable_copy(const harp_variable *variable, harp_variable **new_variable);
LIBHARP_API int harp_variable_copy_attributes(const harp_variable *variable, harp_variable *target_variable);
LIBHARP_API int harp_variable_append(harp_variable *variable, const harp_variable *other_variable);
LIBHARP_API int harp_variable_rename(harp_variable *variable, const char *name);
LIBHARP_API int harp_variable_set_description(harp_variable *variable, const char *description);
LIBHARP_API int harp_variable_set_unit(harp_variable *variable, const char *unit);
LIBHARP_API int harp_variable_set_enumeration_values(harp_variable *variable, int num_enum_values,
                                                     const char **enum_name);
LIBHARP_API int harp_variable_set_string_data_element(harp_variable *variable, long index, const char *str);
LIBHARP_API int harp_variable_convert_data_type(harp_variable *variable, harp_data_type target_data_type);
LIBHARP_API int harp_variable_convert_unit(harp_variable *variable, const char *target_unit);
LIBHARP_API int harp_variable_has_dimension_type(const harp_variable *variable, harp_dimension_type dimension_type);
LIBHARP_API int harp_variable_has_dimension_types(const harp_variable *variable, int num_dimensions,
                                                  const harp_dimension_type *dimension_type);
LIBHARP_API int harp_variable_has_unit(const harp_variable *variable, const char *unit);
LIBHARP_API int harp_variable_verify(const harp_variable *variable);
LIBHARP_API void harp_variable_print(harp_variable *variable, int show_attributes, int (*print)(const char *, ...));
LIBHARP_API void harp_variable_print_data(harp_variable *variable, int (*print)(const char *, ...));

LIBHARP_API int harp_variable_smooth_vertical(harp_variable *variable, harp_variable *vertical_axis,
                                              harp_variable *averaging_kernel, harp_variable *apriori);

/* Product */
LIBHARP_API int harp_product_new(harp_product **new_product);
LIBHARP_API void harp_product_delete(harp_product *product);
LIBHARP_API int harp_product_copy(const harp_product *product, harp_product **new_product);
LIBHARP_API int harp_product_append(harp_product *product, harp_product *other_product);
LIBHARP_API int harp_product_set_source_product(harp_product *product, const char *product_path);
LIBHARP_API int harp_product_set_history(harp_product *product, const char *history);
LIBHARP_API int harp_product_add_variable(harp_product *product, harp_variable *variable);
LIBHARP_API int harp_product_detach_variable(harp_product *product, const harp_variable *variable);
LIBHARP_API int harp_product_remove_variable(harp_product *product, harp_variable *variable);
LIBHARP_API int harp_product_remove_variable_by_name(harp_product *product, const char *name);
LIBHARP_API int harp_product_replace_variable(harp_product *product, harp_variable *variable);
LIBHARP_API int harp_product_is_empty(const harp_product *product);
LIBHARP_API int harp_product_has_variable(const harp_product *product, const char *name);
LIBHARP_API int harp_product_get_variable_by_name(const harp_product *product, const char *name,
                                                  harp_variable **variable);
LIBHARP_API int harp_product_get_variable_index_by_name(const harp_product *product, const char *name, int *index);
LIBHARP_API int harp_product_get_derived_variable(const harp_product *product, const char *name,
                                                  const harp_data_type *data_type, const char *unit, int num_dimensions,
                                                  const harp_dimension_type *dimension_type, harp_variable **variable);
LIBHARP_API int harp_product_add_derived_variable(harp_product *product, const char *name,
                                                  const harp_data_type *data_type, const char *unit, int num_dimensions,
                                                  const harp_dimension_type *dimension_type);
LIBHARP_API int harp_product_update_history(harp_product *product, const char *executable, int argc, char *argv[]);
LIBHARP_API int harp_product_verify(const harp_product *product);
LIBHARP_API int harp_product_execute_operations(harp_product *product, const char *operations);
LIBHARP_API void harp_product_print(const harp_product *product, int show_attributes, int show_data,
                                    int (*print)(const char *, ...));

LIBHARP_API int harp_product_flatten_dimension(harp_product *product, harp_dimension_type dimension_name);
LIBHARP_API int harp_product_sort(harp_product *product, int num_variables, const char **variable_name);
LIBHARP_API int harp_product_bin(harp_product *product, long num_bins, long num_elements, long *bin_index);
LIBHARP_API int harp_product_bin_spatial(harp_product *product, long num_time_bins, long num_time_elements,
                                         long *time_bin_index, long num_latitude_edges, double *latitude_edges,
                                         long num_longitude_edges, double *longitude_edges);
LIBHARP_API int harp_product_rebin_with_axis_bounds_variable(harp_product *product, harp_variable *target_bounds);
LIBHARP_API int harp_product_regrid_with_axis_variable(harp_product *product, harp_variable *target_grid,
                                                       harp_variable *target_bounds);
LIBHARP_API int harp_product_regrid_with_collocated_product(harp_product *product, harp_dimension_type dimension_type,
                                                            const char *axis_name, const char *axis_unit,
                                                            const harp_product *collocated_product);
LIBHARP_API int harp_product_regrid_with_collocated_dataset(harp_product *product, harp_dimension_type dimension_type,
                                                            const char *axis_name, const char *axis_unit,
                                                            harp_collocation_result *collocation_result);
LIBHARP_API int harp_product_smooth_vertical_with_collocated_product(harp_product *product, int num_smooth_variables,
                                                                     const char **smooth_variables,
                                                                     const char *vertical_axis,
                                                                     const char *vertical_unit,
                                                                     const harp_product *collocated_product);
LIBHARP_API int harp_product_smooth_vertical_with_collocated_dataset(harp_product *product, int num_smooth_variables,
                                                                     const char **smooth_variables,
                                                                     const char *vertical_axis,
                                                                     const char *vertical_unit,
                                                                     const harp_collocation_result *collocation_result);
LIBHARP_API int harp_product_get_smoothed_column(harp_product *product, const char *name, const char *unit,
                                                 harp_variable *vertical_grid, harp_variable *vertical_bounds,
                                                 harp_variable *column_avk, harp_variable *apriori,
                                                 harp_variable **variable);
LIBHARP_API int harp_product_get_smoothed_column_using_collocated_product(harp_product *product, const char *name,
                                                                          const char *unit, int num_dimensions,
                                                                          const harp_dimension_type *dimension_type,
                                                                          const char *vertical_axis,
                                                                          const char *vertical_unit,
                                                                          const harp_product *collocated_product,
                                                                          harp_variable **variable);
LIBHARP_API int harp_product_get_smoothed_column_using_collocated_dataset(harp_product *product, const char *name,
                                                                          const char *unit, int num_dimensions,
                                                                          const harp_dimension_type *dimension_type,
                                                                          const char *vertical_axis,
                                                                          const char *vertical_unit,
                                                                          const harp_collocation_result
                                                                          *collocation_result,
                                                                          harp_variable **variable);

/* Product Metadata */
LIBHARP_API int harp_import_product_metadata(const char *filename, const char *options,
                                             harp_product_metadata **metadata);
LIBHARP_API int harp_product_metadata_new(harp_product_metadata **new_metadata);
LIBHARP_API void harp_product_metadata_delete(harp_product_metadata *metadata);
LIBHARP_API void harp_product_metadata_print(harp_product_metadata *metadata, int (*print)(const char *, ...));

/* Dataset */
LIBHARP_API int harp_dataset_import(harp_dataset *dataset, const char *path, const char *options);
LIBHARP_API int harp_dataset_new(harp_dataset **dataset);
LIBHARP_API void harp_dataset_delete(harp_dataset *dataset);
LIBHARP_API void harp_dataset_print(harp_dataset *dataset, int (*print)(const char *, ...));
LIBHARP_API int harp_dataset_get_index_from_source_product(harp_dataset *dataset, const char *source_product,
                                                           long *index);
LIBHARP_API int harp_dataset_has_product(harp_dataset *dataset, const char *source_product);
LIBHARP_API int harp_dataset_add_product(harp_dataset *dataset, const char *source_product,
                                         harp_product_metadata *metadata);
LIBHARP_API int harp_dataset_prefilter(harp_dataset *dataset, const char *operations);

/* Import */
LIBHARP_API int harp_import(const char *filename, const char *operations, const char *options, harp_product **product);
LIBHARP_API int harp_import_test(const char *filename, int (*print)(const char *, ...));

/* Export */
LIBHARP_API int harp_export(const char *filename, const char *format, const harp_product *product);

/* Collocation result functions */
LIBHARP_API int harp_collocation_result_new(harp_collocation_result **new_collocation_result, int num_differences,
                                            const char **difference_variable_name, const char **difference_unit);
LIBHARP_API void harp_collocation_result_delete(harp_collocation_result *collocation_result);
LIBHARP_API int harp_collocation_result_sort_by_a(harp_collocation_result *collocation_result);
LIBHARP_API int harp_collocation_result_sort_by_b(harp_collocation_result *collocation_result);
LIBHARP_API int harp_collocation_result_sort_by_collocation_index(harp_collocation_result *collocation_result);
LIBHARP_API int harp_collocation_result_filter_for_source_product_a(harp_collocation_result *collocation_result,
                                                                    const char *source_product);
LIBHARP_API int harp_collocation_result_filter_for_source_product_b(harp_collocation_result *collocation_result,
                                                                    const char *source_product);
LIBHARP_API int harp_collocation_result_filter_for_collocation_indices(harp_collocation_result *collocation_result,
                                                                       long num_indices, int32_t *collocation_index);
LIBHARP_API int harp_collocation_result_add_pair(harp_collocation_result *collocation_result, long collocation_index,
                                                 const char *source_product_a, long index_a,
                                                 const char *source_product_b, long index_b, int num_differences,
                                                 const double *difference);
LIBHARP_API int harp_collocation_result_remove_pair_at_index(harp_collocation_result *collocation_result, long index);
LIBHARP_API int harp_collocation_result_read(const char *collocation_result_filename,
                                             harp_collocation_result **new_collocation_result);
LIBHARP_API int harp_collocation_result_write(const char *collocation_result_filename,
                                              harp_collocation_result *collocation_result);
LIBHARP_API void harp_collocation_result_swap_datasets(harp_collocation_result *collocation_result);

/* *CFFI-OFF* */

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

#endif
