/* This is part of the netCDF package. Copyright 2018 University
   Corporation for Atmospheric Research/Unidata See COPYRIGHT file for
   conditions of use. See www.unidata.ucar.edu for more info.

   Create a test file with a compound type and compound data for ncdump to read.

   $Id: tst_comp.c,v 1.7 2008/10/20 01:48:08 ed Exp $
*/


#include <nc_tests.h>
#include "err_macros.h"
#include <netcdf.h>
#include <string.h>

#define FILE6_NAME "tst_comp.nc"
#define TYPE6_NAME "obs_t"
#define DIM6_NAME "n"
#define DIM6_LEN 3
#define VAR6_NAME "obs"
#define VAR6_RANK 1
#define ATT6_NAME "_FillValue"
#define ATT6_LEN  1

int
main(int argc, char **argv)
{
   int ncid;
   int dimid, varid;
   nc_type typeid;
   char name_in[NC_MAX_NAME+1];
   int i;

   int var_dims[VAR6_RANK];

   typedef struct obs_t {
       char day;
       short elev;
       int count;
       float relhum;
       double time;
       unsigned char category;
       unsigned short id;
       unsigned int particularity;
       long long attention_span;
   } obs_t ;

   obs_t obsdata[DIM6_LEN] = {
       {15, 2, 1, 0.5, 3600.01, 0, 0, 0, 0LL},
       {-99, -99, -99, -99.0f, -99.0, 255, 65535, 4294967295U,
	-9223372036854775806LL},
       {20, 6, 3, 0.75, 5000.01, 200, 64000, 4220002000U, 9000000000000000000LL }
   };

   obs_t missing_val = {-99, -99, -99, -99, -99, 255, 65535, 4294967295U,
			-9223372036854775806LL};
   obs_t val_in;
   size_t size_in;
   size_t nfields_in;
   nc_type class_in;

   printf("\n*** Testing compound types.\n");
   printf("*** creating compound test file %s...", FILE6_NAME);
   if (nc_create(FILE6_NAME, NC_CLOBBER | NC_NETCDF4, &ncid)) ERR;

   /* Create a compound type. */
   if (nc_def_compound(ncid, sizeof(obs_t), TYPE6_NAME, &typeid)) ERR;
   if (nc_insert_compound(ncid, typeid, "day",
			  NC_COMPOUND_OFFSET(struct obs_t, day), NC_BYTE)) ERR;
   if (nc_insert_compound(ncid, typeid, "elev",
			  NC_COMPOUND_OFFSET(struct obs_t, elev), NC_SHORT)) ERR;
   if (nc_insert_compound(ncid, typeid, "count",
			  NC_COMPOUND_OFFSET(struct obs_t, count), NC_INT)) ERR;
   if (nc_insert_compound(ncid, typeid, "relhum",
			  NC_COMPOUND_OFFSET(struct obs_t, relhum),
			  NC_FLOAT)) ERR;
   if (nc_insert_compound(ncid, typeid, "time",
			  NC_COMPOUND_OFFSET(struct obs_t, time),
			  NC_DOUBLE)) ERR;
   if (nc_insert_compound(ncid, typeid, "category",
			  NC_COMPOUND_OFFSET(struct obs_t, category),
			  NC_UBYTE)) ERR;
   if (nc_insert_compound(ncid, typeid, "id",
			  NC_COMPOUND_OFFSET(struct obs_t, id),
			  NC_USHORT)) ERR;
   if (nc_insert_compound(ncid, typeid, "particularity",
			  NC_COMPOUND_OFFSET(struct obs_t, particularity),
			  NC_UINT)) ERR;
   if (nc_insert_compound(ncid, typeid, "attention_span",
			  NC_COMPOUND_OFFSET(struct obs_t, attention_span),
			  NC_INT64)) ERR;

   /* Declare a dimension for number of obs */
   if (nc_def_dim(ncid, DIM6_NAME, DIM6_LEN, &dimid)) ERR;

   /* Declare a variable of the compound type */
   var_dims[0] = dimid;
   if (nc_def_var(ncid, VAR6_NAME, typeid, VAR6_RANK, var_dims, &varid)) ERR;

   /* Create and write a variable attribute of the compound type */
   if (nc_put_att(ncid, varid, ATT6_NAME, typeid, ATT6_LEN, (void *) &missing_val)) ERR;
   if (nc_enddef(ncid)) ERR;

   /* Store data, writing all values in one call */
   if(nc_put_var(ncid, varid, obsdata)) ERR;

   /* Write the file. */
   if (nc_close(ncid)) ERR;

   /* Check it out. */

   /* Reopen the file. */
   if (nc_open(FILE6_NAME, NC_NOWRITE, &ncid)) ERR;

   /* Get info with the generic inquire for user-defined types */
   if (nc_inq_user_type(ncid, typeid, name_in, NULL, NULL,
			NULL, &class_in)) ERR;
   if (strcmp(name_in, TYPE6_NAME) ||
       class_in != NC_COMPOUND) ERR;

   /* Get the same info with the compound-specific inquire function */
   if (nc_inq_compound(ncid, typeid, name_in, &size_in, &nfields_in)) ERR;
   if (strcmp(name_in, TYPE6_NAME) ||
       size_in != sizeof(obs_t) ||
       nfields_in != 9) ERR;

   if (nc_inq_varid(ncid, VAR6_NAME, &varid)) ERR;

   /* Read in attribute value and check it */
   if (nc_get_att(ncid, varid, ATT6_NAME, &val_in)) ERR;
   if (val_in.day != missing_val.day ||
       val_in.elev != missing_val.elev ||
       val_in.count != missing_val.count ||
       val_in.relhum != missing_val.relhum ||
       val_in.time != missing_val.time ||
       val_in.category != missing_val.category ||
       val_in.id != missing_val.id ||
       val_in.particularity != missing_val.particularity ||
       val_in.attention_span != missing_val.attention_span ) ERR;

   /* Read in each value and check */
   for (i = 0; i < DIM6_LEN; i++) {
       size_t index[VAR6_RANK];
       index[0] = i;
       if (nc_get_var1(ncid, varid, index, (void *) &val_in)) ERR;
       if (val_in.day != obsdata[i].day) ERR;
       if (val_in.elev != obsdata[i].elev) ERR;
       if (val_in.count != obsdata[i].count) ERR;
       if (val_in.relhum != obsdata[i].relhum) ERR;
       if (val_in.time != obsdata[i].time) ERR;
       if (val_in.category != obsdata[i].category) ERR;
       if (val_in.id != obsdata[i].id) ERR;
       if (val_in.particularity != obsdata[i].particularity) ERR;
       if (val_in.attention_span != obsdata[i].attention_span) ERR;
   }

   if (nc_close(ncid)) ERR;

   SUMMARIZE_ERR;
   FINAL_RESULTS;
}
