Index: /trunk/psModules/src/camera/pmFPAfileIO.c
===================================================================
--- /trunk/psModules/src/camera/pmFPAfileIO.c	(revision 12584)
+++ /trunk/psModules/src/camera/pmFPAfileIO.c	(revision 12585)
@@ -17,4 +17,5 @@
 #include "pmFPARead.h"
 #include "pmFPAWrite.h"
+#include "pmFPAfileIO.h"
 #include "pmFPAfileFitsIO.h"
 #include "pmPeaks.h"
@@ -30,129 +31,5 @@
 #include "pmDetrendDB.h"
 
-// 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, I need to call pmFPAAddSourceFromHeader after I've opened the file,
-    // specifically if I have not called this function on startup.  This happens for the
-    // images supplied by the detrend database, which are only identified here (above).
-    // this is never true for the output images, which are constructed later
-
-    if (file->mode == PM_FPA_MODE_READ) {
-        bool addSource = false;
-        switch (file->fileLevel) {
-        case PM_FPA_LEVEL_FPA:
-            addSource = !file->fpa->hdu;
-            break;
-        case PM_FPA_LEVEL_CHIP: {
-                pmChip *chip = pmFPAviewThisChip(view, file->fpa);
-                if (!chip) {
-                    psError (PS_ERR_IO, true, "inconsistent file/fpa: fileLevel is CHIP, view is FPA");
-                    return false;
-                }
-                addSource = !chip->hdu;
-                break;
-            }
-        case PM_FPA_LEVEL_CELL: {
-                pmCell *cell = pmFPAviewThisCell(view, file->fpa);
-                if (!cell) {
-                    psError (PS_ERR_IO, true, "inconsistent file/fpa: fileLevel is CELL, view is FPA");
-                    return false;
-                }
-                addSource = !cell->hdu;
-                break;
-            }
-        default:
-            psAbort("fileLevel not correctly set");
-            break;
-        }
-
-        if (addSource) {
-            psMetadata *phu = psFitsReadHeader (NULL, file->fits);
-            if (!file->format) {
-                file->format = pmConfigCameraFormatFromHeader (config, phu);
-                if (!file->format) {
-                    psError(PS_ERR_IO, false, "Failed to read CCD format from %s\n", file->filename);
-                    psFree(phu);
-                    return NULL;
-                }
-            } else {
-                bool valid;
-                if (!pmConfigValidateCameraFormat (&valid, file->format, phu)) {
-                    psError (PS_ERR_UNKNOWN, false, "Error in config scripts\n");
-                    psFree (phu);
-                    return NULL;
-                }
-                if (!valid) {
-                    psError(PS_ERR_IO, false, "file %s is not from the required camera", file->filename);
-                    psFree (phu);
-                    return NULL;
-                }
-            }
-            pmFPAview *thisView = pmFPAAddSourceFromHeader (file->fpa, phu, file->format);
-            psFree (thisView);
-            psFree (phu);
-            // XXX we can check the output view to be sure it corresponds to our current view
-        }
-    }
-#if 0
-    // XXXX can we now drop this?  (EAM 2007.03.15)
-    // This should be done by pmFPAfileBlank
-    if (file->mode == PM_FPA_MODE_WRITE) {
-        // Want to write out any potential blank
-        pmFPA *fpa = pmFPAfileSuitableFPA(file, view, config);
-
-        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_LEVEL_CELL: {
-                pmCell *cell = pmFPAviewThisCell(view, fpa);
-                pmCellWrite(cell, file->fits, NULL, true);
-                break;
-            }
-        default:
-            psAbort("fileLevel not correctly set");
-            break;
-        }
-
-        psFree(fpa);
-    }
-#endif
-    return true;
-
-}
-
-
+// XXXX should we require this function to be called only within pmFPAfileRead or pmFPAfileWrite?
 // open file (if not already opened)
 bool pmFPAfileOpen (pmFPAfile *file, const pmFPAview *view, pmConfig *config)
@@ -175,14 +52,5 @@
     }
 
-    // get the current level
-    pmFPALevel level = pmFPAviewLevel (view);
-
-    // do we need to open this file?
-    if (level != file->fileLevel) {
-        psTrace("psModules.camera", 6, "skip open of %s at this level %s: fileLevel is %s",
-                file->name, pmFPALevelToName(level), pmFPALevelToName(file->fileLevel));
-        return true;
-    }
-
+    // XXX are these programming errors?
     if (file->mode == PM_FPA_MODE_NONE) {
         psError(PS_ERR_IO, true, "File is mode PM_FPA_MODE_NONE");
@@ -199,5 +67,4 @@
         mode = writeMode;
     }
-
     if ((file->mode == PM_FPA_MODE_WRITE) && !file->save) {
         psTrace("psModules.camera", 6, "skip open for %s, output file not requested", file->name);
@@ -281,5 +148,5 @@
 
     switch (file->type) {
-      // open the FITS types:
+	// open the FITS types:
       case PM_FPA_FILE_IMAGE:
       case PM_FPA_FILE_MASK:
@@ -287,11 +154,4 @@
       case PM_FPA_FILE_HEADER:
       case PM_FPA_FILE_FRINGE:
-        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
       case PM_FPA_FILE_CMF:
         psTrace ("psModules.camera", 5, "opening %s (type: %d)\n", file->filename, file->type);
@@ -315,7 +175,14 @@
 	    }
 	}
-        break;
-
-      // defer opening TEXT types:
+
+	// 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;
+	}
+        break;
+
+	// defer opening TEXT types:
       case PM_FPA_FILE_SX:
       case PM_FPA_FILE_OBJ:
@@ -340,4 +207,11 @@
     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, files is inactive", file->name);
@@ -350,22 +224,8 @@
     }
 
-    // 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);
 
-    // do we need to open this file?
-    if (level == file->fileLevel) {
-        if (!pmFPAfileOpen (file, view, config)) {
-            psError(PS_ERR_IO, false, "failed to open file %s", file->name);
-            return false;
-        }
-    }
-
-    // do we need to read this file?
+    // 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",
@@ -374,78 +234,71 @@
     }
 
+    // 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) {
-        file->fileLevel = level;
-        if (!pmFPAfileOpen (file, view, config)) {
-            psError(PS_ERR_IO, false, "failed to open file %s when attempting to read", file->name);
-            return false;
-        }
-    }
-
+	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:
-        if (!pmFPAviewReadFitsImage(view, file)) {
-            psError(PS_ERR_UNKNOWN, false, "skipping %s (type: %d)\n", file->filename, file->type);
-            return false;
-        }
-        psTrace ("psModules.camera", 5, "reading %s (type: %d)\n", file->filename, file->type);
-        break;
-    case PM_FPA_FILE_MASK:
-        if (!pmFPAviewReadFitsMask(view, file)) {
-            psError(PS_ERR_UNKNOWN, false, "skipping %s (type: %d)\n", file->filename, file->type);
-            return false;
-        }
-        psTrace ("psModules.camera", 5, "reading %s (type: %d)\n", file->filename, file->type);
-        break;
-    case PM_FPA_FILE_WEIGHT:
-        if (!pmFPAviewReadFitsWeight(view, file)) {
-            psError(PS_ERR_UNKNOWN, false, "skipping %s (type: %d)\n", file->filename, file->type);
-            return false;
-        }
-        psTrace ("psModules.camera", 5, "reading %s (type: %d)\n", file->filename, file->type);
-        break;
-    case PM_FPA_FILE_HEADER:
-        if (!pmFPAviewReadFitsHeaderSet(view, file)) {
-            psError(PS_ERR_UNKNOWN, false, "skipping %s (type: %d)\n", file->filename, file->type);
-            return false;
-        }
-        psTrace ("psModules.camera", 5, "reading %s (type: %d)\n", file->filename, file->type);
-        break;
-    case PM_FPA_FILE_FRINGE:
-        if (!pmFPAviewReadFitsImage (view, file)) {
-            psError(PS_ERR_UNKNOWN, false, "skipping %s (type: %d)\n", file->filename, file->type);
-            return false;
-        }
-        psTrace ("psModules.camera", 5, "reading %s (type: %d)\n", file->filename, file->type);
-
-        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:
-        pmFPAviewReadObjects (view, file, config);
-        psTrace ("psModules.camera", 5, "reading %s (type: %d)\n", file->filename, file->type);
-        break;
-
-    case PM_FPA_FILE_PSF:
-        pmFPAviewReadPSFmodel (view, file, config);
-        psTrace ("psModules.camera", 5, "reading %s (type: %d)\n", file->filename, file->type);
-        break;
-
-    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;
-    }
+      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;
 }
@@ -461,5 +314,5 @@
     }
 
-    // an internal file should not be returned to here
+    // 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");
@@ -470,5 +323,5 @@
     pmFPALevel level = pmFPAviewLevel (view);
 
-    // do we need to read this file?
+    // 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",
@@ -484,10 +337,10 @@
     case PM_FPA_FILE_FRINGE:
         if (pmFPAviewFreeData(view, file)) {
-            psTrace ("psModules.camera", 5, "freed %s for %s (type: %d)\n", file->filename, file->name, file->type);
+            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 (type: %d)\n", file->filename, file->type);
+            psError(PS_ERR_UNKNOWN, false, "skipping %s (%s)\n", file->filename, file->name);
             return false;
         }
@@ -499,5 +352,5 @@
     case PM_FPA_FILE_CMF:
         // pmFPAviewFreeObjects (view, file);
-        psTrace ("psModules.camera", 5, "NOT freeing %s (type: %d)\n", file->filename, file->type);
+        psTrace ("psModules.camera", 5, "NOT freeing %s (%s)\n", file->filename, file->name);
         break;
 
@@ -515,5 +368,5 @@
 }
 
-bool pmFPAfileBlank(pmFPAfile *file, const pmFPAview *view, pmConfig *config)
+bool pmFPAfileWrite(pmFPAfile *file, const pmFPAview *view, pmConfig *config)
 {
     PS_ASSERT_PTR_NON_NULL(file, false);
@@ -521,10 +374,10 @@
 
     if (file->state & PM_FPA_STATE_INACTIVE) {
-        psTrace("psModules.camera", 6, "skip blank for %s, files is inactive", file->name);
+        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 blank for %s, mode is not WRITE", file->name);
+        psTrace("psModules.camera", 6, "skip write for %s, mode is not WRITE", file->name);
         return true;
     }
@@ -537,5 +390,5 @@
 
     if (!file->save) {
-        psTrace("psModules.camera", 6, "skip blank for %s, save is FALSE", file->name);
+        psTrace("psModules.camera", 6, "skip write for %s, save is FALSE", file->name);
         return true;
     }
@@ -544,95 +397,7 @@
     pmFPALevel level = pmFPAviewLevel (view);
 
-    if (level != file->fileLevel) {
-        psTrace("psModules.camera", 6, "skip blank for %s, level is %s", file->name,
-                pmFPALevelToName(file->freeLevel));
-        return true;
-    }
-
-    // do we need to open this file?
-    if (!pmFPAfileOpen (file, view, config)) {
-        psError(PS_ERR_IO, false, "failed to open %s", file->filename);
-        return false;
-    }
-
-    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_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;
-}
-
-
-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
+	(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));
@@ -641,7 +406,9 @@
 
     // 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))) {
+	(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);
@@ -649,5 +416,28 @@
         }
     }
-
+# 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:
@@ -908,8 +698,10 @@
         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);
@@ -920,8 +712,10 @@
                 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:
@@ -968,2 +762,168 @@
 }
 
+// for this file and view, if we need to read a PHU, read it.  return true for any non-error
+// condition. this function should be called by pmFPAfileOpen.
+bool pmFPAfileReadPHU (pmFPAfile *file, const pmFPAview *view, pmConfig *config)
+{
+    // required conditions
+    if (file->mode != PM_FPA_MODE_READ) return true;
+    if (file->state != PM_FPA_STATE_OPEN) psAbort ("pmFPAfileReadPHU called on unopened file");
+    if (file->fpa == NULL) psAbort ("pmFPAfileReadPHU called on file without an FPA");
+
+    // check if we need to read a PHU (if not, return true)
+    switch (file->fileLevel) {
+      case PM_FPA_LEVEL_FPA:
+	if (file->fpa->hdu) return true;
+	break;
+      case PM_FPA_LEVEL_CHIP: {
+	  pmChip *chip = pmFPAviewThisChip(view, file->fpa);
+	  if (!chip) psAbort ("inconsistent file/fpa: fileLevel is CHIP, view is FPA");
+	  if (chip->hdu) return true;
+	  break;
+      }
+      case PM_FPA_LEVEL_CELL: {
+	  pmCell *cell = pmFPAviewThisCell(view, file->fpa);
+	  if (!cell) psAbort ("inconsistent file/fpa: fileLevel is CELL, view is FPA");
+	  if (cell->hdu) return true;
+	  break;
+      }
+      default:
+	psAbort("fileLevel not correctly set");
+	break;
+    }
+
+    // XXX do we need to advance to the first HDU?
+    psMetadata *phu = psFitsReadHeader (NULL, file->fits);
+    if (!file->format) {
+	file->format = pmConfigCameraFormatFromHeader (config, phu);
+	if (!file->format) {
+	    psError(PS_ERR_IO, false, "Failed to read CCD format from %s\n", file->filename);
+	    psFree(phu);
+	    return false;
+	}
+    } else {
+	bool valid;
+	if (!pmConfigValidateCameraFormat (&valid, file->format, phu)) {
+	    psError (PS_ERR_UNKNOWN, false, "Error in camera configuration\n");
+	    psFree (phu);
+	    return false;
+	}
+	if (!valid) {
+	    psError(PS_ERR_IO, false, "file %s is not from the required camera", file->filename);
+	    psFree (phu);
+	    return false;
+	}
+    }
+    pmFPAview *thisView = pmFPAAddSourceFromHeader (file->fpa, phu, file->format);
+    psFree (thisView);
+    psFree (phu);
+    // XXX we can check the output view to be sure it corresponds to our current view
+    return true;
+}
+
+// XXX this function is only called from pmFPAfileWrite 
+bool pmFPAfileWritePHU(pmFPAfile *file, const pmFPAview *view, pmConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(file, false);
+    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?
+
+    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_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
Index: /trunk/psModules/src/camera/pmFPAfileIO.h
===================================================================
--- /trunk/psModules/src/camera/pmFPAfileIO.h	(revision 12584)
+++ /trunk/psModules/src/camera/pmFPAfileIO.h	(revision 12585)
@@ -4,6 +4,6 @@
  * @author EAM, IfA
  *
- * @version $Revision: 1.4 $ $Name: not supported by cvs2svn $
- * @date $Date: 2007-02-15 00:51:20 $
+ * @version $Revision: 1.5 $ $Name: not supported by cvs2svn $
+ * @date $Date: 2007-03-24 17:53:55 $
  * Copyright 2004-2005 Institute for Astronomy, University of Hawaii
  */
@@ -39,4 +39,7 @@
 bool pmFPAfileIOChecks (pmConfig *config, const pmFPAview *view, pmFPAfilePlace place);
 
+bool pmFPAfileWritePHU(pmFPAfile *file, const pmFPAview *view, pmConfig *config);
+bool pmFPAfileReadPHU (pmFPAfile *file, const pmFPAview *view, pmConfig *config);
+
 /// @}
 # endif
Index: /trunk/psModules/src/camera/pmFPAview.c
===================================================================
--- /trunk/psModules/src/camera/pmFPAview.c	(revision 12584)
+++ /trunk/psModules/src/camera/pmFPAview.c	(revision 12585)
@@ -3,6 +3,6 @@
  *  @author EAM, IfA
  *
- *  @version $Revision: 1.9 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2007-02-07 23:58:17 $
+ *  @version $Revision: 1.10 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2007-03-24 17:53:55 $
  *
  *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
@@ -51,4 +51,25 @@
 }
 
+// return a view restricted to the level (must be >= the input level)
+pmFPAview *pmFPAviewForLevel(pmFPALevel level, const pmFPAview *input) 
+{
+    PS_ASSERT_PTR_NON_NULL(input, NULL);
+
+    pmFPAview *output = pmFPAviewAlloc (input->nRows);
+    *output = *input;
+
+    switch (level) {
+      case PM_FPA_LEVEL_FPA:
+	output->chip = -1;
+      case PM_FPA_LEVEL_CHIP:
+	output->cell = -1;
+      case PM_FPA_LEVEL_CELL:
+	output->readout = -1;
+	break;
+      default:
+	break;
+    }
+    return output;
+}
 
 pmFPALevel pmFPAviewLevel(const pmFPAview *view)
Index: /trunk/psModules/src/camera/pmFPAview.h
===================================================================
--- /trunk/psModules/src/camera/pmFPAview.h	(revision 12584)
+++ /trunk/psModules/src/camera/pmFPAview.h	(revision 12585)
@@ -4,6 +4,6 @@
  * @author Eugene Magnier, IfA
  *
- * @version $Revision: 1.6 $ $Name: not supported by cvs2svn $
- * @date $Date: 2007-01-24 02:54:14 $
+ * @version $Revision: 1.7 $ $Name: not supported by cvs2svn $
+ * @date $Date: 2007-03-24 17:53:55 $
  * Copyright 2005-2006 Institute for Astronomy, University of Hawaii
  */
@@ -41,4 +41,7 @@
 bool pmFPAviewReset(pmFPAview *view     ///< View to reset
                    );
+
+// return a view restricted to the level (must be >= the input level)
+pmFPAview *pmFPAviewForLevel(pmFPALevel level, const pmFPAview *input);
 
 /// Determine the current view level
