#ifndef NCTYPES_H
#define NCTYPES_H
#include <netcdf.h>
#include "mars.h"

/*==========================================*/

typedef struct netcdf_attribute {
    struct netcdf_attribute* next;
    char* owner;
    char* name;
    int id;
    int type;
    int len;

    short short_value;
    long long_value;
    char* char_value;
    float float_value;
    double double_value;

    boolean cleared;

} netcdf_attribute;

typedef struct netcdf_attribute_list {
    netcdf_attribute* first;
    netcdf_attribute* last;
    int cnt;
} netcdf_attribute_list;

typedef struct netcdf_dimension {
    struct netcdf_dimension* next;
    struct netcdf_field* owner;

    char* name;
    int id;
    int len;

    int write_id;

    boolean cleared;
} netcdf_dimension;

typedef struct netcdf_dimension_list {
    netcdf_dimension* first;
    netcdf_dimension* last;
    int cnt;
} netcdf_dimension_list;


typedef struct netcdf_hypercube {
    size_t ndims;
    netcdf_dimension* dims[NC_MAX_VAR_DIMS];
} netcdf_hypercube;

typedef struct netcdf_variable {
    struct netcdf_variable* next;
    struct netcdf_field* owner;


    char* name;
    int id;
    int type;
    int nattr;

    netcdf_attribute_list attributes;
    netcdf_hypercube cube;


    int write_id;


    boolean cleared;

} netcdf_variable;

typedef struct netcdf_variable_list {
    netcdf_variable* first;
    netcdf_variable* last;
    int cnt;
} netcdf_variable_list;

struct netcdf_field {
    struct netcdf_field* next;
    char* path;
    int tmp;

    int number_of_dimensions;
    int number_of_variables;
    int number_of_global_attributes;
    int id_of_unlimited_dimension;
    int format;

    netcdf_attribute_list global_attributes;
    netcdf_variable_list variables;
    netcdf_dimension_list dimensions;

    size_t nvars;
    netcdf_variable** variables_by_dimensions;
    netcdf_variable** variables_by_natural_order;
};


struct netcdf_schema {
    netcdf_field_list fields;
};

const char* netcdf_type_name(int type);
size_t netcdf_type_size(int type);
netcdf_attribute* netcdf_attribute_new(netcdf_attribute_list* list, const char* owner, const char* name, int id, int type, int len);
netcdf_attribute* netcdf_attribute_clone(netcdf_attribute_list* list, netcdf_attribute* c);

netcdf_attribute* netcdf_attribute_by_name(netcdf_attribute_list* list, const char* name);

netcdf_dimension* netcdf_dimension_new(netcdf_dimension_list* list, netcdf_field* owner, const char* name, int id, int len);
netcdf_dimension* netcdf_dimension_clone(netcdf_field* target, netcdf_dimension_list* list, netcdf_dimension* c);
netcdf_dimension* netcdf_dimension_by_name(netcdf_dimension_list* list, const char* name);


netcdf_variable* netcdf_variable_new(netcdf_variable_list* list, netcdf_field* owner,
                                     netcdf_dimension_list* dim_list, const char* name, int id, int type, int ndims, int* dims, int nattr);
netcdf_variable* netcdf_variable_clone(netcdf_field* target, netcdf_variable_list* list, netcdf_variable* c);


netcdf_field* netcdf_field_new(netcdf_field_list* list, const char* path, int tmp);
void netcdf_field_delete(netcdf_field_list* list);
void netcdf_field_print(netcdf_field_list* list, int depth);


netcdf_variable* netcdf_variable_by_name(netcdf_variable_list* list, const char* name);
size_t netcdf_variable_number_of_values(netcdf_variable* c);
void* netcdf_variable_get_values(netcdf_variable* c, size_t*);
netcdf_variable* netcdf_dimension_get_variable(netcdf_dimension* d);

err netcdf_variable_by_dimension(netcdf_variable_list* list, netcdf_dimension* d, netcdf_variable* result[], size_t* count);

#endif
