#ifndef PM_CONCEPTS_H
#define PM_CONCEPTS_H

#include "pslib.h"
#include "pmFPA.h"

// Function to call to parse a concept once it has been read
typedef psMetadataItem* (*pmConceptParseFunc)(const psMetadataItem *concept, const psMetadataItem *pattern, const psMetadata *cameraFormat, const pmFPA *fpa, const pmChip *chip, const pmCell *cell);
// Function to call to format a concept for writing
typedef psMetadataItem* (*pmConceptFormatFunc)(const psMetadataItem *concept, const psMetadata *cameraFormat, const pmFPA *fpa, const pmChip *chip, const pmCell *cell);

// A "concept" specification
typedef struct
{
    psMetadataItem *blank;              // Blank value of concept; also contains the name
    pmConceptParseFunc parse;           // Function to call to read the concept
    pmConceptFormatFunc format;         // Function to call to write the concept
}
pmConceptSpec;

// Allocator
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
                                 );

// Register a new concept
bool pmConceptRegister(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
                       pmFPALevel level // Level at which to store concept in the FPA hierarchy
                      );

// Some specificity to reading and writing concepts
typedef enum {
    PM_CONCEPT_SOURCE_NONE     = 0x00,  // No concepts
    PM_CONCEPT_SOURCE_CAMERA   = 0x01,  // Concept comes from the camera information
    PM_CONCEPT_SOURCE_DEFAULTS = 0x02,  // Concept comes from defaults
    PM_CONCEPT_SOURCE_HEADER   = 0x04,  // Concept comes from FITS header
    PM_CONCEPT_SOURCE_DATABASE = 0x08,  // Concept comes from database
    PM_CONCEPT_SOURCE_ALL      = 0x0e   // All concepts
} pmConceptSource;

// Set blanks, read or write concepts at the appropriate level
bool pmConceptsBlankFPA(pmFPA *fpa      // FPA for which to set blank concepts
                       );
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
                      );
bool pmConceptsWriteFPA(pmFPA *fpa,     // FPA for which to write concepts
                        pmConceptSource source, // Source for concepts
                        bool propagateDown, // Propagate to lower levels?
                        psDB *db        // Database handle
                       );
bool pmConceptsBlankChip(pmChip *chip   // FPA for which to set blank concepts
                        );
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
                       );
bool pmConceptsWriteChip(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
                        );
bool pmConceptsBlankCell(pmCell *cell   // Cell for which to set blank concepts
                        );
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
                       );
bool pmConceptsWriteCell(pmCell *cell,  // FPA for which to write concepts
                         pmConceptSource source, // Source for concepts
                         bool propagateUp, // Propagate to higher levels?
                         psDB *db       // Database handle
                        );

// Set up the blank concepts
bool pmConceptsInit(void);
// Free the concept specs so there's no memory leak
void pmConceptsDone(void);

// Copy all the concepts within an FPA to another FPA
bool pmFPACopyConcepts(pmFPA *target,   // The target FPA
                       pmFPA *source    // The target FPA
                      );


#endif
