/* Copyright 2009, UCAR/Unidata and OPeNDAP, Inc.
   See the COPYRIGHT dap for more information. */

/*
Draft OC External Interface
Created: 4/4/2009
Last Revised: 4/14/2009
*/

#ifndef OC_H
#define OC_H

#include <stdlib.h>
#include <stdio.h>

/* if defined, use magic numbers for consistency]) */
#define OC_FASTCONSISTENCY

/* OC_MAX_DIMS should be greater or equal to max allowed by dap or netcdf*/
#define OC_MAX_DIMS 1024

/* Specifies the OCtype.*/
/* Primitives = Duplicate of the NODE_Byte..Node_URL union nc_type*/

typedef unsigned long OCtype;

/* Note: use #define rather than enum so we can extend if needed
   more easily */
/* Primitives*/
/* OC_Ubyte, OC_Char, OC_Int64 and OC_UInt64 are defined for future extension*/
#define OC_NAT ((OCtype)0)
#define OC_Char ((OCtype)1)
#define OC_Byte ((OCtype)2)
#define OC_UByte ((OCtype)3)
#define OC_Int16 ((OCtype)4)
#define OC_UInt16 ((OCtype)5)
#define OC_Int32 ((OCtype)6)
#define OC_UInt32 ((OCtype)7)
#define OC_Int64 ((OCtype)8)
#define OC_UInt64 ((OCtype)9)
#define OC_Float32 ((OCtype)10)
#define OC_Float64 ((OCtype)11)
#define OC_String ((OCtype)12)
#define OC_URL ((OCtype)13)

/* Non-primitives*/
#define OC_Dataset	((OCtype)100)
#define OC_Sequence	((OCtype)101)
#define OC_Grid		((OCtype)102)
#define OC_Structure	((OCtype)103)
#define OC_Dimension	((OCtype)104)
#define OC_Attribute	((OCtype)105)
#define OC_Attributeset	((OCtype)106)
#define OC_Primitive	((OCtype)107)
#define OC_Group	((OCtype)108)
#define OC_Type		((OCtype)109)

/* Define a set of error
  positive are system errors
  (needs work)
*/

typedef int OCerror;
#define OC_NOERR	(0)
#define OC_EBADID	(-1)
#define OC_ECHAR	(-2)
#define OC_EDIMSIZE	(-3)
#define OC_EEDGE	(-4)
#define OC_EINVAL	(-5)
#define OC_EINVALCOORDS	(-6)
#define OC_ENOMEM	(-7)
#define OC_ENOTVAR	(-8)
#define OC_EPERM	(-9)
#define OC_ESTRIDE	(-10)
#define OC_EDAP		(-11)
#define OC_EXDR		(-12)
#define OC_ECURL	(-13)
#define OC_EBADURL	(-14)
#define OC_EBADVAR	(-15)
#define OC_EOPEN	(-16)
#define OC_EIO   	(-17)
#define OC_ENODATA   	(-18)
#define OC_EDAPSVC   	(-19)
#define OC_ENAMEINUSE  	(-20)
#define OC_EDAS		(-21)
#define OC_EDDS		(-22)
#define OC_EDATADDS	(-23)
#define OC_ERCFILE	(-24)
#define OC_ENOFILE	(-25)

/* Define the classes of DAP DXD objects */
typedef int OCdxd;
#define OCDDS     0
#define OCDAS     1
#define OCDATADDS 2
#define OCDATA OCDATADDS

/* Define flags */
typedef int OCflags;
#define OCONDISK 1

typedef enum OCmode {
OCNULLMODE = 0,
OCFIELDMODE = 1,
OCSEQUENCEMODE = 2,
OCARRAYMODE = 3,
OCPRIMITIVEMODE = 4,
OCEMPTYMODE = 0x8000000 /* internal use only */
} OCmode;


/* Define an unsigned alternative to off(64)_t*/
typedef unsigned long long ocoffset_t;

/* Define a wrapper for dimension sizes */
typedef size_t ocindex_t;

/* Define the effective API */

#ifndef OCINTERNAL_H

/* The OCobject type references a component of a DAS or DDS
   (e.g. Sequence, Grid, Dataset, etc). These objects
   are nested, so most objects reference a container object
   and subnode objects.
*/


#ifdef OC_FASTCONSISTENCY
/* Use unsigned int * so we can dereference to get magic number */
typedef unsigned int* OCobject;
#define OCNULL NULL
#else
typedef unsigned long OCobject;
#define OCNULL ((OCobject)0)
#endif

/* These are the two critical types*/
/* Think of OClink as analogous to the C stdio FILE structure;
   it "holds" all the other state info about
   a connection to the server, the url request, and the DAS/DDS/DATADDSinfo.
*/
/* Renamed from OCconnection because of confusion about term "connection"
   3/24/2010 by dmh
*/
typedef OCobject OClink;

/* Keep old name for back compatibility */
typedef OClink OCconnection; /*Deprecated*/

/* Tag kind of log entry*/
#define OCLOGNOTE 0
#define OCLOGWARN 1
#define OCLOGERR 2
#define OCLOGDBG 3

/**************************************************/

#ifdef __cplusplus
extern "C" {
#endif

extern int oc_dumpnode(OClink conn, OCobject root0);

/**************************************************/
/* Link management */

extern OCerror oc_open(const char* url, OClink*);
extern OCerror oc_close(OClink);

/**************************************************/
/* Root management */
/* Fetch and parse a given class of DXD the server specified
   at open time, and using a specified set of constraints
   and flags.
   Return the root node of the parsed tree of objects.
*/
extern OCerror oc_fetchf(OClink,
			const char* constraints,
			OCdxd,
			OCflags,
			OCobject* rootp);


/*
  Equivalent to oc_fetchf with zero flag parameter
*/
extern OCerror oc_fetch(OClink,
			const char* constraints,
			OCdxd,
			OCobject* rootp);

/* Release/reclaim the tree of objects associated with a given root */
extern OCerror oc_root_free(OClink, OCobject root);

/* Return the # of  OCobjects associated with a tree with specified root */
extern unsigned int oc_inq_nobjects(OClink, OCobject root);

/* Return all the OCobjects associated with a tree with specified root */
extern OCobject* oc_inq_objects(OClink, OCobject root);

/* Return the text of the DDS or DAS as received from the server */
extern const char* oc_inq_text(OClink, OCobject root);

/**************************************************/
/* Object Management */

/* Any of the pointers may be NULL in the following procedure call;
  If the object is of type Dataset, then return # of global attributes
  If the object is of type Attribute, then return the # of values in nattrp.
  The caller must free the resulting name string.
*/
extern OCerror oc_inq_object(OClink, OCobject,
		  char** namep,
		  OCtype* typep,
		  OCtype* primitivetypep, /* if objecttype == OC_Primitive */
		  OCobject* parentp,
		  unsigned int* rankp,
		  unsigned int* nsubnodesp,
		  unsigned int* nattrp);

/* Also define some more individual accessors */

extern OCerror oc_inq_name(OClink,OCobject,char**);
extern OCerror oc_inq_class(OClink,OCobject,OCtype*);
extern OCerror oc_inq_type(OClink,OCobject,OCtype*); /*alias for oc_inq_class*/
extern OCerror oc_inq_primtype(OClink,OCobject,OCtype*);
extern OCerror oc_inq_nsubnodes(OClink,OCobject,unsigned int*);
extern OCerror oc_inq_rank(OClink,OCobject,unsigned int*);
extern OCerror oc_inq_nattr(OClink,OCobject,unsigned int*);
extern OCerror oc_inq_root(OClink,OCobject,OCobject*);
extern OCerror oc_inq_container(OClink,OCobject,OCobject*);

/* Return the subnode objects, if any, associated with a given object.
Caller must free the returned subnodes memory.
*/
extern OCerror oc_inq_subnodes(OClink,OCobject,OCobject** subnodes);

/* Return the i'th subnode object, if any, associated with a given object */
/* If there is none such, then return OC_EINVAL */
extern OCerror oc_inq_ith(OClink,OCobject, unsigned int, OCobject*);

/* Return the dimension objects, if any, associated with a given object */
/* Caller must free returned vector for dimids */
/* If there are no dimensions (i.e. rank == 0), then return NULL */
extern OCerror oc_inq_dimset(OClink,OCobject, OCobject** dimids);

/* Return the i'th dim object, if any, associated with a given object */
/* If there is no such dim, then return OC_EINVAL */
extern OCerror oc_inq_ithdim(OClink,OCobject, unsigned int, OCobject*);

/* Return the size and name associated with a given dimension object
   as defined in the DDS
*/
extern OCerror oc_inq_dim(OClink,OCobject,ocindex_t*,char**);

/* Attribute Management */

/* Added: 11/2/2009 DMH:
   Provide access to DDS node attributes
   in the form of the original underlying
   DAS string.
   One specifies the DDS root to get the global attributes.
   Caller must free returned strings.
*/

extern OCerror oc_inq_attrstrings(OClink,OCobject, unsigned int i,
			   char** name, OCtype* octype,
			   unsigned int* nvalues,char*** stringvalues);

/* Obtain the attributes associated with a given DDS OCobject.
   One specifies the DDS root to get the global attributes
   This code takes the DAS strings and does a default
   conversion to binary values.
*/
extern OCerror oc_inq_attr(OClink,OCobject, unsigned int i,
			   char** name,OCtype* octype,
			   unsigned int* nvalues,void** values);

/* Convenience function to simplify reclaiming the allocated attribute
   value memory
*/
extern void oc_attr_reclaim(OCtype, unsigned int nvalues, void* values);

/* Access ith value string of a DAS object.
   OCtype of the object is assumed to be OC_Attribute.
   Note that this is  different than the above inq_attr
   and inq_attrstrings, which work on DDS
   objects. Note also that the return value is always a string.
   Caller must free returned string.
*/

extern OCerror oc_inq_dasattr_nvalues(OClink, OCobject,
			unsigned int* nvaluesp);

extern OCerror oc_inq_dasattr(OClink,OCobject, unsigned int,
			      OCtype* primtypep, char** valuep);

/**************************************************/
/* Data management */

/*
These procedures allow for the location and extraction
of data from the data packet part of a DATADDS.
See ocuserman.html for detailed description.
*/

typedef OCobject OCdata;

/* Obtain the OCdata object that references the
   whole data from a DATADDS fetch request specified
   by the root object. This does not access the server.
*/
extern OCerror oc_data_root(OClink, OCobject root, OCdata);

/* Create an empty OCdata object */
extern OCdata oc_data_new(OClink);

/* Reclaim a no longer needed OCdata object */
extern OCerror oc_data_free(OClink, OCdata);

/* Given an OCdata object, set the nested subnode OCdata object
   to refer to the data associated with the i'th element of
   the parent data object. NOTE: if the i'th element is not
   present then this function will return OC_ENODATA.
   See the user's manual for details on mapping multi-
   dimensional arrays to single indices.
*/
extern OCerror oc_data_ith(OClink,
				OCdata parentdata,
				ocindex_t index,
				OCdata subdata);

/* Return the actual data values associated with the specified OCdata.
   The OCdata is assumed to be referencing either a scalar
   primitive value or a (1d) array of primitive values.
   If scalar, then index must be 0 and count must be 1.
*/
extern OCerror oc_data_get(OClink,OCdata,
                         void* memory, size_t memsize,
                         ocindex_t index, ocindex_t count);

/* Return the OCdata's current index */
extern OCerror oc_data_index(OClink,OCdata, ocindex_t*);

/* Return the mode associated the specified OCdata object */
extern OCerror oc_data_mode(OClink,OCdata, OCmode*);

/* Return the OCobject associated the specified OCdata object */
extern OCerror oc_data_object(OClink,OCdata, OCobject*);

/* Compute the the count associated with the specified OCdata
   instance. Note: this is potentially computationally costly
   when computing # records.
*/
extern OCerror oc_data_count(OClink, OCdata, ocindex_t*);

/**************************************************/
/* Misc. OCtype-related functions */

/* Return size of the given type (Primitive only) */
extern size_t oc_typesize(OCtype);

/* Return a canonical printable string describing a given type:
   e.g. Byte, Int16, etc.
*/
extern const char* oc_typetostring(OCtype);

/* Given a value of a primitive OC type, provide a canonical
   string representing that value
*/
extern OCerror oc_typeprint(OCtype, char* buf, size_t bufsize, void* value);

/**************************************************/
/* Logging */

extern void oc_loginit(void);
extern void oc_setlogging(int onoff); /* 1=>start logging 0=>stop */
extern void oc_logopen(const char* logfilename);
extern void oc_logclose(void);

extern void oc_logtext(int tag, const char* text);

extern void oc_log(int tag, const char* fmt, ...);

/**************************************************/
/* Miscellaneous */

/* Convert an OCerror to a human readable string */
extern const char* oc_errstring(int err);

/* Get client parameters from the URL
   DO NOT free the result
*/
extern const char* oc_clientparam_get(OClink, const char* param);

extern OCerror oc_clientparam_delete(OClink, const char* param);
extern OCerror oc_clientparam_insert(OClink, const char* param, const char* value);
extern OCerror oc_clientparam_replace(OClink, const char* param, const char* value);

/**************************************************/
/* Merging operations */

/* Merge a specified DAS into a specified DDS or DATADDS */
extern OCerror oc_attach_das(OClink, OCobject dasroot, OCobject ddsroot);

/**************************************************/
/* Debugging */
extern OCerror oc_dd(OClink,OCobject,int level);
extern OCerror oc_ddnode(OClink,OCobject);

/* When a server error is detected, then it is possible
   to get the server error info using this procedure */
extern OCerror oc_svcerrordata(OClink link, char** codep,
                               char** msgp, long* httpp);



/**************************************************/
/* Experimental */

/* New 10/31/2009: return raw information about a datadds
*/

extern OCerror oc_raw_xdrsize(OClink, OCobject, size_t*);

/* Resend a url as a head request to check the Last-Modified time */
extern OCerror oc_update_lastmodified_data(OClink);

/* Get last known modification time; -1 => data unknown */
extern long oc_get_lastmodified_data(OClink);

extern OCerror oc_ping(const char* url);

/**************************************************/

#endif /*OCINTERNAL_H*/

#ifdef __cplusplus
}
#endif

#endif /*OC_H*/
