/** \file
 *
 *  Contains the NetCdfWriter class declaration.
 *
 *  Copyright (c) 2007,2008,2009 MBARI
 *  MBARI Proprietary Information.  All Rights Reserved
 */

#ifndef NETCDFWRITER_H_
#define NETCDFWRITER_H_

#include "utils/NetCdf.h"

#include "io/FileOutStream.h"
#include "utils/Timestamp.h"

class DataValue;
class ElementURI;
class FileOutStream;
class Unit;

class NetCdfWriter;
typedef NetCdfWriter NetCdfGroup;

/**
 *  A very compact, very simple netCDF writer with a minimal feature set.
 *  It is intended for writing a set of record variables to a file, sequentially
 *  as time increases. (No provision for large, multidimensional arrays, etc.)
 *
 *  \ingroup utils
 */
class NetCdfWriter : public NetCdf
{
public:

    typedef FastMap<const Str, NetCdfGroup*> NetCdfGroups;


    /// Returns an newNetCdfWriter of a NetCdfWriter for a file
    static NetCdfWriter* NewNetCdfWriter( const char* fileName, bool version4, const char* trajectoryName = "LRAUVTrajectory" );

    /// Destructor
    virtual ~NetCdfWriter();

    /// Indicates intialization success
    bool isOk() const
    {
        return ok_;
    }

    const NetCdfAtt* addGlobalAtt( const Str& name, const Str& value );

    const NetCdfAtt* addGlobalAtt( const Str& name, const unsigned char value );

    const NetCdfAtt* addGlobalAtt( const Str& name, const short value );

    const NetCdfAtt* addGlobalAtt( const Str& name, const int value );

    const NetCdfAtt* addGlobalAtt( const Str& name, const float value );

    const NetCdfAtt* addGlobalAtt( const Str& name, const double value );

    const NetCdfDim* addDim( const Str& name, const unsigned int dimSize );

    NetCdfVar* addVar( const Str& name, const NetCdfType netCdfType, const NetCdfDim* dimTime = NULL, const NetCdfDim* dimM = NULL, const NetCdfDim* dimN = NULL, const NetCdfDim* dimO = NULL );

    NetCdfVar* addStaticVar( const Str& name, const NetCdfType netCdfType, const NetCdfDim* dim = NULL );

    const NetCdfAtt* addVarAtt( NetCdfVar* netCdfVar, const Str& name, const Str& value );

    const NetCdfAtt* addVarAtt( NetCdfVar* netCdfVar, const Str& name, unsigned char value );

    const NetCdfAtt* addVarAtt( NetCdfVar* netCdfVar, const Str& name, const int value );

    const NetCdfAtt* addVarAtt( NetCdfVar* netCdfVar, const Str& name, const float value );

    const NetCdfAtt* addVarAtt( NetCdfVar* netCdfVar, const Str& name, const double value );

    void setAttValue( const NetCdfAtt* netCdfAtt, const Str& value );

    void setAttValue( const NetCdfAtt* netCdfAtt, const unsigned char value );

    void setAttValue( const NetCdfAtt* netCdfAtt, const int value );

    void setAttValue( const NetCdfAtt* netCdfAtt, const float value );

    void setAttValue( const NetCdfAtt* netCdfAtt, const double value );

    NetCdfGroup* addGroup( const Str& name );

    NetCdfGroup* findGroup( const Str& name );

    /// Opens a NetCdfWriter for a file
    /// Returns true if no error.
    bool initialize( );

    /// Write all the variables
    bool writeRecord( Timestamp& timestamp );

    /// Just write the specified variable
    bool writeVarRecord( NetCdfVar* netCdfVar, const ElementURI* uri = NULL );

    /// Set the number of records in the file header
    /// Returns true if no error.
    bool finalize( );

protected:

    /// Protected Constructor
    NetCdfWriter( const char* filename, bool version4, const char* trajectoryName );

    /// Protected group Constructor
    NetCdfWriter( const char* name, int parentNcId );

    const NetCdfAtt* addAtt( NetCdfAtts& atts, int varId, const Str& name, const Str& value );

    const NetCdfAtt* addAtt( NetCdfAtts& atts, int varId, const Str& name, const unsigned char value );

    const NetCdfAtt* addAtt( NetCdfAtts& atts, int varId, const Str& name, const short value );

    const NetCdfAtt* addAtt( NetCdfAtts& atts, int varId, const Str& name, const int value );

    const NetCdfAtt* addAtt( NetCdfAtts& atts, int varId, const Str& name, const float value );

    const NetCdfAtt* addAtt( NetCdfAtts& atts, int varId, const Str& name, const double value );

    /// Used by writeVarRecord to put a value in the variable
    int putValue( NetCdfVar* netCdfVar, size_t index[], double value );

    bool ok_;
    Str filename_;
    unsigned int numRecs_;
    bool initialized_;
    bool finalized_;
    const char* trajectoryName_;
    bool version4_;
    const NetCdfDim* trajectoryLenDim_;
    NetCdfVar* trajectoryVar_;
    const NetCdfDim* timeDim_;
    NetCdfVar* timeVar_;
    unsigned long long currentLocation_;
    NetCdfGroups groups_;                  /* group map */

private:
    // Note that the copy constructor below is private and not given a body.
    // Any attempt to call it will return a compiler error.
    NetCdfWriter( const NetCdfWriter& old ); // disallow copy constructor

};

#endif /*NETCDFWRITER_H_*/
