/* @file pmConcepts.h
 * @brief Top-level functions for defining, registering, reading and writing concepts
 *
 * @author Paul Price, IfA
 *
 * @version $Revision: 1.14 $ $Name: not supported by cvs2svn $
 * @date $Date: 2007-03-30 21:12:56 $
 * Copyright 2005-2006 Institute for Astronomy, University of Hawaii
 */

#ifndef PM_CONCEPTS_H
#define PM_CONCEPTS_H

/// @addtogroup Concepts Data Abstraction Concepts
/// @{

/// Source for concepts when reading and writing.
///
/// Since some sources become available at different times from others, we need to provide some specificity to
/// reading and writing concepts (or we're forced to wait until everything's available, which we don't want to
/// do).  Concepts may be read from or written to multiple sources at once by OR-ing them.
typedef enum {
    PM_CONCEPT_SOURCE_NONE     = 0x00,  ///< No concepts
    PM_CONCEPT_SOURCE_CELLS    = 0x01,  ///< Concept comes from the camera information
    PM_CONCEPT_SOURCE_DEFAULTS = 0x02,  ///< Concept comes from defaults
    PM_CONCEPT_SOURCE_PHU      = 0x04,  ///< Concept comes from PHU
    PM_CONCEPT_SOURCE_HEADER   = 0x08,  ///< Concept comes from FITS header
    PM_CONCEPT_SOURCE_DATABASE = 0x10,  ///< Concept comes from database
    PM_CONCEPT_SOURCE_ALL      = 0xff   ///< All concepts
} pmConceptSource;

/// Function to call to parse a concept once it has been read
typedef psMetadataItem* (*pmConceptParseFunc)(const psMetadataItem *concept, ///< Concept to parse
        const psMetadataItem *pattern, ///< Pattern for parsing
                                              pmConceptSource source, ///< Source of concept
        const psMetadata *cameraFormat, ///< Camera format definition
        const pmFPA *fpa, ///< FPA for concept, or NULL
        const pmChip *chip, ///< Chip for concept, or NULL
        const pmCell *cell ///< Cell for concept, or NULL
                                             );

/// Function to call to format a concept for writing
typedef psMetadataItem* (*pmConceptFormatFunc)(const psMetadataItem *concept, ///< Concept to format
                                               pmConceptSource source, ///< Source of concept
        const psMetadata *cameraFormat, ///< Camera format definition
        const pmFPA *fpa, ///< FPA for concept, or NULL
        const pmChip *chip, ///< Chip for concept, or NULL
        const pmCell *cell ///< Cell for concept, or NULL
                                              );

/// A "concept" specification
///
/// Defines the name, default comment, blank value, and functions to parse (after reading) and format (before
/// writing) the concept.
typedef struct
{
    psMetadataItem *blank;              ///< Blank value of concept; also contains the name and comment
    pmConceptParseFunc parse;           ///< Function to call to read the concept
    pmConceptFormatFunc format;         ///< Function to call to write the concept
    bool required;                      ///< Is concept required (throw an error on problems)?
}
pmConceptSpec;

/// Allocator for pmConceptSpec
pmConceptSpec *pmConceptSpecAlloc(psMetadataItem *blank, ///< Blank value; contains the name
                                  pmConceptParseFunc parse, ///< Function to call to parse the concept
                                  pmConceptFormatFunc format, ///< Function to call to format the concept
                                  bool required ///< Is concept required?
                                 );

/// Get whether a particular concept is required
bool pmConceptGetRequired(const char *name, ///< Name of concept
                          pmFPALevel level ///< Level at which concept resides
    );

/// Set whether a particular concept is required
bool pmConceptSetRequired(const char *name, ///< Name of concept
                          pmFPALevel level, ///< Level at which concept resides
                          bool required ///< Whether concept is required or not
    );

/// Register a new concept for parsing and formatting
///
/// Defines a new concept, based on the blank value (with name and default comment), and functions to parse
/// and format the concept.  The new concept is registered at the specified level (FPA, chip or cell).  If the
/// parse function is NULL, then a default parse function is used, which performs minimal parsing.  Similarly
/// for the format function.
bool pmConceptRegister(psMetadataItem *blank, ///< Blank value; contains the name and default comment
                       pmConceptParseFunc parse, ///< Function to call to parse the concept, or NULL
                       pmConceptFormatFunc format, ///< Function to call to format the concept, or NULL
                       bool required,   ///< Is concept required?
                       pmFPALevel level ///< Level at which to store concept in the FPA hierarchy
                      );

/// Get a list of defined concepts for a particular level.
psList *pmConceptsList(pmFPALevel level);

/// Read the concepts for the given set of fpa, chip, cell
///
/// Attempts to read as many concepts as possible from the specified source for the specified FPA, chip and
/// cell.  That is, it will read chip- and cell-level concepts in addition to fpa-level concepts, if the chip
/// and cell are provided.
bool pmConceptsRead(pmFPA *fpa,         ///< FPA for which to read concepts
                    pmChip *chip,       ///< Chip for which to read concepts, or NULL
                    pmCell *cell,       ///< Cell for which to read concepts, or NULL
                    pmConceptSource source, ///< The source of the concepts to read
                    psDB *db            ///< Database handle
                   );

/// Set the concepts within the FPA to the blank value
bool pmConceptsBlankFPA(pmFPA *fpa      ///< FPA for which to set blank concepts
                       );

/// Read concepts for an FPA; optionally, read concepts at all lower levels.
///
/// Once concepts should be available for reading at the FPA-level, this function attempts to read the
/// concepts from the specified source.  It also allows concepts to be read at lower levels by iterating over
/// the components.
bool pmConceptsReadFPA(pmFPA *fpa,      ///< FPA for which to read concepts
                       pmConceptSource source, ///< Source for concepts
                       bool propagateDown, ///< Propagate to lower levels?
                       psDB *db         ///< Database handle
                      );

/// Write concepts for an FPA; optionally, write concepts at all lower levels.
///
/// This function writes all concepts for the FPA to the specified "source".  It also allows concepts to be
/// written for all lower levels by iterating over the components.
bool pmConceptsWriteFPA(const pmFPA *fpa,     ///< FPA for which to write concepts
                        pmConceptSource source, ///< Source for concepts
                        bool propagateDown, ///< Propagate to lower levels?
                        psDB *db        ///< Database handle
                       );

/// Set the concepts within the chip to the blank value
bool pmConceptsBlankChip(pmChip *chip   ///< FPA for which to set blank concepts
                        );

/// Read concepts for a chip; optionally, read concepts at the FPA and cell levels.
///
/// Once concepts should be available for reading at the FPA-level, this function attempts to read the
/// concepts from the specified source.  It also allows concepts to be read at the fpa level (through the
/// parent), and the cell level by iterating over the components.
bool pmConceptsReadChip(pmChip *chip,   ///< Chip for which to read concepts
                        pmConceptSource source, ///< Source for concepts
                        bool propagateUp, ///< Propagate to higher levels?
                        bool propagateDown, ///< Propagate to lower levels?
                        psDB *db        ///< Database handle
                       );

/// Write concepts for a chip; optionally, write concepts at the FPA and cell levels.
///
/// This function writes all concepts for the chip to the specified "source".  It also allows concepts to be
/// written for the FPA, and the cell level by iterating over the components.
bool pmConceptsWriteChip(const pmChip *chip,  ///< Chip for which to write concepts
                         pmConceptSource source, ///< Source for concepts
                         bool propagateUp,///< Propagate to higher levels?
                         bool propagateDown, ///< Propagate to lower levels?
                         psDB *db       ///< Database handle
                        );

/// Set the concepts within the cell to the blank value
bool pmConceptsBlankCell(pmCell *cell   ///< Cell for which to set blank concepts
                        );

/// Read concepts for a cell; optionally, read concepts for the parents.
///
/// Once concepts should be available for reading at the FPA-level, this function attempts to read the
/// concepts from the specified source.  It also allows concepts to be read at upper levels through the
/// parents (note, it would not read concepts for all chips, but only the parent of this cell).
bool pmConceptsReadCell(pmCell *cell,   ///< Cell for which to read concepts
                        pmConceptSource source, ///< Source for concepts
                        bool propagateUp, ///< Propagate to higher levels?
                        psDB *db        ///< Database handle
                       );

/// Write concepts for a cell; optionally, write concepts for the parents.
///
/// This function writes all concepts for the chip to the specified "source".  It also allows concepts to be
/// written for the upper levels through the parents (note, it would not write concepts for all chips, but
/// only the parent of this cell).
bool pmConceptsWriteCell(const pmCell *cell,  ///< FPA for which to write concepts
                         pmConceptSource source, ///< Source for concepts
                         bool propagateUp, ///< Propagate to higher levels?
                         psDB *db       ///< Database handle
                        );

/// Initialise the concepts system.
///
/// Register the standard concepts, so that concepts may be read and written.  This function is called
/// automatically the first time the concepts functions are used.
bool pmConceptsInit(void);

/// Signifies that the user is done with the concepts system.
///
/// Frees the registered concepts so there is no memory leak when the user checks "persistent" memory.
void pmConceptsDone(void);

/// Copy all the concepts within an FPA to another FPA
///
/// Iterates over all components of the FPA, and copies the concepts metadata from the source to the target.
bool pmFPACopyConcepts(pmFPA *target,   ///< The target FPA
                       const pmFPA *source    ///< The source FPA
                      );
/// @}
#endif
