
/** @file  psMetadata.h
*
*  @brief Contains metadata struuctures, enumerations and functions prototypes
*
*  This file defines metadata item, metadata type, metadata flags, metadata containers, and function
*  prototypes necessary creating psLib metadata APIs
*
*  @ingroup Metadata
*
*  @author Ross Harman, MHPCC
*
*  @version $Revision: 1.23 $ $Name: not supported by cvs2svn $
*  @date $Date: 2004-10-06 01:06:27 $
*
*  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
*/
#ifndef PS_METADATA_H
#define PS_METADATA_H

#include <stdarg.h>
#include <stdio.h>

#include "psHash.h"
#include "psList.h"

/// @addtogroup Metadata
/// @{

/** Metadata item type.
 *
 * Enumeration for maintaining metadata item types.
 */
typedef enum {
    PS_META_ITEM_SET = 0,              ///< Null. Metadata is in psMetadataItem.items
    PS_META_BOOL,                      ///< Boolean data.
    PS_META_S32,                       ///< Signed 32-bit integer data.
    PS_META_F32,                       ///< Single-precision float data.
    PS_META_F64,                       ///< Double-precision float data.
    PS_META_STR,                       ///< String data (Stored in as void *).
    PS_META_VEC,                       ///< Vector data (Stored in as void *).
    PS_META_IMG,                       ///< Image data (Stored in as void *).
    PS_META_JPEG,                      ///< JPEG data (Stored in as void *).
    PS_META_PNG,                       ///< PNG data (Stored in as void *).
    PS_META_ASTROM,                    ///< Astrometric coefficients (Stored in as void *).
    PS_META_UNKNOWN,                   ///< Other data (Stored in as void *).
    PS_META_NTYPE                      ///< Number of types. Must be last.
} psMetadataType;

/** Metadata item data structure.
 *
 * Struct for maintaining metadata items of varying types. It also contains
 * information about the item name, flags, comments, and other items with the same name.
 */
typedef struct psMetadataItem
{
    const int id;                      ///< Unique ID for metadata item.
    char *restrict name;               ///< Name of metadata item.
    psMetadataType type;               ///< Type of metadata item.
    union {
        bool B;                        ///< boolean data
        psS32 S32;                     ///< Signed 32-bit integer data.
        psF32 F32;                     ///< Single-precision float data.
        psF64 F64;                     ///< Double-precision float data.
        psPTR V;                       ///< Pointer to other type of data.
    } data;                            ///< Union for data types.
    char *comment;                     ///< Optional comment ("", not NULL).
    psList* restrict items;            ///< List of psMetadataItems with same name.
}
psMetadataItem;

/** Metadata data structure.
 *
 *  Struct for holding metadata items. Metadata items are held in two
 *  containers. The first employs a doubly-linked list to preserve the order
 *  of the metadata. The second container employs a hash table which
 *  allows fast lookup when given a metadata keyword.
 */
typedef struct psMetadata
{
    psList* restrict list;             ///< the metadata in linked-list
    psHash* restrict table;            ///< the metadata in a hash table
}
psMetadata;

/** Create a metadata item.
 *
 *  Returns a fill psMetadataItem ready for insertion into the psMetadata
 *  struct. The name argument specifies the name to use for this item, and
 *  may include sprintf formatting codes. The format entry specifies both
 *  the metadata type and optional flags and is created by bit-wise or of the
 *  appropriate type and flag. The comment argument is a fixed string used to
 *  comment the metadata item. The arguments to the name formatting codes and
 *  the metadata itself are passed as arguments following the comment string.
 *  The data must be a pointer for any of the elements stored in data.void.
 *  The argument list must be interpreted appropriately by the va_list
 *  operators in the function specified size and type.
 *
 * @return psMetadataItem* : Pointer metadata item.
 */
psMetadataItem* psMetadataItemAlloc(
    const char *name,                  ///< Name of metadata item.
    psMetadataType type,               ///< Type of metadata item.
    const char *comment,               ///< Comment for metadata item.
    ...                                ///< Arguments for name formatting and metadata item data.
);

/** Create a metadata item with va_list.
 *
 *  Returns a fill psMetadataItem ready for insertion into the psMetadata
 *  struct. The name argument specifies the name to use for this item, and
 *  may include sprintf formatting codes. The format entry specifies both
 *  the metadata type and optional flags and is created by bit-wise or of the
 *  appropriate type and flag. The comment argument is a fixed string used to
 *  comment the metadata item. The arguments to the name formatting codes and
 *  the metadata itself are passed as arguments following the comment string.
 *  The data must be a pointer for any of the elements stored in data.void.
 *  The argument list must be interpreted appropriately by the va_list
 *  operators in the function specified size and type.
 *
 * @return psMetadataItem* : Pointer metadata item.
 */
psMetadataItem* psMetadataItemAllocV(
    const char *name,                  ///< Name of metadata item.
    psMetadataType type,               ///< Type of metadata item.
    const char *comment,               ///< Comment for metadata item.
    va_list list                       ///< Arguments for name formatting and metadata item data.
);

/** Create a metadata collection.
 *
 *  Returns an empty metadata container with fully allocated internal metadata
 *  containers.
 *
 *  @return psMetadata* : Pointer metadata.
 */
psMetadata* psMetadataAlloc(void);

/** Add existing metadata item to metadata collection.
 *
 *  Add a metadata item that has already been created to the metadata
 *  collection.
 *
 *  @return bool: True for success, false for failure.
 */
bool psMetadataAddItem(
    psMetadata* restrict md,           ///< Metadata collection to insert metadat item.
    psMetadataItem* restrict item,     ///< Metadata item to be added.
    int location                       ///< Location to be added.
);

/** Create and add a metadata item to metadata collection.
 *
 * Creates a new metadata item add to the metadata collection.
 *
 * @return bool: True for success, false for failure.
 */
bool psMetadataAdd(
    psMetadata* restrict md,           ///< Metadata collection to insert metadat item.
    int where,                         ///< Location to be added.
    const char *name,                  ///< Name of metadata item.
    psMetadataType type,               ///< Type of metadata item.
    const char *comment,               ///< Comment for metadata item.
    ...                                ///< Arguments for name formatting and metadata item data.
);

/** Remove an item from metadata collection.
 *
 *  Items may be removed from metadata by specifing a key or location. If the
 *  name is null, the where argument is used instead. If name is not null,
 *  where is set to PS_LIST_UNKNOWN. If the item is found, it is removed from
 *  the metadata and true is returned.  If the key is not unique, then all
 *  items corresponding to it are removed.
 *
 * @return bool: True for success, false for failure.
 */
bool psMetadataRemove(
    psMetadata* restrict md,           ///< Metadata collection to insert metadat item.
    int where,                         ///< Location to be removed.
    const char *restrict key           ///< Name of metadata key.
);

/** Find an item in the metadata collection based on key name.
 *
 *  Items may be found in the metadata by providing a key. If the key is
 *  non-unique, the first item is returned. If the item is not found, null is
 *  returned.
 *
 * @return psMetadataItem* : Pointer metadata item.
 */
psMetadataItem* psMetadataLookup(
    psMetadata* restrict md,           ///< Metadata collection to insert metadata item.
    const char *restrict key           ///< Name of metadata key.
);

/** Find an item in the metadata collection based on list index.
 *
 *  Items may be found in the metadata by their entry position in the list
 *  container.
 *
 *  @return psMetadataItem* : Pointer metadata item.
 */
psMetadataItem* psMetadataGet(
    psMetadata* restrict md,           ///< Metadata collection to insert metadat item.
    int where                          ///< Location to be retrieved.
);

/** Set or reset metadata iterator.
 *
 *  Metadata may be iterated by setting or resetting an iterator to a location
 *  in the metadata list.
 *
 * @return void: void.
 */
bool psMetadataSetIterator(
    psMetadata* restrict md,           ///< Metadata collection to iterate.
    int where                          ///< Location of iterator.
);

/** Get next metadata item.
 *
 * Get next metadata item in iterator list.
 *
 * @return psMetadataItem* : Pointer metadata item.
 */
psMetadataItem* psMetadataGetNext(
    psMetadata* restrict md,           ///< Metadata collection to iterate.
    const char *restrict match,        ///< Beginning of key name.
    int which                          ///< Iterator to be used.
);

/** Get previous metadata item.
 *
 * Get previous metadata item in iterator list.
 *
 * @return psMetadataItem* : Pointer metadata item.
 */
psMetadataItem* psMetadataGetPrevious(
    psMetadata* restrict md,           ///< Metadata collection to iterate.
    const char *restrict match,        ///< Beginning of key name.
    int which                          ///< Iterator to be used.
);


/// @}

#endif
