/*********************************************************************
 *   Copyright 1992, University Corporation for Atmospheric Research
 *   See netcdf/README file for copying and redistribution conditions.
 *
 *   Purpose:   C++ class interface for netCDF
 *
 *   $Header: /afs/ncsa/projects/hdf/cvs/hdf4/mfhdf/c++/netcdf.hh,v 1.2 1993/04/30 20:29:48 koziol Exp $
 *********************************************************************/

#ifndef NETCDF_HH
#define NETCDF_HH

#include "netcdf.h"             // the C interface
#include "ncvalues.hh"          // arrays that know their element type

typedef const char* NcToken;    // names for netCDF objects
typedef unsigned int NcBool;    // many members return 0 on failure

class NcDim;                    // dimensions
class NcVar;                    // variables
class NcAtt;                    // attributes


/*
 * ***********************************************************************
 * Abstract base class for netCDF files.  The concrete derived classes are
 * NcOldFile and NcNewFile.
 * ***********************************************************************
 */
class NcFile
{
  public:

    // Pure destructor used to make this an abstract base class.
    virtual ~NcFile( void )=0;

    NcBool is_valid( void ) const;         // opened OK in ctr, still valid

    int num_dims( void ) const;            // number of dimensions
    int num_vars( void ) const;            // number of variables
    int num_atts( void ) const;            // number of (global) attributes

    NcDim* get_dim( NcToken ) const;       // dimension by name
    NcVar* get_var( NcToken ) const;       // variable by name
    NcAtt* get_att( NcToken ) const;       // global attribute by name

    NcDim* get_dim( int ) const;           // n-th dimension
    NcVar* get_var( int ) const;           // n-th variable
    NcAtt* get_att( int ) const;           // n-th global attribute
    NcDim* rec_dim( void ) const;          // unlimited dimension, if any
    
    // Add new dimensions, variables, global attributes.
    // These put the file in "define" mode, so could be expensive.
    NcDim* add_dim( NcToken dimname, long dimsize );
    NcDim* add_dim( NcToken dimname );     // unlimited

    NcVar* add_var( NcToken varname, NcType type,       // scalar
                    const NcDim* dim0=0,                // 1-dim
                    const NcDim* dim1=0,                // 2-dim
                    const NcDim* dim2=0,                // 3-dim
                    const NcDim* dim3=0,                // 4-dim
                    const NcDim* dim4=0 );              // 5-dim
    NcVar* add_var( NcToken varname, NcType type,       // n-dim
                          int ndims, const NcDim* dims );

    NcBool add_att( NcToken attname, char );             // scalar attributes
    NcBool add_att( NcToken attname, short );
    NcBool add_att( NcToken attname, int );
    NcBool add_att( NcToken attname, long );
    NcBool add_att( NcToken attname, float );
    NcBool add_att( NcToken attname, double );
    NcBool add_att( NcToken attname, const char*);       // string attribute
    NcBool add_att( NcToken attname, int, const char* ); // vector attributes
    NcBool add_att( NcToken attname, int, const short* );
    NcBool add_att( NcToken attname, int, const int* );
    NcBool add_att( NcToken attname, int, const long* );
    NcBool add_att( NcToken attname, int, const float* );
    NcBool add_att( NcToken attname, int, const double* );

    enum FillMode {
        Fill = NC_FILL,                    // prefill (default)
        NoFill = NC_NOFILL,                // don't prefill
        Bad
      };

    NcBool set_fill( FillMode = Fill );    // set fill-mode
    FillMode get_fill( void );             // get fill-mode

    NcBool sync( void );                   // synchronize to disk
    NcBool close( void );                  // to close earlier than dtr
    NcBool abort( void );                  // back out of bad defines
    
    // Needed by other Nc classes, but users will not need them
    NcBool define_mode( void ); // leaves in define mode, if possible
    NcBool data_mode( void );   // leaves in data mode, if possible
    int id( void ) const;       // id used by C interface

  protected:
    int the_id;
    int in_define_mode;
    NcDim** dimensions;
    NcVar** variables;
    NcVar* globalv;             // "variable" for global attributes
};


/*
 * **********************************************************************
 * To create new netCDF files, opened in definition mode for adding new
 * dimensions, variables, and attributes.
 * **********************************************************************
 */
class NcNewFile : public NcFile
{
  public:

    enum CreateMode {
        NoClobber = NC_NOCLOBBER, // create only if doesn't exist (default)
        Clobber = NC_CLOBBER      // create new file, even if exists
      };

    NcNewFile( const char * path, CreateMode = NoClobber );
    virtual ~NcNewFile( void ) {};
};


/*
 * **********************************************************************
 * For existing netCDF files, opened in data access mode.
 * **********************************************************************
 */
class NcOldFile : public NcFile
{
  public:

    enum OpenMode {
        ReadOnly = NC_NOWRITE,  // open for read only (default)
        Write = NC_WRITE        // open for write
      };

    NcOldFile( const char * path, OpenMode = ReadOnly );
    virtual ~NcOldFile( void ) {};
};


/*
 * **********************************************************************
 * A netCDF dimension, with a name and a size.  These are only created
 * by NcFile member functions, because they cannot exist independently
 * of an open netCDF file.
 * **********************************************************************
 */
class NcDim
{
  public:
    NcToken name( void ) const;
    long size( void ) const;
    NcBool is_valid( void ) const;
    NcBool is_unlimited( void ) const;
    NcBool rename( NcToken newname );
    int id( void ) const;

  private:
    const NcFile *the_file;
    int the_id;
    char *the_name;

    NcDim(const NcFile*, int num);         // existing dimension
    NcDim(NcFile*, NcToken name, long sz); // defines a new dim
    virtual ~NcDim( void );
    
    // to construct dimensions, since constructor is private
  friend NcOldFile::NcOldFile( const char *, NcOldFile::OpenMode );
  friend NcBool NcFile::sync( void );
  friend NcDim* NcFile::add_dim( NcToken, long );
    // to delete dimensions, since destructor is private
  friend NcBool NcFile::close( void );
};


/*
 * **********************************************************************
 * Abstract base class for a netCDF variable or attribute, both of which
 * have a name, a type, and associated values.  These only exist as
 * components of an open netCDF file.
 * **********************************************************************
 */
class NcTypedComponent
{
  public:
    virtual NcToken name( void ) const = 0;
    virtual NcType type( void ) const = 0;
    virtual NcBool is_valid( void ) const = 0;
    virtual long num_vals( void ) const = 0; 
    virtual NcBool rename( NcToken newname ) = 0;
    virtual NcValues* values( void ) const = 0; // block of all values

    // The following member functions provide conversions from the value
    // type to a desired basic type.  If the value is out of range,
    // the default "fill-value" for the appropriate type is returned.

    virtual ncbyte as_ncbyte( int n ) const;    // nth value as an unsgnd char
    virtual char as_char( int n ) const;        // nth value as char
    virtual short as_short( int n ) const;      // nth value as short
    virtual long as_long( int n ) const;        // nth value as long
    virtual float as_float( int n ) const;      // nth value as floating-point
    virtual double as_double( int n ) const;    // nth value as double
    virtual char* as_string( int n ) const;     // nth value as string

  protected:
    NcFile *the_file;
    NcTypedComponent( NcFile* );
    virtual NcValues* get_space( void ) const;  // to hold values
};


/*
 * **********************************************************************
 * netCDF variables.  In addition to a name and a type, these also have
 * a shape, given by a list of dimensions
 * **********************************************************************
 */
class NcVar : public NcTypedComponent
{
  public:
    virtual ~NcVar( void );
    NcToken name( void ) const;
    NcType type( void ) const;
    NcBool is_valid( void ) const;
    int num_dims( void ) const;         // dimensionality of variable
    NcDim* get_dim( int ) const;        // n-th dimension
    const long* edges( void ) const;    // dimension sizes
    int num_atts( void ) const;         // number of attributes
    NcAtt* get_att( NcToken ) const;    // attribute by name
    NcAtt* get_att( int ) const;        // n-th attribute
    long num_vals( void ) const;        // product of dimension sizes
    NcValues* values( void ) const;     // all values

    // Put scalar or 1, ..., 5 dimensional arrays by providing enough
    // arguments.  Arguments are edge lengths, and their number must not
    // exceed variable\'s dimensionality.  Start corner is [0,0,..., 0] by
    // default, but may be reset using the set_cur() member.  FALSE is
    // returned if type of values does not match type for variable.
    NcBool put( const char* vals,
                long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 );
    NcBool put( const short* vals,
                long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 );
    NcBool put( const long* vals,
                long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 );
    NcBool put( const int* vals,
                long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 );
    NcBool put( const float* vals,
                long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 );
    NcBool put( const double* vals,
                long c0=0, long c1=0, long c2=0, long c3=0, long c4=0 );

    // Put n-dimensional arrays, starting at [0, 0, ..., 0] by default,
    // may be reset with set_cur().
    NcBool put( const char* vals, const long* counts );
    NcBool put( const short* vals, const long* counts );
    NcBool put( const long* vals, const long* counts );
    NcBool put( const int* vals, const long* counts );
    NcBool put( const float* vals, const long* counts );
    NcBool put( const double* vals, const long* counts );

    // Get scalar or 1, ..., 5 dimensional arrays by providing enough
    // arguments.  Arguments are edge lengths, and their number must not
    // exceed variable\'s dimensionality.  Start corner is [0,0,..., 0] by
    // default, but may be reset using the set_cur() member.
    NcBool get( char* vals, long c0=0, long c1=0,
                long c2=0, long c3=0, long c4=0 ) const;
    NcBool get( short* vals, long c0=0, long c1=0,
                long c2=0, long c3=0, long c4=0 ) const;
    NcBool get( long* vals, long c0=0, long c1=0,
                long c2=0, long c3=0, long c4=0 ) const;
    NcBool get( int* vals, long c0=0, long c1=0,
                long c2=0, long c3=0, long c4=0 ) const;
    NcBool get( float* vals, long c0=0, long c1=0,
                long c2=0, long c3=0, long c4=0 ) const;
    NcBool get( double* vals, long c0=0, long c1=0,
                long c2=0, long c3=0, long c4=0 ) const; 

    // Get n-dimensional arrays, starting at [0, 0, ..., 0] by default,
    // may be reset with set_cur().
    NcBool get( char* vals, const long* counts ) const;
    NcBool get( short* vals, const long* counts ) const;
    NcBool get( long* vals, const long* counts ) const;
    NcBool get( int* vals, const long* counts ) const;
    NcBool get( float* vals, const long* counts ) const;
    NcBool get( double* vals, const long* counts ) const;

    NcBool set_cur(long c0=-1, long c1=-1, long c2=-1,
                         long c3=-1, long c4=-1);
    NcBool set_cur(long* cur);

    // these put file in define mode, so could be expensive
    NcBool add_att( NcToken, char );             // add scalar attributes
    NcBool add_att( NcToken, short );
    NcBool add_att( NcToken, int );
    NcBool add_att( NcToken, long );
    NcBool add_att( NcToken, float );
    NcBool add_att( NcToken, double );
    NcBool add_att( NcToken, const char* );      // string attribute
    NcBool add_att( NcToken, int, const char* ); // vector attributes
    NcBool add_att( NcToken, int, const short* );
    NcBool add_att( NcToken, int, const int* );
    NcBool add_att( NcToken, int, const long* );
    NcBool add_att( NcToken, int, const float* );
    NcBool add_att( NcToken, int, const double* );

    NcBool rename( NcToken newname );

    int id( void ) const;               // rarely needed, C interface id
    
  private:
    int the_id;
    long* the_cur;
    char* the_name;

    // private constructors because only an NcFile creates these
    NcVar( void );
    NcVar(NcFile*, int);

    int attnum( NcToken attname ) const;
    NcToken attname( int attnum ) const;
    void init_cur( void );

    // to make variables, since constructor is private
  friend NcOldFile::NcOldFile( const char *, OpenMode );
  friend NcNewFile::NcNewFile( const char *, CreateMode );
  friend NcBool NcFile::sync( void );
  friend NcVar* NcFile::add_var( NcToken varname, NcType type,
                                 const NcDim*,
                                 const NcDim*,
                                 const NcDim*,
                                 const NcDim*,
                                 const NcDim*);
  friend NcVar* NcFile::add_var( NcToken, NcType, int,
                                 const NcDim* );
};


/*
 * **********************************************************************
 * netCDF attributes.  In addition to a name and a type, these are each
 * associated with a specific variable, or are global to the file.
 * **********************************************************************
 */
class NcAtt : public NcTypedComponent
{
  public:          
    virtual ~NcAtt( void );
    NcToken name( void ) const;
    NcType type( void ) const;
    NcBool is_valid( void ) const;
    long num_vals( void ) const; 
    NcValues* values( void ) const;
    NcBool rename( NcToken newname );
    NcBool remove( void );

  private:
    const NcVar* the_variable;
    char* the_name;
    // protected constructors because only NcVars and NcFiles create
    // attributes
    NcAtt( NcFile*, const NcVar*, NcToken);
    NcAtt( NcFile*, NcToken); // global attribute
    
    // To make attributes, since constructor is private
  friend NcOldFile::NcOldFile( const char *, OpenMode );
  friend NcNewFile::NcNewFile( const char *, CreateMode );
  friend NcAtt* NcVar::get_att( NcToken ) const;
};


/*
 * **********************************************************************
 * To control error handling.  Declaring an NcError object temporarily
 * changes the error-handling behavior until the object is destroyed, at
 * which time the previous error-handling behavior is restored.
 * **********************************************************************
 */
class NcError {
  public:
    enum Behavior {
        silent_nonfatal = 0,
        verbose_nonfatal = NC_VERBOSE,
        silent_fatal = NC_FATAL,
        verbose_fatal = NC_FATAL | NC_VERBOSE      
      };

    // constructor saves previous error state, sets new state
    NcError( Behavior b = verbose_fatal );

    // destructor restores previous error state
    virtual ~NcError( void );

    int get_err( void );                 // returns most recent error

  private:
    int the_old_state;
    int the_old_err;
};

#endif                          /* NETCDF_HH */


syntax highlighted by Code2HTML, v. 0.9.1