\documentclass[panstarrs]{panstarrs}

\title{The \PS{} Metadata API}
\author{Robert Lupton, Gene Magnier}
\group{}
\organization{}
\docnumber{PSDC-???}

\fancyhead{}
\fancyhead[L]{\PS{} Document}
\fancyhead[R]{PSDC-???}
\fancyhead[C]{Revision 0.1 -- Draft}
\fancyfoot[L]{psMetaData}
\fancyfoot[R]{\today}

\begin{document}

\pagenumbering{roman} \thispagestyle{empty} \maketitle

\pagebreak \pagestyle{fancy}
{ \Large \bf Revision History}
\begin{center}
\begin{tabular}{|p{1in}|p{1in}|p{4.5in}|}
\hline
{\bf Revision Number} & {\bf Release Date} & {\bf Description} \\
\hline
%0.1 & 2003/12/08 & First draft \\
\hline
\end{tabular}
\end{center}

{ \Large \bf Referenced Documents}
\begin{center}
\begin{tabular}{|p{1in}|p{2.75in}|p{2.75in}|}
\hline
{\bf PanSTARRS ID} & {\bf Title} & {\bf Author} \\
\hline
%%% References here.
\hline
\end{tabular}
\end{center}

\pagebreak
\tableofcontents

% \pagebreak
% \listoffigures

\pagebreak \pagenumbering{arabic}

\section{Introduction}

This document addresses the question of how \PS{}
metadata should be represented in memory. We do not
(yet) address how it should be represented on disk.

\section{Metadata Representation}

We propose that an item of metadata be represented as a C structure with at least the following
fields:
\begin{verbatim}
/*
 * A struct to define a single item of metadata
 */
typedef struct {
    const int id;                       // unique ID for this item
    
    char *name;                         // Name of item
    psMetaDataType type;                // type of this item
    const union {
        float f;                        // floating value
        int i;                          // integer value
        void *v;                        // other type
    } val;                              // value of metadata
    char *comment;                      // optional comment ("", not NULL)
} psMetaDataItem;
\end{verbatim}

The \code{id} is a unique identifier for this item of metadata; experience
shows that such tags are useful.

The \code{psMetaDataType type} entry specifies the type of the data
being represented; the possibilities are listed in section \ref{metadataTypes}.

\subsection{Possible Types of Metadata}
\label{metadataTypes}

The possible types of metadata are identified by the enumerated type
\code{psMetaDataType} (see also table \ref{tabMetaDataTypes}); the initial defined values are:
\begin{verbatim}
/*
 * Possible types of metadata.  
 */
typedef enum {                          // type of val is:
    psMetaFloat,                        // float (.f)
    psMetaInt,                          // int (.i)
    psMetaStr,                          // string (.v)
    psMetaImg,                          // image (.v)
    psMetaJPEG,                         // JPEG (.v)
    psMetaPNG,                          // PNG (.v)
    psMetaAstrom,                       // astrometric coefficients (.v)
    psMetaUnknown,                      // other (.v)
    psMetaNType                         // Number of types; must be last
} psMetaDataType;
\end{verbatim}

\begin{table}
\begin{tabular}{llll}
\textbf{Value} & \textbf{Type} & \textbf{member of union} & \textbf{Comments}\\
\hline
psMetaFloat & float & f & value, not pointer, is stored \\
psMetaInt & int & i &  value, not pointer, is stored \\
psMetaStr & string & v &  value, not pointer to original, is stored \\
psMetaImg & psImage & v &  \\
psMetaJPEG & JPEG & v &  \\
psMetaPNG & PNG & v &  \\
psMetaAstrom & psAstrom & v &  \\
psMetaUnknown & other & v &  \\
psMetaNType & (none) & & The number of types defined
\end{tabular}
\begin{caption}{Supported Metadata Types}
\label{tabMetaDataTypes}
  Possible types of metadata
\end{caption}
\end{table}

\section{Collections of Metadata}

\begin{verbatim}
typedef struct {
    psDlist *list;			// list of psMetaDataItem
    psHash *table;			// hash table of the same metadata
} psMetaDataSet;
\end{verbatim}

The type \code{psMetaDataSet} is a container class for metadata. Note that there are
in fact \emph{two} representations of the metadata (each \code{psMetaDataItem} appears
on both).

We are using the standard \PS{} doubly-linked list types \code{psDlist} and  \code{psHash}
(see \href{file:utils#psDlist}{utils.pdf:psDlist} and \href{file:utils#psHash}{utils.pdf:psHash} for details).
For example:
\begin{verbatim}
    for (int i = 0; i < 10; i += 5) {
        float sqrti = sqrt(i);
        psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_INT, &i, NULL, "const.%d", i));
        psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_FLOAT, &sqrti, "square root", "const.sqrt%d", i));
    }
    psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_STR, "Bonjour", "French", "lang.hello"));
    /*
     * Remove a key
     */
    psMetaDataItemFree(psMetaDataRemove(ms, "lang.hello"));
    /*
     * Print all metadata
     */
    fprintf(stdout, "------\n");
    psMetaDataSetIterator(ms);
    while ((meta = psMetaDataGetNext(ms, NULL)) != NULL) {
        psMetaDataItemPrint(stdout, meta, "");
    }
    /*
     * Look up a key by name
     */
    fprintf(stdout, "------\n");
    fprintf(stdout, "Looking up by name:\n");
    meta = psMetaDataLookup(ms, "const.5");
    if (meta != NULL) {
        psMetaDataItemPrint(stdout, meta, "");
    }
\end{verbatim}

\section{Naming convention for MetaData}

The \code{psMetaDataItem} struct includes a name.  This name should be of
the form \code{name1.name2.name3$\cdots$}, e.g.\hfil\break
\null\qquad\qquad\code{IPP.phase1.ota12.biassec}.

We shall set in place a system for assigning the top-level `domains'
to responsible individuals, and for gathering a complete list of
all metadata names in use throughout the project.

\subsection{Support for Multiple Values for a Given Name}

\begin{verbatim}
    psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_STR | PS_META_NON_UNIQUE,
                                           "Bonjour", "French", "lang.hello"));
    psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_STR | PS_META_NON_UNIQUE,
                                           "Aloha", "Hawaiian", "lang.hello"));
    psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_STR | PS_META_NON_UNIQUE,
                                           "Good Morning", "English", "lang.hello"));
    /*
     * Print all metadata starting "lang"
     */
    psMetaDataSetIterator(ms);
    while ((meta = psMetaDataGetNext(ms, "lang")) != NULL) {
        psMetaDataItemPrint(stdout, meta, "");
    }
\end{verbatim}

It is an unfortunate fact that certain metadata keywords (such as \code{COMMENT} in a FITS header)
may be repeated with different values.  The \code{psMetaDataAppend} routine is required
to check that all metadata names are unique unless the type is qualified as \code{PS_META_NON_UNIQUE};
in this case a unique integer will be added to each name that you specify. In this case,
you may either delete individual element separately or as a complete set:
\begin{verbatim}
psMetaDataItemFree(psMetaDataRemove(ms, "lang.hello.0"));
psMetaDataItemFree(psMetaDataRemove(ms, "lang.hello"));
\end{verbatim}

\appendix
\section{MetaData APIs}

\begin{verbatim}
psMetaDataItem *psMetaDataItemAlloc(
    psMetaDataType type,		// type of this piece of metadata
    const void *val,			// value of new item
    					// N.b. a pointer even if the item
    					// is of type e.g. int
    const char *comment,		// comment associated with item
    const char *name,			// name of new item of metadata (may be an sprintf format)
    ...);				// possible arguments for name format

void psMetaDataItemFree(psMetaDataItem *ms); // piece of metadata to destroy

psMetaDataSet *psMetaDataSetAlloc(void);	  // make a new set of metadata
void psMetaDataSetDel(psMetaDataSet *ms); // destroy a set of metadata

/*****************************************************************************/
/*
 * Utilities
 */
psMetaDataItem *psMetaDataAppend(psMetaDataSet *restrict ms, psMetaDataItem *restrict item);
psMetaDataItem *psMetaDataRemove(psMetaDataSet *restrict ms, const char *restrict key);

void psMetaDataSetIterator(psMetaDataSet *ms);
psMetaDataItem *psMetaDataGetNext(psMetaDataSet *ms);
psMetaDataItem *psMetaDataLookup(const psMetaDataSet *ms, const char *key);

void psMetaDataItemPrint(FILE *fd,		// file descriptor to write to
			 const psMetaDataItem *ms); // item of metadata to print
\end{verbatim}

\bibliographystyle{plain}
\bibliography{panstarrs}

\end{document}
