Index: trunk/psModules/src/camera/pmFPA.c
===================================================================
--- trunk/psModules/src/camera/pmFPA.c	(revision 12590)
+++ trunk/psModules/src/camera/pmFPA.c	(revision 12603)
@@ -277,4 +277,5 @@
     tmpCell->file_exists = false;       // Not yet identified
     tmpCell->data_exists = false;       // Not yet read in
+    tmpCell->wrote_phu = false;
 
     tmpCell->concepts = psMetadataAlloc();
@@ -311,4 +312,5 @@
     tmpChip->file_exists = false;       // Not yet identified
     tmpChip->data_exists = false;       // Not yet read in
+    tmpChip->wrote_phu = false;
 
     tmpChip->concepts = psMetadataAlloc();
@@ -337,4 +339,5 @@
     tmpFPA->chips = psArrayAlloc(0);
     tmpFPA->hdu = NULL;
+    tmpFPA->wrote_phu = false;
 
     tmpFPA->concepts = psMetadataAlloc();
Index: trunk/psModules/src/camera/pmFPA.h
===================================================================
--- trunk/psModules/src/camera/pmFPA.h	(revision 12590)
+++ trunk/psModules/src/camera/pmFPA.h	(revision 12603)
@@ -6,6 +6,6 @@
  * @author Eugene Magnier, IfA
  *
- * @version $Revision: 1.12 $ $Name: not supported by cvs2svn $
- * @date $Date: 2007-01-24 02:54:14 $
+ * @version $Revision: 1.13 $ $Name: not supported by cvs2svn $
+ * @date $Date: 2007-03-27 20:49:57 $
  * Copyright 2005-2006 Institute for Astronomy, University of Hawaii
  */
@@ -44,4 +44,5 @@
     psArray *chips;                     ///< The component chips
     pmHDU *hdu;                         ///< FITS header data unit of interest, or NULL
+    bool wrote_phu;                     ///< Have we written a PHU at this level? (write case only)
 }
 pmFPA;
@@ -71,4 +72,5 @@
     bool data_exists;                   ///< Does the data for this chip exist (read case only)?
     pmHDU *hdu;                         ///< FITS header data unit of interest,
+    bool wrote_phu;                     ///< Have we written a PHU at this level? (write case only)
 }
 pmChip;
@@ -103,4 +105,5 @@
     bool data_exists;                   ///< Does the data for this cell exist (read case only)?
     pmHDU *hdu;                         ///< FITS header data unit of interest
+    bool wrote_phu;                     ///< Have we written a PHU at this level? (write case only)
 }
 pmCell;
Index: trunk/psModules/src/camera/pmFPAfileDefine.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 12590)
+++ trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 12603)
@@ -930,5 +930,5 @@
 
     if (config->cameraName[0] == '_' &&
-            strcmp(config->cameraName + strlen(config->cameraName) - 5, "-CHIP") == 0) {
+	strcmp(config->cameraName + strlen(config->cameraName) - 5, "-CHIP") == 0) {
         // The input camera has already been mosaicked to this level
         pmFPAfile *file = pmFPAfileDefineOutput(config, NULL, filename);
Index: trunk/psModules/src/camera/pmFPAfileFitsIO.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileFitsIO.c	(revision 12590)
+++ trunk/psModules/src/camera/pmFPAfileFitsIO.c	(revision 12603)
@@ -76,7 +76,10 @@
         psFree(copy);
         psFree(phuView);
-        return false;
+        return NULL;
     }
     psFree(phuView);
+
+    // preserve this state variable
+    copy->wrote_phu = file->fpa->wrote_phu;
 
     switch (level) {
Index: trunk/psModules/src/camera/pmFPAfileIO.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileIO.c	(revision 12590)
+++ trunk/psModules/src/camera/pmFPAfileIO.c	(revision 12603)
@@ -31,6 +31,489 @@
 #include "pmDetrendDB.h"
 
-// XXXX should we require this function to be called only within pmFPAfileRead or pmFPAfileWrite?
-// open file (if not already opened)
+// attempt create, read, write, close, or free pmFPAfiles available in files files are
+// automatically opened before they are read.  In the case of MEF files, the PHU is
+// read when the file is opened and written before the first extension is written.
+bool pmFPAfileIOChecks (pmConfig *config, const pmFPAview *view, pmFPAfilePlace place)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    PS_ASSERT_PTR_NON_NULL(config->files, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    psMetadata *files = config->files;
+
+    // attempt to perform all create, read, write, close operations
+    psMetadataItem *item = NULL;
+    psMetadataIterator *iter = psMetadataIteratorAlloc (files, PS_LIST_HEAD, NULL);
+    while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
+        pmFPAfile *file = item->data.V;
+
+        switch (place) {
+        case PM_FPA_BEFORE:
+            if (!pmFPAfileRead (file, view, config)) {
+                psError(PS_ERR_IO, false, "failed READ in FPA_BEFORE block for %s", file->name);
+                goto failure;
+            }
+            if (!pmFPAfileCreate(file, view, config)) {
+                psError(PS_ERR_IO, false, "failed CREATE in FPA_BEFORE block for %s", file->name);
+                goto failure;
+            }
+            break;
+        case PM_FPA_AFTER:
+            if (!pmFPAfileWrite (file, view, config)) {
+                psError(PS_ERR_IO, false, "failed WRITE in FPA_AFTER block for %s", file->name);
+                goto failure;
+            }
+            if (!pmFPAfileClose(file, view)) {
+                psError(PS_ERR_IO, false, "failed CLOSE in FPA_AFTER block for %s", file->name);
+                goto failure;
+            }
+            break;
+        default:
+            psAbort("You can't get here");
+        }
+    }
+
+    // attempt to free data that is no longer needed
+    psMetadataIteratorSet (iter, PS_LIST_HEAD);
+    while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
+        pmFPAfile *file = item->data.V;
+
+        switch (place) {
+        case PM_FPA_BEFORE:
+            break;
+        case PM_FPA_AFTER:
+            if (!pmFPAfileFreeData(file, view)) {
+                if (!psMetadataRemoveKey(files, file->name)) {
+                    psError(PS_ERR_IO, false, "failed to remove %s in FPA_AFTER block", file->name);
+                    goto failure;
+                }
+            }
+            break;
+        default:
+            psAbort("You can't get here");
+        }
+    }
+    psFree (iter);
+    return true;
+
+failure:
+    psFree (iter);
+    return false;
+}
+
+// read the file, if necessary and possible
+bool pmFPAfileRead(pmFPAfile *file, const pmFPAview *view, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(file, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    // an internal file should not be sent here (should not be left on config->files)
+    PS_ASSERT(file->mode != PM_FPA_MODE_INTERNAL, false);
+
+    // skip the following states
+    if (file->state & PM_FPA_STATE_INACTIVE) {
+        psTrace("psModules.camera", 6, "skip read for %s, file is inactive", file->name);
+        return true;
+    }
+    if (file->mode != PM_FPA_MODE_READ) {
+        psTrace("psModules.camera", 6, "skip read for %s, mode is not READ", file->name);
+        return true;
+    }
+
+    // get the current level
+    pmFPALevel level = pmFPAviewLevel (view);
+
+    // do we need to read this file? defer until we read the correct level
+    if (level != file->dataLevel) {
+        psTrace("psModules.camera", 6, "skip reading of %s at this level %s: dataLevel is %s",
+                file->name, pmFPALevelToName(level), pmFPALevelToName(file->dataLevel));
+        return true;
+    }
+
+    // do we need to open this file?
+    if (level >= file->fileLevel) {
+	// we are allowed to open a file at a level which is not the fileLevel, but we need to
+	// supply a view at the fileLevel for the file lookup functions below
+	pmFPAview *fileView = pmFPAviewForLevel (file->fileLevel, view);
+	if (!pmFPAfileOpen (file, fileView, config)) {
+            psError(PS_ERR_IO, false, "failed to open file %s (%s)", file->filename, file->name);
+	    psFree (fileView);
+            return false;
+        }
+	psFree (fileView);
+    }
+
+    // We need to read it --- double-check it's open!
+    if (file->state == PM_FPA_STATE_CLOSED) {
+	psError(PS_ERR_IO, false, "failed to open file %s when attempting to read", file->name);
+	return false;
+    }
+
+    // select a reading method
+    bool status = true;
+    switch (file->type) {
+      case PM_FPA_FILE_IMAGE:
+	status = pmFPAviewReadFitsImage(view, file);
+	break;
+      case PM_FPA_FILE_MASK:
+	status = pmFPAviewReadFitsMask(view, file);
+        break;
+      case PM_FPA_FILE_WEIGHT:
+	status = pmFPAviewReadFitsWeight(view, file);
+        break;
+      case PM_FPA_FILE_HEADER:
+	status = pmFPAviewReadFitsHeaderSet(view, file);
+        break;
+      case PM_FPA_FILE_FRINGE:
+	status = pmFPAviewReadFitsImage (view, file);
+	if (status) {
+	    if (!pmFPAviewReadFitsTable(view, file, "FRINGE")) {
+		psError(PS_ERR_UNKNOWN, false, "Unable to read fringe data from %s.\n", file->filename);
+		return false;
+	    }
+	}
+	break;
+      case PM_FPA_FILE_SX:
+      case PM_FPA_FILE_RAW:
+      case PM_FPA_FILE_OBJ:
+      case PM_FPA_FILE_CMP:
+      case PM_FPA_FILE_CMF:
+        status = pmFPAviewReadObjects (view, file, config);
+        break;
+      case PM_FPA_FILE_PSF:
+	status = pmFPAviewReadPSFmodel (view, file, config);
+        break;
+      case PM_FPA_FILE_JPEG:
+      case PM_FPA_FILE_KAPA:
+        break;
+      default:
+        psError(PS_ERR_IO, true, "warning: type mismatch; saw type %d (%s)", file->type, file->name);
+        return false;
+    }
+    if (!status) {
+	psError(PS_ERR_UNKNOWN, false, "failed to read %s (%s)\n", file->filename, file->name);
+	return false;
+    }
+    psTrace ("psModules.camera", 5, "read %s (%s)\n", file->filename, file->name);
+    return true;
+}
+
+// create the data elements (headers, images) appropriate for this view
+bool pmFPAfileCreate (pmFPAfile *file, const pmFPAview *view, const pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(file, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    // these are not error conditions; these are state tests
+    if (file->state & PM_FPA_STATE_INACTIVE) {
+        psTrace("psModules.camera", 6, "skip create for inactive file %s", file->name);
+        return true;
+    }
+    if (file->mode != PM_FPA_MODE_WRITE) {
+        psTrace("psModules.camera", 6, "skip create for non-write file %s", file->name);
+        return true;
+    }
+
+    // an internal file should not be returned to here
+    PS_ASSERT(file->mode != PM_FPA_MODE_INTERNAL, false);
+
+    // get the current level
+    pmFPALevel level = pmFPAviewLevel (view);
+
+    // don't create the file if the src (FPA) is not defined
+    if (file->src == NULL) {
+        psTrace("psModules.camera", 6, "skip create for FPA without src FPA for %s", file->name);
+        return true;
+    }
+
+    // do we need to write this file?
+    if (level != file->fileLevel || file->mosaicLevel != PM_FPA_LEVEL_NONE) {
+        psTrace("psModules.camera", 6, "skip creation of %s at this level %s: fileLevel is %s",
+                file->name, pmFPALevelToName(level), pmFPALevelToName(file->fileLevel));
+        return true;
+    }
+
+    switch (file->type) {
+    case PM_FPA_FILE_IMAGE:
+    case PM_FPA_FILE_MASK:
+    case PM_FPA_FILE_WEIGHT:
+    case PM_FPA_FILE_FRINGE: {
+            // create FPA structure component based on view
+            psMetadata *format = file->format; // Camera format configuration
+            if (!format) {
+                format = config->format;
+            }
+
+            pmFPA *nameSource = file->src; // Source of FPA.NAME
+            if (!nameSource) {
+                nameSource = file->fpa;
+            }
+            bool mdok;                  // Status of MD lookup
+            const char *fpaname = psMetadataLookupStr(&mdok, nameSource->concepts, "FPA.NAME"); // Name of FPA
+
+            pmFPAAddSourceFromView(file->fpa, fpaname, view, format);
+            psTrace ("psModules.camera", 5, "created fpa data elements for %s (fpa: %p)\n", file->name, file->fpa);
+            break;
+    }
+    case PM_FPA_FILE_HEADER:
+      psAbort ("Create not defined for HEADER");
+      break;
+    case PM_FPA_FILE_SX:
+    case PM_FPA_FILE_RAW:
+    case PM_FPA_FILE_OBJ:
+    case PM_FPA_FILE_CMP:
+    case PM_FPA_FILE_CMF:
+    case PM_FPA_FILE_PSF:
+    case PM_FPA_FILE_JPEG:
+    case PM_FPA_FILE_KAPA:
+        break;
+
+    default:
+        psError(PS_ERR_IO, true, "Unsupported type for %s: %d", file->name, file->type);
+        return false;
+    }
+    return true;
+}
+
+bool pmFPAfileWrite(pmFPAfile *file, const pmFPAview *view, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(file, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    if (file->state & PM_FPA_STATE_INACTIVE) {
+        psTrace("psModules.camera", 6, "skip write for %s, files is inactive", file->name);
+        return true;
+    }
+
+    if (file->mode != PM_FPA_MODE_WRITE) {
+        psTrace("psModules.camera", 6, "skip write for %s, mode is not WRITE", file->name);
+        return true;
+    }
+
+    // an internal file should not be returned to here
+    if (file->mode == PM_FPA_MODE_INTERNAL) {
+        psError(PS_ERR_IO, true, "File is mode PM_FPA_MODE_INTERNAL");
+        return false;
+    }
+
+    if (!file->save) {
+        psTrace("psModules.camera", 6, "skip write for %s, save is FALSE", file->name);
+        return true;
+    }
+
+    // get the current level
+    pmFPALevel level = pmFPAviewLevel (view);
+
+    // the effective dataLevel (for mosaics, we have preserved the original dataLevel)
+    pmFPALevel dataLevel = (file->mosaicLevel != PM_FPA_LEVEL_NONE) ? file->mosaicLevel : file->dataLevel;
+
+    // do we need to write this file?
+    if (level != dataLevel) {
+        psTrace("psModules.camera", 6, "skip writing of %s at this level %s: dataLevel is %s",
+                file->name, pmFPALevelToName(level), pmFPALevelToName(dataLevel));
+        return true;
+    }
+
+    // open the file if not yet opened
+    // XXX do we need to test mosaicLevel?
+    if (level >= file->fileLevel) {
+	// we are allowed to open a file at a level which is not the fileLevel, but 
+	// we need to supply view at the fileLevel for the file lookup functions below
+	pmFPAview *fileView = pmFPAviewForLevel (file->fileLevel, view);
+        if (!pmFPAfileOpen (file, fileView, config)) {
+            psError(PS_ERR_IO, false, "failed to open %s (%s)", file->filename, file->name);
+	    psFree (fileView);
+            return false;
+        }
+	psFree (fileView);
+    }
+
+    // do we need to write out a PHU?
+    if (level >= file->fileLevel) {
+        if (!pmFPAfileWritePHU (file, view, config)) {
+            psError(PS_ERR_IO, false, "failed to write phu for %s (%s)", file->filename, file->name);
+            return false;
+        }
+    }
+
+    // select a writing method
+    bool status = true;
+    switch (file->type) {
+      case PM_FPA_FILE_IMAGE:
+        status = pmFPAviewWriteFitsImage(view, file, config);
+        break;
+      case PM_FPA_FILE_MASK:
+	status = pmFPAviewWriteFitsMask(view, file, config);
+        break;
+      case PM_FPA_FILE_WEIGHT:
+	status = pmFPAviewWriteFitsWeight(view, file, config);
+        break;
+      case PM_FPA_FILE_HEADER:
+	psAbort ("no HEADER write functions defined");
+        break;
+      case PM_FPA_FILE_FRINGE:
+	status = pmFPAviewWriteFitsImage (view, file, config);
+	if (status) {
+	    if (!pmFPAviewWriteFitsTable(view, file, "FRINGE")) {
+		psError(PS_ERR_UNKNOWN, false, "Unable to write fringe data from %s.\n", file->filename);
+		return false;
+	    }
+	}
+        break;
+      case PM_FPA_FILE_SX:
+      case PM_FPA_FILE_RAW:
+      case PM_FPA_FILE_OBJ:
+      case PM_FPA_FILE_CMP:
+      case PM_FPA_FILE_CMF:
+        status = pmFPAviewWriteObjects (view, file, config);
+        break;
+
+      case PM_FPA_FILE_PSF:
+        status = pmFPAviewWritePSFmodel (view, file, config);
+        break;
+
+      case PM_FPA_FILE_JPEG:
+        status = pmFPAviewWriteJPEG (view, file, config);
+        break;
+
+      case PM_FPA_FILE_KAPA:
+        status = pmFPAviewWriteSourcePlot (view, file, config);
+        break;
+
+      default:
+        psError(PS_ERR_IO, true, "warning: type mismatch; saw type %d (%s)", file->type, file->name);
+        return false;
+    }
+    if (!status) {
+	psError(PS_ERR_UNKNOWN, false, "failed to write %s (%s)\n", file->filename, file->name);
+	return false;
+    }
+    psTrace ("psModules.camera", 5, "wrote %s (fpa: %p)\n", file->filename, file->fpa);
+    return true;
+}
+
+bool pmFPAfileClose (pmFPAfile *file, const pmFPAview *view)
+{
+    PS_ASSERT_PTR_NON_NULL(file, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    // an internal file should not be sent here (should not be left on config->files)
+    PS_ASSERT(file->mode != PM_FPA_MODE_INTERNAL, false);
+
+    // skip the following states
+    if (file->state & PM_FPA_STATE_INACTIVE) {
+        psTrace("psModules.camera", 6, "skip close for %s, files is inactive", file->name);
+        return true;
+    }
+    if (file->state == PM_FPA_STATE_CLOSED) {
+        psTrace("psModules.camera", 6, "skip close for %s, files is closed", file->name);
+        return true;
+    }
+
+    // is current level == open level?
+    pmFPALevel level = pmFPAviewLevel (view);
+    if (file->fileLevel != level) {
+        psTrace("psModules.camera", 6, "skip closing of %s at this level %s: dataLevel is %s",
+                file->name, pmFPALevelToName(level), pmFPALevelToName(file->dataLevel));
+        return true;
+    }
+
+    // check if we are actually open
+    bool status = true;
+    switch (file->type) {
+        // check the FITS types
+      case PM_FPA_FILE_IMAGE:
+      case PM_FPA_FILE_MASK:
+      case PM_FPA_FILE_WEIGHT:
+      case PM_FPA_FILE_HEADER:
+      case PM_FPA_FILE_FRINGE:
+      case PM_FPA_FILE_CMF:
+        psTrace ("psModules.camera", 5, "closing %s (type: %d)\n", file->filename, file->type);
+        status = psFitsClose (file->fits);
+        file->fits = NULL;
+        file->phu = NULL;
+        file->header = NULL;
+        file->state = PM_FPA_STATE_CLOSED;
+        break;
+
+        // ignore the TEXT types
+      case PM_FPA_FILE_SX:
+      case PM_FPA_FILE_RAW:
+      case PM_FPA_FILE_OBJ:
+      case PM_FPA_FILE_CMP:
+      case PM_FPA_FILE_PSF:
+      case PM_FPA_FILE_JPEG:
+      case PM_FPA_FILE_KAPA:
+        break;
+
+      default:
+        psError(PS_ERR_IO, true, "type mismatch: %d (%s)", file->type, file->name);
+        return false;
+    }
+    if (!status) {
+	psError(PS_ERR_UNKNOWN, false, "failed to close %s (%s)\n", file->filename, file->name);
+	return false;
+    }
+    return true;
+}
+
+bool pmFPAfileFreeData(pmFPAfile *file, const pmFPAview *view)
+{
+    PS_ASSERT_PTR_NON_NULL(file, false);
+    PS_ASSERT_PTR_NON_NULL(view, false);
+
+    // an internal file should not be sent here (should not be left on config->files)
+    PS_ASSERT(file->mode != PM_FPA_MODE_INTERNAL, false);
+
+    if (file->state & PM_FPA_STATE_INACTIVE) {
+        psTrace("psModules.camera", 6, "skip free for %s, files is inactive", file->name);
+        return true;
+    }
+
+    // get the current level
+    pmFPALevel level = pmFPAviewLevel (view);
+
+    // do we need to free this file?
+    if (level != file->freeLevel) {
+        psTrace("psModules.camera", 6, "skip free of %s at this level %s: freeLevel is %s",
+                file->name, pmFPALevelToName(level), pmFPALevelToName(file->freeLevel));
+        return true;
+    }
+
+    bool status = true;
+    switch (file->type) {
+      case PM_FPA_FILE_IMAGE:
+      case PM_FPA_FILE_MASK:
+      case PM_FPA_FILE_WEIGHT:
+      case PM_FPA_FILE_HEADER:
+      case PM_FPA_FILE_FRINGE:
+	status = pmFPAviewFreeData(view, file);
+        break;
+      case PM_FPA_FILE_SX:
+      case PM_FPA_FILE_RAW:
+      case PM_FPA_FILE_OBJ:
+      case PM_FPA_FILE_CMP:
+      case PM_FPA_FILE_CMF:
+	psTrace ("psModules.camera", 5, "NOT freeing %s (%s) : save for further analysis\n", file->filename, file->name);
+        break;
+      case PM_FPA_FILE_PSF:
+      case PM_FPA_FILE_JPEG:
+      case PM_FPA_FILE_KAPA:
+	psTrace ("psModules.camera", 5, "nothing to free for %s (%s)\n", file->filename, file->name);
+        break;
+      default:
+        psError(PS_ERR_IO, true, "warning: type mismatch; saw type %d", file->type);
+        return false;
+    }
+    if (!status) {
+	psError(PS_ERR_UNKNOWN, false, "failed to read %s (%s)\n", file->filename, file->name);
+	return false;
+    }
+    psTrace ("psModules.camera", 5, "freed %s (%s)\n", file->filename, file->name);
+    return true;
+}
+
+// open file (if not already opened).
+// this function is only called only within pmFPAfileRead or pmFPAfileWrite.
 bool pmFPAfileOpen (pmFPAfile *file, const pmFPAview *view, pmConfig *config)
 {
@@ -52,13 +535,8 @@
     }
 
-    // XXX are these programming errors?
-    if (file->mode == PM_FPA_MODE_NONE) {
-        psError(PS_ERR_IO, true, "File is mode PM_FPA_MODE_NONE");
-        return false;
-    }
-    if (file->mode == PM_FPA_MODE_INTERNAL) {
-        psError(PS_ERR_IO, true, "File is mode PM_FPA_MODE_INTERNAL");
-        return false;
-    }
+    // these are programming errors
+    PS_ASSERT(file->mode != PM_FPA_MODE_NONE, false);
+    PS_ASSERT(file->mode != PM_FPA_MODE_INTERNAL, false);
+
     if (file->mode == PM_FPA_MODE_READ) {
         mode = readMode;
@@ -200,564 +678,4 @@
     }
     return true;
-}
-
-bool pmFPAfileRead(pmFPAfile *file, const pmFPAview *view, pmConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(file, false);
-    PS_ASSERT_PTR_NON_NULL(view, false);
-
-    // an internal file should not be sent here
-    // XXX is this a programming error?
-    if (file->mode == PM_FPA_MODE_INTERNAL) {
-        psError(PS_ERR_IO, true, "File is mode PM_FPA_MODE_INTERNAL");
-        return false;
-    }
-
-    if (file->state & PM_FPA_STATE_INACTIVE) {
-        psTrace("psModules.camera", 6, "skip read for %s, file is inactive", file->name);
-        return true;
-    }
-
-    if (file->mode != PM_FPA_MODE_READ) {
-        psTrace("psModules.camera", 6, "skip read for %s, mode is not READ", file->name);
-        return true;
-    }
-
-    // get the current level
-    pmFPALevel level = pmFPAviewLevel (view);
-
-    // do we need to read this file? defer until we read the correct level
-    if (level != file->dataLevel) {
-        psTrace("psModules.camera", 6, "skip reading of %s at this level %s: dataLevel is %s",
-                file->name, pmFPALevelToName(level), pmFPALevelToName(file->dataLevel));
-        return true;
-    }
-
-    // do we need to open this file?
-    if (level >= file->fileLevel) {
-	// we are allowed to open a file at a level which is not the fileLevel, but 
-	// we need to supply view at the fileLevel for the file lookup functions below
-	pmFPAview *fileView = pmFPAviewForLevel (file->fileLevel, view);
-	if (!pmFPAfileOpen (file, fileView, config)) {
-            psError(PS_ERR_IO, false, "failed to open file %s (%s)", file->filename, file->name);
-	    psFree (fileView);
-            return false;
-        }
-	psFree (fileView);
-    }
-
-    // We need to read it --- double-check it's open!
-    if (file->state == PM_FPA_STATE_CLOSED) {
-	psError(PS_ERR_IO, false, "failed to open file %s when attempting to read", file->name);
-	return false;
-    }
-
-    // select a reading method
-    bool status = false;
-    switch (file->type) {
-      case PM_FPA_FILE_IMAGE:
-	status = pmFPAviewReadFitsImage(view, file);
-	break;
-      case PM_FPA_FILE_MASK:
-	status = pmFPAviewReadFitsMask(view, file);
-        break;
-      case PM_FPA_FILE_WEIGHT:
-	status = pmFPAviewReadFitsWeight(view, file);
-        break;
-      case PM_FPA_FILE_HEADER:
-	status = pmFPAviewReadFitsHeaderSet(view, file);
-        break;
-      case PM_FPA_FILE_FRINGE:
-	status = pmFPAviewReadFitsImage (view, file);
-	if (status) {
-	    if (!pmFPAviewReadFitsTable(view, file, "FRINGE")) {
-		psError(PS_ERR_UNKNOWN, false, "Unable to read fringe data from %s.\n", file->filename);
-		return false;
-	    }
-	}
-	break;
-      case PM_FPA_FILE_SX:
-      case PM_FPA_FILE_RAW:
-      case PM_FPA_FILE_OBJ:
-      case PM_FPA_FILE_CMP:
-      case PM_FPA_FILE_CMF:
-        status = pmFPAviewReadObjects (view, file, config);
-        break;
-      case PM_FPA_FILE_PSF:
-	status = pmFPAviewReadPSFmodel (view, file, config);
-        break;
-      case PM_FPA_FILE_JPEG:
-      case PM_FPA_FILE_KAPA:
-        break;
-      default:
-        psError(PS_ERR_IO, true, "warning: type mismatch; saw type %d (%s)", file->type, file->name);
-        return false;
-    }
-
-    if (!status) {
-	psError(PS_ERR_UNKNOWN, false, "skipping %s (%s)\n", file->filename, file->name);
-	return false;
-    }
-    psTrace ("psModules.camera", 5, "read %s (%s)\n", file->filename, file->name);
-
-    return true;
-}
-
-bool pmFPAfileFreeData(pmFPAfile *file, const pmFPAview *view)
-{
-    PS_ASSERT_PTR_NON_NULL(file, false);
-    PS_ASSERT_PTR_NON_NULL(view, false);
-
-    if (file->state & PM_FPA_STATE_INACTIVE) {
-        psTrace("psModules.camera", 6, "skip free for %s, files is inactive", file->name);
-        return true;
-    }
-
-    // an internal file should not be sent here
-    if (file->mode == PM_FPA_MODE_INTERNAL) {
-        psError(PS_ERR_IO, true, "File is mode PM_FPA_MODE_INTERNAL");
-        return false;
-    }
-
-    // get the current level
-    pmFPALevel level = pmFPAviewLevel (view);
-
-    // do we need to free this file?
-    if (level != file->freeLevel) {
-        psTrace("psModules.camera", 6, "skip free of %s at this level %s: freeLevel is %s",
-                file->name, pmFPALevelToName(level), pmFPALevelToName(file->freeLevel));
-        return true;
-    }
-
-    switch (file->type) {
-    case PM_FPA_FILE_IMAGE:
-    case PM_FPA_FILE_MASK:
-    case PM_FPA_FILE_WEIGHT:
-    case PM_FPA_FILE_HEADER:
-    case PM_FPA_FILE_FRINGE:
-        if (pmFPAviewFreeData(view, file)) {
-            psTrace ("psModules.camera", 5, "freed %s (%s)\n", file->filename, file->name);
-            if (file->filename == NULL) {
-                psTrace ("psModules.camera", 5, "filename is not defined for %s\n", file->name);
-            }
-        } else {
-            psError(PS_ERR_UNKNOWN, false, "skipping %s (%s)\n", file->filename, file->name);
-            return false;
-        }
-        break;
-    case PM_FPA_FILE_SX:
-    case PM_FPA_FILE_RAW:
-    case PM_FPA_FILE_OBJ:
-    case PM_FPA_FILE_CMP:
-    case PM_FPA_FILE_CMF:
-        // pmFPAviewFreeObjects (view, file);
-        psTrace ("psModules.camera", 5, "NOT freeing %s (%s)\n", file->filename, file->name);
-        break;
-
-        // XXX not certain what I need to free here
-    case PM_FPA_FILE_PSF:
-    case PM_FPA_FILE_JPEG:
-    case PM_FPA_FILE_KAPA:
-        break;
-
-    default:
-        psError(PS_ERR_IO, true, "warning: type mismatch; saw type %d", file->type);
-        return false;
-    }
-    return true;
-}
-
-bool pmFPAfileWrite(pmFPAfile *file, const pmFPAview *view, pmConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(file, false);
-    PS_ASSERT_PTR_NON_NULL(view, false);
-
-    if (file->state & PM_FPA_STATE_INACTIVE) {
-        psTrace("psModules.camera", 6, "skip write for %s, files is inactive", file->name);
-        return true;
-    }
-
-    if (file->mode != PM_FPA_MODE_WRITE) {
-        psTrace("psModules.camera", 6, "skip write for %s, mode is not WRITE", file->name);
-        return true;
-    }
-
-    // an internal file should not be returned to here
-    if (file->mode == PM_FPA_MODE_INTERNAL) {
-        psError(PS_ERR_IO, true, "File is mode PM_FPA_MODE_INTERNAL");
-        return false;
-    }
-
-    if (!file->save) {
-        psTrace("psModules.camera", 6, "skip write for %s, save is FALSE", file->name);
-        return true;
-    }
-
-    // get the current level
-    pmFPALevel level = pmFPAviewLevel (view);
-
-    // do we need to write this file?
-    if ((file->mosaicLevel == PM_FPA_LEVEL_NONE && level != file->dataLevel) || // No mosaicking happening
-	(file->mosaicLevel != PM_FPA_LEVEL_NONE && level != file->mosaicLevel)) { // Mosaicking happening
-        psTrace("psModules.camera", 6, "skip writing of %s at this level %s: dataLevel is %s",
-                file->name, pmFPALevelToName(level), pmFPALevelToName(file->dataLevel));
-        return true;
-    }
-
-    // do we need to open this file?
-    // XXX do we need both mosaicLevel and dataLevel?
-# if (0)    
-    if (level >= file->fileLevel &&
-	(file->mosaicLevel == PM_FPA_LEVEL_NONE ||
-	 (file->mosaicLevel != PM_FPA_LEVEL_NONE && level >= file->mosaicLevel))) {
-        if (!pmFPAfileOpen (file, view, config)) {
-            psError(PS_ERR_IO, false, "failed to open %s", file->filename);
-            return false;
-        }
-    }
-# endif 
-
-    // open the file if not yet opened
-    if (level >= file->fileLevel) {
-	// we are allowed to open a file at a level which is not the fileLevel, but 
-	// we need to supply view at the fileLevel for the file lookup functions below
-	pmFPAview *fileView = pmFPAviewForLevel (file->fileLevel, view);
-        if (!pmFPAfileOpen (file, fileView, config)) {
-            psError(PS_ERR_IO, false, "failed to open %s (%s)", file->filename, file->name);
-	    psFree (fileView);
-            return false;
-        }
-	psFree (fileView);
-    }
-
-    // do we need to write out a PHU?
-    if (level >= file->fileLevel) {
-        if (!pmFPAfileWritePHU (file, view, config)) {
-            psError(PS_ERR_IO, false, "failed to write phu for %s (%s)", file->filename, file->name);
-            return false;
-        }
-    }
-
-    // XXX catch error status
-    switch (file->type) {
-    case PM_FPA_FILE_IMAGE:
-        pmFPAviewWriteFitsImage(view, file, config);
-        psTrace ("psModules.camera", 5, "wrote image %s (fpa: %p)\n", file->filename, file->fpa);
-        break;
-    case PM_FPA_FILE_MASK:
-        pmFPAviewWriteFitsMask(view, file, config);
-        psTrace ("psModules.camera", 5, "wrote mask %s (fpa: %p)\n", file->filename, file->fpa);
-        break;
-    case PM_FPA_FILE_WEIGHT:
-        pmFPAviewWriteFitsWeight(view, file, config);
-        psTrace ("psModules.camera", 5, "wrote weight %s (fpa: %p)\n", file->filename, file->fpa);
-        break;
-    case PM_FPA_FILE_HEADER:
-      // pmFPAviewWriteFitsWeight(view, file, config);
-      // psTrace ("psModules.camera", 5, "wrote weight %s (fpa: %p)\n", file->filename, file->fpa);
-      psAbort ("no HEADER write functions defined");
-        break;
-    case PM_FPA_FILE_FRINGE:
-        pmFPAviewWriteFitsImage (view, file, config);
-        psTrace ("psModules.camera", 5, "wrote image %s (fpa: %p)\n", file->filename, file->fpa);
-        pmFPAviewWriteFitsTable(view, file, "FRINGE");
-        psTrace ("psModules.camera", 5, "wrote fringe table %s (fpa: %p)\n", file->filename, file->fpa);
-        break;
-
-    case PM_FPA_FILE_SX:
-    case PM_FPA_FILE_RAW:
-    case PM_FPA_FILE_OBJ:
-    case PM_FPA_FILE_CMP:
-    case PM_FPA_FILE_CMF:
-        psTrace ("psModules.camera", 5, "writing object %s (fpa: %p)\n", file->filename, file->fpa);
-        if (!pmFPAviewWriteObjects (view, file, config)) {
-            psError(PS_ERR_IO, false, "Failed to write object %s", file->filename);
-            return false;
-        }
-
-        break;
-
-    case PM_FPA_FILE_PSF:
-        pmFPAviewWritePSFmodel (view, file, config);
-        psTrace ("psModules.camera", 5, "wrote PSF %s (fpa: %p)\n", file->filename, file->fpa);
-        break;
-
-    case PM_FPA_FILE_JPEG:
-        pmFPAviewWriteJPEG (view, file, config);
-        psTrace ("psModules.camera", 5, "wrote JPEG %s (fpa: %p)\n", file->filename, file->fpa);
-        break;
-
-    case PM_FPA_FILE_KAPA:
-        pmFPAviewWriteSourcePlot (view, file, config);
-        psTrace ("psModules.camera", 5, "wrote KAPA %s (fpa: %p)\n", file->filename, file->fpa);
-        break;
-
-    default:
-        fprintf (stderr, "warning: type mismatch\n");
-        return false;
-    }
-    return true;
-}
-
-// create the data elements (headers, images) appropriate for this view
-bool pmFPAfileCreate (pmFPAfile *file, const pmFPAview *view, const pmConfig *config)
-{
-    PS_ASSERT_PTR_NON_NULL(file, false);
-    PS_ASSERT_PTR_NON_NULL(view, false);
-
-    // these are not error conditions; these are state tests
-    if (file->state & PM_FPA_STATE_INACTIVE) {
-        psTrace("psModules.camera", 6, "skip create for inactive file %s", file->name);
-        return true;
-    }
-    if (file->mode != PM_FPA_MODE_WRITE) {
-        psTrace("psModules.camera", 6, "skip create for non-write file %s", file->name);
-        return true;
-    }
-
-    // an internal file should not be returned to here
-    if (file->mode == PM_FPA_MODE_INTERNAL) {
-        psError(PS_ERR_IO, true, "File is mode PM_FPA_MODE_INTERNAL");
-        return false;
-    }
-
-    // get the current level
-    pmFPALevel level = pmFPAviewLevel (view);
-
-    // don't create the file if the src (FPA) is not defined
-    if (file->src == NULL) {
-        psTrace("psModules.camera", 6, "skip create for FPA without src FPA for %s", file->name);
-        return true;
-    }
-
-    // do we need to write this file?
-    if (level != file->fileLevel || file->mosaicLevel != PM_FPA_LEVEL_NONE) {
-        psTrace("psModules.camera", 6, "skip creation of %s at this level %s: fileLevel is %s",
-                file->name, pmFPALevelToName(level), pmFPALevelToName(file->fileLevel));
-        return true;
-    }
-
-    switch (file->type) {
-    case PM_FPA_FILE_IMAGE:
-    case PM_FPA_FILE_MASK:
-    case PM_FPA_FILE_WEIGHT:
-    case PM_FPA_FILE_FRINGE: {
-            // create FPA structure component based on view
-            psMetadata *format = file->format; // Camera format configuration
-            if (!format) {
-                format = config->format;
-            }
-
-            pmFPA *nameSource = file->src; // Source of FPA.NAME
-            if (!nameSource) {
-                nameSource = file->fpa;
-            }
-            bool mdok;                  // Status of MD lookup
-            const char *fpaname = psMetadataLookupStr(&mdok, nameSource->concepts, "FPA.NAME"); // Name of FPA
-
-            pmFPAAddSourceFromView(file->fpa, fpaname, view, format);
-            psTrace ("psModules.camera", 5, "created fpa data elements for %s (fpa: %p)\n", file->name, file->fpa);
-            break;
-    }
-    case PM_FPA_FILE_HEADER:
-      psAbort ("Create not defined for HEADER");
-      break;
-    case PM_FPA_FILE_SX:
-    case PM_FPA_FILE_RAW:
-    case PM_FPA_FILE_OBJ:
-    case PM_FPA_FILE_CMP:
-    case PM_FPA_FILE_CMF:
-    case PM_FPA_FILE_PSF:
-    case PM_FPA_FILE_JPEG:
-    case PM_FPA_FILE_KAPA:
-        break;
-
-    default:
-        psError(PS_ERR_IO, true, "Unsupported type for %s: %d", file->name, file->type);
-        return false;
-    }
-    return true;
-}
-
-bool pmFPAfileClose (pmFPAfile *file, const pmFPAview *view)
-{
-    PS_ASSERT_PTR_NON_NULL(file, false);
-    PS_ASSERT_PTR_NON_NULL(view, false);
-
-    if (file->state & PM_FPA_STATE_INACTIVE) {
-        psTrace("psModules.camera", 6, "skip close for %s, files is inactive", file->name);
-        return true;
-    }
-    if (file->state == PM_FPA_STATE_CLOSED) {
-        return true;
-    }
-
-    // an internal file should not be returned to here
-    if (file->mode == PM_FPA_MODE_INTERNAL) {
-        psError(PS_ERR_IO, true, "File is mode PM_FPA_MODE_INTERNAL");
-        return false;
-    }
-
-    // is current level == open level?
-    pmFPALevel level = pmFPAviewLevel (view);
-    if (file->fileLevel != level) {
-        psTrace("psModules.camera", 6, "skip closing of %s at this level %s: dataLevel is %s",
-                file->name, pmFPALevelToName(level), pmFPALevelToName(file->dataLevel));
-        return true;
-    }
-
-    // check if we are actually open
-    switch (file->type) {
-        // check the FITS types
-    case PM_FPA_FILE_IMAGE:
-    case PM_FPA_FILE_MASK:
-    case PM_FPA_FILE_WEIGHT:
-    case PM_FPA_FILE_HEADER:
-    case PM_FPA_FILE_FRINGE:
-    case PM_FPA_FILE_CMF:
-        psFitsClose (file->fits);
-        psTrace ("psModules.camera", 5, "closing %s (type: %d)\n", file->filename, file->type);
-        file->fits = NULL;
-        file->phu = NULL;
-        file->header = NULL;
-        file->state = PM_FPA_STATE_CLOSED;
-        break;
-
-        // ignore the TEXT types
-    case PM_FPA_FILE_SX:
-    case PM_FPA_FILE_RAW:
-    case PM_FPA_FILE_OBJ:
-    case PM_FPA_FILE_CMP:
-    case PM_FPA_FILE_PSF:
-    case PM_FPA_FILE_JPEG:
-    case PM_FPA_FILE_KAPA:
-        break;
-
-    default:
-        psError(PS_ERR_IO, true, "type mismatch: %d", file->type);
-        return false;
-    }
-    return true;
-}
-
-// set the state of the specified pmFPAfile to active (state == true) or inactive
-// if name is NULL, set the state for all pmFPAfiles
-bool pmFPAfileActivate (psMetadata *files, bool state, char *name)
-{
-    PS_ASSERT_PTR_NON_NULL(files, false);
-
-    if (!name) {
-        psMetadataItem *item = NULL;
-        psMetadataIterator *iter = psMetadataIteratorAlloc (files, PS_LIST_HEAD, NULL);
-        while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
-            pmFPAfile *file = item->data.V;
-            if (state) {
-                file->state &= PS_NOT_U8(PM_FPA_STATE_INACTIVE);
-            } else {
-                file->state |= PM_FPA_STATE_INACTIVE;
-            }
-        }
-        psFree (iter);
-        return true;
-    }
-
-    bool status = false;
-    pmFPAfile *file = psMetadataLookupPtr (&status, files, name);
-    if (!status) {
-        psTrace("psModules.camera", 6, "%s is not a defined IO file", name);
-        return false;
-    }
-    if (!file) {
-        psError(PS_ERR_IO, true, "file %s is NULL", name);
-        return false;
-    }
-    if (state) {
-        file->state &= PS_NOT_U8(PM_FPA_STATE_INACTIVE);
-    } else {
-        file->state |= PM_FPA_STATE_INACTIVE;
-    }
-    return true;
-}
-
-// attempt create, read, write, close, or free pmFPAfiles available in files
-// files are automatically opened before they are read
-bool pmFPAfileIOChecks (pmConfig *config, const pmFPAview *view, pmFPAfilePlace place)
-{
-    PS_ASSERT_PTR_NON_NULL(config, false);
-    PS_ASSERT_PTR_NON_NULL(config->files, false);
-    PS_ASSERT_PTR_NON_NULL(view, false);
-
-    psMetadata *files = config->files;
-
-    // attempt to perform all create, read, write, close operations
-    psMetadataItem *item = NULL;
-    psMetadataIterator *iter = psMetadataIteratorAlloc (files, PS_LIST_HEAD, NULL);
-    while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
-        pmFPAfile *file = item->data.V;
-
-        switch (place) {
-        case PM_FPA_BEFORE:
-# if (0)
-            if (!pmFPAfileOpen(file, view, config)) {
-                psError(PS_ERR_IO, false, "failed OPEN in FPA_BEFORE block for %s", file->name);
-                goto failure;
-            }
-# endif
-            if (!pmFPAfileRead (file, view, config)) {
-                psError(PS_ERR_IO, false, "failed READ in FPA_BEFORE block for %s", file->name);
-                goto failure;
-            }
-            if (!pmFPAfileCreate(file, view, config)) {
-                psError(PS_ERR_IO, false, "failed CREATE in FPA_BEFORE block for %s", file->name);
-                goto failure;
-            }
-# if (0)
-            if (!pmFPAfileBlank(file, view, config)) {
-                psError(PS_ERR_IO, false, "failed BLANK in FPA_BEFORE block for %s", file->name);
-                goto failure;
-            }
-# endif
-            break;
-        case PM_FPA_AFTER:
-            if (!pmFPAfileWrite (file, view, config)) {
-                psError(PS_ERR_IO, false, "failed WRITE in FPA_AFTER block for %s", file->name);
-                goto failure;
-            }
-            if (!pmFPAfileClose(file, view)) {
-                psError(PS_ERR_IO, false, "failed CLOSE in FPA_AFTER block for %s", file->name);
-                goto failure;
-            }
-            break;
-        default:
-            psAbort("You can't get here");
-        }
-    }
-
-    // attempt to free data that is no longer needed
-    psMetadataIteratorSet (iter, PS_LIST_HEAD);
-    while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
-        pmFPAfile *file = item->data.V;
-
-        switch (place) {
-        case PM_FPA_BEFORE:
-            break;
-        case PM_FPA_AFTER:
-            if (!pmFPAfileFreeData(file, view)) {
-                if (!psMetadataRemoveKey(files, file->name)) {
-                    psError(PS_ERR_IO, false, "failed to remove %s in FPA_AFTER block", file->name);
-                    goto failure;
-                }
-            }
-            break;
-        default:
-            psAbort("You can't get here");
-        }
-    }
-    psFree (iter);
-    return true;
-
-failure:
-    psFree (iter);
-    return false;
 }
 
@@ -828,102 +746,98 @@
     PS_ASSERT_PTR_NON_NULL(view, false);
 
-    // XXX we need to test IF we need to write out a PHU blank
-    // is this function performed by the pmFPAWrite,etc functions?
-
+    bool status = true;
     switch (file->type) {
-    case PM_FPA_FILE_IMAGE:
-    case PM_FPA_FILE_MASK:
-    case PM_FPA_FILE_WEIGHT:
-    case PM_FPA_FILE_FRINGE:
-    if (file->mode == PM_FPA_MODE_WRITE) {
-        // Want to write out any potential blank
-        pmFPA *fpa = pmFPAfileSuitableFPA(file, view, config); // FPA, ensuring it's ready to write a blank
-
-        switch (file->fileLevel) {
-        case PM_FPA_LEVEL_FPA:
-            pmFPAWrite(fpa, file->fits, NULL, true, false);
-            break;
-        case PM_FPA_LEVEL_CHIP: {
-                pmChip *chip = pmFPAviewThisChip(view, fpa);
-                pmChipWrite(chip, file->fits, NULL, true, false);
-                break;
+      case PM_FPA_FILE_IMAGE:
+      case PM_FPA_FILE_MASK:
+      case PM_FPA_FILE_WEIGHT:
+      case PM_FPA_FILE_FRINGE:
+	if (file->mode == PM_FPA_MODE_WRITE) {
+	    // Want to write out any potential blank
+	    // XXX why do we need to construct a new fpa?? 
+	    pmFPA *fpa = pmFPAfileSuitableFPA(file, view, config); // FPA, ensuring it's ready to write a blank
+
+	    switch (file->fileLevel) {
+	      case PM_FPA_LEVEL_FPA:
+		if (file->fpa->wrote_phu) break;
+		status = pmFPAWrite(fpa, file->fits, NULL, true, false);
+		file->fpa->wrote_phu = true;
+		break;
+	      case PM_FPA_LEVEL_CHIP: {
+		  pmChip *chip = pmFPAviewThisChip(view, fpa);
+		  if (chip->wrote_phu) break;
+		  status = pmChipWrite(chip, file->fits, NULL, true, false);
+		  chip->wrote_phu = true;
+		  break;
+	      }
+	      case PM_FPA_LEVEL_CELL: {
+		  pmCell *cell = pmFPAviewThisCell(view, fpa);
+		  if (cell->wrote_phu) break;
+		  status = pmCellWrite(cell, file->fits, NULL, true);
+		  cell->wrote_phu = true;
+		  break;
+	      }
+	      default:
+		psAbort("fileLevel not correctly set");
+		break;
+	    }
+
+	    psFree(fpa);
+	}
+      case PM_FPA_FILE_SX:
+      case PM_FPA_FILE_RAW:
+      case PM_FPA_FILE_OBJ:
+      case PM_FPA_FILE_CMP:
+      case PM_FPA_FILE_CMF:
+      case PM_FPA_FILE_PSF:
+      case PM_FPA_FILE_JPEG:
+      case PM_FPA_FILE_KAPA:
+	break;
+      default:
+        fprintf (stderr, "warning: type mismatch\n");
+        return false;
+    }
+    if (!status) {
+	psError(PS_ERR_UNKNOWN, false, "failed to write PHU for %s (%s)\n", file->filename, file->name);
+	return false;
+    }
+    return true;
+}
+
+// set the state of the specified pmFPAfile to active (state == true) or inactive
+// if name is NULL, set the state for all pmFPAfiles
+bool pmFPAfileActivate (psMetadata *files, bool state, char *name)
+{
+    PS_ASSERT_PTR_NON_NULL(files, false);
+
+    if (!name) {
+        psMetadataItem *item = NULL;
+        psMetadataIterator *iter = psMetadataIteratorAlloc (files, PS_LIST_HEAD, NULL);
+        while ((item = psMetadataGetAndIncrement (iter)) != NULL) {
+            pmFPAfile *file = item->data.V;
+            if (state) {
+                file->state &= PS_NOT_U8(PM_FPA_STATE_INACTIVE);
+            } else {
+                file->state |= PM_FPA_STATE_INACTIVE;
             }
-        case PM_FPA_LEVEL_CELL: {
-                pmCell *cell = pmFPAviewThisCell(view, fpa);
-                pmCellWrite(cell, file->fits, NULL, true);
-                break;
-            }
-        default:
-            psAbort("fileLevel not correctly set");
-            break;
-        }
-
-        psFree(fpa);
-    }
-    case PM_FPA_FILE_SX:
-    case PM_FPA_FILE_RAW:
-    case PM_FPA_FILE_OBJ:
-    case PM_FPA_FILE_CMP:
-    case PM_FPA_FILE_CMF:
-    case PM_FPA_FILE_PSF:
-    case PM_FPA_FILE_JPEG:
-    case PM_FPA_FILE_KAPA:
-      break;
-    default:
-        fprintf (stderr, "warning: type mismatch\n");
-        return false;
-    }
-    return true;
-}
-
-# if (0)
-
-//XXX from pmFPAfileOpen (Image section)
-        psTrace ("psModules.camera", 5, "opening %s (type: %d)\n", file->filename, file->type);
-        if (!openImage(file, view, mode, config)) {
-            psError(PS_ERR_UNKNOWN, false, "Unable to open image %s (type %d)\n", file->filename, file->type);
-            return false;
-        }
-        break;
-        // open the FITS object files
-/////
-
-
-// Open a file that contains an image
-static bool openImage(pmFPAfile *file,  // File to open
-                      const pmFPAview *view, // View pointing to open level
-                      const char *mode,  // Open mode (for psFitsOpen)
-                      pmConfig *config  // Configuration
-                     )
-{
-    bool status;
-
-    file->fits = psFitsOpen (file->filename, mode);
-    if (file->fits == NULL) {
-        psError(PS_ERR_IO, false, "error opening file %s\n", file->filename);
-        return false;
-    }
-    file->state = PM_FPA_STATE_OPEN;
-    
-    // if needed, set the optional EXTWORD field based on the camera value
-    if (config && config->format) {
-	psMetadata *fileMenu = psMetadataLookupMetadata (NULL, config->format, "FILE");
-	if (!fileMenu) {
-	    psError (PS_ERR_IO, true, "FILE METADATA missing from camera format %s\n", config->formatName);
-	    return false;
-	}
-	char *extword = psMetadataLookupStr (&status, fileMenu, "EXTWORD");
-	if (status) {
-	    psFitsSetExtnameWord (file->fits, extword);
-	}
-    }
-
-    // In some cases, we need to read the PHU after we've opened the file.  This happens for
-    // the images supplied by the detrend database, which are only identified here (above).
-    if (!pmFPAfileReadPHU (file, view, config)) {
-	psError (PS_ERR_IO, true, "error reading PHU for %s (%s)\n", file->filename, file->name);
-	return false;
-    }
-    return true;
-}
-# endif
+        }
+        psFree (iter);
+        return true;
+    }
+
+    bool status = false;
+    pmFPAfile *file = psMetadataLookupPtr (&status, files, name);
+    if (!status) {
+        psTrace("psModules.camera", 6, "%s is not a defined IO file", name);
+        return false;
+    }
+    if (!file) {
+        psError(PS_ERR_IO, true, "file %s is NULL", name);
+        return false;
+    }
+    if (state) {
+        file->state &= PS_NOT_U8(PM_FPA_STATE_INACTIVE);
+    } else {
+        file->state |= PM_FPA_STATE_INACTIVE;
+    }
+    return true;
+}
