#ifndef PM_CONCEPTS_H
#define PM_CONCEPTS_H

#include "pslib.h"

#include "pmFPA.h"

// Function to call to read a concept
typedef psMetadataItem* (*pmConceptReadFunc)(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db);
// Function to call to write a concept
typedef bool (*pmConceptWriteFunc)(pmFPA *fpa, pmChip *chip, pmCell *cell, psDB *db);

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

// Allocator
pmConceptSpec *pmConceptSpecAlloc(psMetadataItem *blank, // Blank value; contains the name
                                  pmConceptReadFunc read, // Function to call to read the concept
                                  pmConceptWriteFunc write // Function to call to write the concept
                                 );

// Level at which to store a concept in the FPA hierarchy
typedef enum {
    PM_CONCEPT_LEVEL_FPA,               // Store in the FPA
    PM_CONCEPT_LEVEL_CHIP,              // Store in the chip
    PM_CONCEPT_LEVEL_CELL               // Store in the cell
} pmConceptLevel;

// Register a new concept
bool pmConceptRegister(psMetadataItem *blank, // Blank value; contains the name
                       pmConceptReadFunc read, // Function to call to read the concept
                       pmConceptWriteFunc write, // Function to call to write the concept
                       pmConceptLevel level // Level at which to store concept in the FPA hierarchy
                      );

// 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
                       psDB *db         // Database handle
                      );
bool pmConceptsWriteFPA(pmFPA *fpa,     // FPA for which to write concepts
                        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
                        psDB *db        // Database handle
                       );
bool pmConceptsWriteChip(pmChip *chip,  // Chip for which to write concepts
                         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
                        psDB *db        // Database handle
                       );
bool pmConceptsWriteCell(pmCell *cell,  // FPA for which to write concepts
                         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
