#if !defined(PS_META_DATA_H)
#define PS_META_DATA_H 1

/** \file psMetadata.h
 *  \brief Metadata handling structures and functions
 *  \ingroup AstroGroup
 */

/** Possible types of metadata. */
typedef enum {				///< type of val is:
    PS_META_ITEM_SET = 0,		///< NULL; metadata is in psMetadataType.items
    PS_META_S32,			///< int (.i)
    PS_META_F32,			///< float (.f)
    PS_META_F64,			///< double (.d)
    PS_META_STR,			///< string (.v)
    PS_META_IMG,			///< image (.v)
    PS_META_JPEG,			///< JPEG (.v)
    PS_META_PNG,			///< PNG (.v)
    PS_META_ASTROM,			///< astrometric coefficients (.v)
    PS_META_UNKNOWN,			///< other (.v)
    PS_META_NTYPE			///< Number of types; must be last
} psMetadataType;

/** A struct to define a single item of metadata */
typedef struct {
    const int id;			///< unique ID for this item
    const char *name;			///< Name of item
    psMetadataType type;		///< type of this item
    const union {
	psS32 S32;			///< integer value
	psF32 F32;			///< floating value
	psF64 F64;			///< double value
	void *void;			///< other type
    } data;				///< value of metadata
    char *comment;			///< optional comment ("", not NULL)
    psDlist *items;			///< list of psMetadataItems with the same name
} psMetadataItem;

/** A set of metadata */
typedef struct {
    psDlist *list;			///< list of psMetadataItem
    psHash *table;			///< hash table of the same metadata
} psMetadata;

/** Functions **************************************************************/
/** \addtogroup AstroGroup Astronomy-Specific Utilities
 *  \{
 */

/** Constructor */
psMetadataItem *psMetadataItemAlloc(const char *name, ///< name of new item of metadata (sprintf format)
				    psMetadataType type, ///< type of this piece of metadata
				    const char *comment, ///< comment associated with item
				    ...)	///< arguments for name and data
;

psMetadataItem *psMetadataItemAllocV(const char *name, ///< name of new item of metadata (sprintf format)
				    psMetadataType type, ///< type of this piece of metadata
				    const char *comment, ///< comment associated with item
				    va_list ap)	///< arguments for name and data
;

/** Constructor */
psMetadata *psMetadataAlloc(void)   ///< make a new set of metadata
;

/**** Utilities **********************************************************************/

/// Add item to the end of the metadata
bool *psMetadataAddItem(psMetadata *md, ///< metadata to add to
			int location,	///< Where to add item
			psMetadataItem *item) ///< Metatdata item to add
;

/// Add item to the end of the metadata.  Combines psMetadataItemAlloc and psMetadataAppendItem
bool *psMetadataAdd(psMetadata *md,	///< Metadata to add to
		    int location,	///< Where to add item
		    const char *name,	///< name of new item of metadata (sprintf format)
		    int format,		///< type of this piece of metadata + flags
		    const char *comment, ///< comment associated with item
		    ...)		///< possible arguments for name format
;

/// delete item from the metadata
bool *psMetadataRemove(psMetadata *md,	///< metadata to delete from
		       int location, 	///< Where to remove
		       const char *key	///< Key to delete
    );

/// find the metadata with the specified key
psMetadataItem *psMetadataLookup(const psMetadata *md, ///< metadata to look up
				 const char *key ///< Key to find
    );

/// retrieve the metadata on the basis of entry position
psMetadataItem *psMetadataGet(const psMetadata *md, ///< metadata to look up
			      int location ///< entry position
    );

/// reset the iterator to the start of the list
void psMetadataSetIterator(psMetadata *md, ///< metadata to set iterator for
			   int iterator, ///< Which iterator to set
			   int location	///< Where to set iterator
			   );

/// get the next item in the sequence
psMetadataItem *psMetadataGetNext(psMetadata *md, ///< metadata to get from
				  const char *match, ///< String to match
				  int iterator ///< Which iterator to use
    );

/// get the next item in the sequence
psMetadataItem *psMetadataGetPrevious(psMetadata *md, ///< metadata to get from
				      const char *match, ///< String to match
				      int iterator ///< Which iterator to use
    );

/// print metadata item to the specified stream
void psMetadataItemPrint(FILE *fd,	///< file descriptor to write to
			 const char *format, ///< Format of output
			 const psMetadataItem *md ///< item of metadata to print
    );

/// Read only header from image file.
psMetadata *
psMetadataReadHeader(psMetadata *out,	///< read data to this structure
		     const char *ext,	///< MEF extension name ("PHU" for primary header)
		     int extnum,	///< MEF extension number (-1 for "PHU", 0 : Nextend - 1)
		     const char *file)	///< file to read from
;

/// Read only header from image file descriptor.
psMetadata *
psMetadataFReadHeader(psMetadata *out,	///< read data to this structure
		      const char *ext,	///< MEF extension name ("PHU" for primary header)
		      int extnum,	///< MEF extension number (-1 for "PHU", 0 : Nextend - 1)
		      FILE *f)		///< file descriptor to read from
;

/* \} */ // End of AstroGroup Functions
#endif
