Index: /branches/eam_branch_20080706/ppImage/src/ppImageLoop.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImageLoop.c	(revision 18429)
+++ /branches/eam_branch_20080706/ppImage/src/ppImageLoop.c	(revision 18430)
@@ -62,4 +62,8 @@
                     continue;
                 }
+
+		// XXX set the options->*Mask values here (after the mask images have been loaded
+		// and before any of the value are used)
+		ppImageSetMaskBits (config, options);
 
                 // perform the detrend analysis
Index: /branches/eam_branch_20080706/ppImage/src/ppImageMetadataStats.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImageMetadataStats.c	(revision 18429)
+++ /branches/eam_branch_20080706/ppImage/src/ppImageMetadataStats.c	(revision 18430)
@@ -14,4 +14,5 @@
     }
 
+    // XXX should this be just options->maskValue?? I think so...
     psMaskType maskVal = options->satMask | options->badMask | options->maskValue;
 
Index: /branches/eam_branch_20080706/ppImage/src/ppImageMosaic.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImageMosaic.c	(revision 18429)
+++ /branches/eam_branch_20080706/ppImage/src/ppImageMosaic.c	(revision 18430)
@@ -34,4 +34,5 @@
     // XXX mosaic the chip, making a deep copy.  this has the side effect of making the
     // output image products pure trimmed images, but also increases the memory footprint.
+    // XXX I think we should be using options->maskValue
     status = pmChipMosaic(outChip, inChip, true, options->blankMask);
     return status;
Index: /branches/eam_branch_20080706/ppImage/src/ppImageOptions.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImageOptions.c	(revision 18429)
+++ /branches/eam_branch_20080706/ppImage/src/ppImageOptions.c	(revision 18430)
@@ -191,5 +191,8 @@
 
     // Mask recipe options
+    // XXX we cannot set these values here; wait until just before ppImageDetrend
     options->doMask = psMetadataLookupBool(NULL, recipe, "MASK");
+
+# if (0)    
     const char *masks = psMetadataLookupStr(&status, recipe, "MASK.VALUE");
     if (status) {
@@ -201,4 +204,5 @@
     options->blankMask = pmConfigMask("BLANK", config);
     // XXX should it be an error for these to not exist?
+# endif
 
     options->doBias = psMetadataLookupBool(NULL, recipe, "BIAS");
Index: /branches/eam_branch_20080706/ppImage/src/ppImageParseCamera.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImageParseCamera.c	(revision 18429)
+++ /branches/eam_branch_20080706/ppImage/src/ppImageParseCamera.c	(revision 18430)
@@ -20,5 +20,5 @@
     }
 
-    // if MASK or WEIGHT was supplied on command line, bind files to 'input'
+    // if MASK or WEIGHT was supplied on command line, bind files to 'input'.
     // the mask and weight will be mosaicked with the image
     pmFPAfile *inputMask = pmFPAfileBindFromArgs(&status, input, config, "PPIMAGE.INPUT.MASK", "PPIMAGE.INPUT.MASK");
@@ -27,7 +27,20 @@
         return NULL;
     }
-    if (inputMask && inputMask->type != PM_FPA_FILE_MASK) {
+    if (inputMask) {
+      if (inputMask->type != PM_FPA_FILE_MASK) {
         psError(PS_ERR_IO, true, "PPIMAGE.INPUT.MASK is not of type MASK");
         return NULL;
+      }
+      // XXX need to load the mask bit names from one of the headers
+      // this grabs the first available hdu : no guarantee that it will be valid, though
+      pmHDU *hdu = pmHDUGetFirst (inputMask->fpa);
+      if (!hdu) {
+        psError(PS_ERR_IO, true, "no valid HDU for PPIMAGE.INPUT.MASK");
+        return NULL;
+      }
+      if (!pmConfigMaskReadHeader (config, hdu->header)) {
+        psError(PS_ERR_IO, false, "error in mask bits");
+        return NULL;
+      }
     }
 
@@ -66,4 +79,5 @@
     }
     if (options->doMask) {
+
         if (!ppImageDefineFile (config, input->fpa, "PPIMAGE.MASK", "MASK", PM_FPA_FILE_MASK, PM_DETREND_TYPE_MASK)) {
             psError (PS_ERR_IO, false, "Can't find a mask image source");
@@ -71,5 +85,25 @@
             return NULL;
         }
-	// Need to read the names of bit masks from the mask header and set them in the recipe
+	// XXX have ppImageDefineFile return the pmFPAfile?
+	pmFPAfile *mask = psMetadataLookupPtr(&status, config->files, "PPIMAGE.MASK");
+	psAssert (mask, "mask not defined?  not possible!");
+
+	// Need to read the names of bit masks from the mask header and set them in the
+	// recipe.  If we are loading this from the detrend db, this action will happen
+	// when the file is resolved.
+	if (!mask->detrend) {
+	    // XXX need to load the mask bit names from one of the headers
+	    // this grabs the first available hdu : no guarantee that it will be valid, though
+	    pmHDU *hdu = pmHDUGetFirst (mask->fpa);
+	    if (!hdu) {
+		psError(PS_ERR_IO, true, "no valid HDU for PPIMAGE.INPUT.MASK");
+		return NULL;
+	    }
+	    // XXX is this consistent with the pmConfigMaskReadHeader call above?
+	    if (!pmConfigMaskReadHeader (config, hdu->header)) {
+		psError(PS_ERR_IO, false, "error in mask bits");
+		return NULL;
+	    }
+	}
     }
     if (options->doShutter) {
Index: /branches/eam_branch_20080706/ppImage/src/ppImagePixelStats.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImagePixelStats.c	(revision 18429)
+++ /branches/eam_branch_20080706/ppImage/src/ppImagePixelStats.c	(revision 18430)
@@ -10,4 +10,5 @@
     bool mdok;              // Status of MD lookup
 
+    // XXX should this be just options->maskValue?? I think so...
     psMaskType maskVal = options->satMask | options->badMask | options->maskValue;
 
Index: /branches/eam_branch_20080706/ppImage/src/ppImageReplaceBackground.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImageReplaceBackground.c	(revision 18429)
+++ /branches/eam_branch_20080706/ppImage/src/ppImageReplaceBackground.c	(revision 18430)
@@ -41,4 +41,5 @@
 
     // define the mask value to be used in ppImage
+    // XXX should this be just options->maskValue?? I think so...  (but it should certainly include flat!)
     psMaskType maskVal  = options->satMask | options->badMask | options->flatMask | options->blankMask;
 
Index: /branches/eam_branch_20080706/ppImage/src/ppImageSetMaskBits.c
===================================================================
--- /branches/eam_branch_20080706/ppImage/src/ppImageSetMaskBits.c	(revision 18430)
+++ /branches/eam_branch_20080706/ppImage/src/ppImageSetMaskBits.c	(revision 18430)
@@ -0,0 +1,37 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ppImage.h"
+
+bool ppImageSetMaskBits (pmConfig *config, ppImageOptions *options) {
+
+    // Mask recipe options
+    const char *masks = psMetadataLookupStr(&status, recipe, "MASK.VALUE");
+    if (status) {
+        options->maskValue = pmConfigMask(masks, config);
+    }
+
+    darkMask           = pmConfigMask("DARK", 	  config);
+    options->flatMask  = pmConfigMask("FLAT", 	  config);
+    options->blankMask = pmConfigMask("BLANK",	  config);
+    detectorMask       = pmConfigMask("DETECTOR", config);
+
+    options->satMask   = pmConfigMask("SAT",      config);
+    options->badMask   = pmConfigMask("BAD",      config);
+
+    rangeMask          = pmConfigMask("RANGE",    config);
+
+    crMask             = pmConfigMask("CR",       config);
+    ghostMask          = pmConfigMask("GHOST",    config);
+
+    // XXX it should be an error for these to not exist
+    if (!options->flatMask) {
+      psWarning ("FLAT MASK is not set");
+    }
+    if (!options->flatMask) {
+      psWarning ("FLAT MASK is not set");
+    }
+
+    return true;
+}
Index: /branches/eam_branch_20080706/psModules/src/camera/pmFPAfileIO.c
===================================================================
--- /branches/eam_branch_20080706/psModules/src/camera/pmFPAfileIO.c	(revision 18429)
+++ /branches/eam_branch_20080706/psModules/src/camera/pmFPAfileIO.c	(revision 18430)
@@ -792,4 +792,13 @@
           }
 
+	  // XXX if we have a mask file, then we need to read the mask bit names
+	  // defined for this file
+	  if (file->type == PM_FPA_FILE_MASK) {
+	    if (!pmConfigMaskReadHeader (config, phu)) {
+		psError(PS_ERR_IO, false, "error in mask bits");
+		return false;
+	    }
+	  }
+
           // determine the current format from the header
           // determine camera if not specified already
Index: /branches/eam_branch_20080706/psModules/src/config/pmConfigMask.c
===================================================================
--- /branches/eam_branch_20080706/psModules/src/config/pmConfigMask.c	(revision 18429)
+++ /branches/eam_branch_20080706/psModules/src/config/pmConfigMask.c	(revision 18430)
@@ -40,5 +40,6 @@
 }
 
-// replace the named masks in the recipe with values in the header
+// replace the named masks in the recipe with values in the header:
+// replace only the names in the header in the recipe
 void pmConfigMasksReadHeader (pmConfig *config, psMetadata *header) {
 
@@ -49,25 +50,29 @@
     }
 
-    int nMask = 0;
+    int nMask = psMetadataLookupS32 (&status, header, "MSKNUM");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, true, "Unable to find MSKNUM in header.");
+        return false;
+    }
 
-    psMetadataIterator *iter = psMetadataIteratorAlloc(recipe, PS_LIST_HEAD, NULL); // Iterator
+    for (int i = 0; i < nMask; i++) {
 
-    psMetadataItem *item;               // Item from iteration
-    while ((item = psMetadataGetAndIncrement(iter))) {
+	snprintf (namekey,  64, "MSKNAM%02d", i);
+	snprintf (valuekey, 64, "MSKVAL%02d", i);
 
-	if (item->type != PS_DATA_U8) {
-	    psWarning("mask recipe entry %s is not a bit value\n", item->name);
-	    continue;
+	char *name = psMetadataLookupStr (&status, header, namekey);
+	psU8 bit = psMetadataLookupU8 (&status, header, valuekey);
+
+	// XXX validate that bit is a 2^n value?
+
+	psMetadataItem *item = psMetadataLookup (header, name);
+	if (!item) {
+	  psWarning("mask recipe entry %s not in recipe\n", name);
+	  psMetadataAddU8 (recipe, PS_LIST_TAIL, name, 0, "Bitmask bit value", bit);
+	} else {
+	  item->data.U8 = bit;
 	}
-
-	snprintf (namekey,  64, "MSKNAM%02d", nMask);
-	snprintf (valuekey, 64, "MSKVAL%02d", nMask);
-
-	psMetadataAddStr (header, PS_LIST_TAIL, namekey, 0, "Bitmask bit name", item->name);
-	psMetadataAddU8 (header, PS_LIST_TAIL, valuekey, 0, "Bitmask bit value", item->data.U8);
-	nMask ++;
     }
     
-    psMetadataAddU8 (header, PS_LIST_TAIL, "MSKNUM", 0, "Bitmask bit count", nMask);
     return true;
 }
@@ -102,5 +107,5 @@
     }
     
-    psMetadataAddU8 (header, PS_LIST_TAIL, "MSKNUM", 0, "Bitmask bit count", nMask);
+    psMetadataAddS32 (header, PS_LIST_TAIL, "MSKNUM", 0, "Bitmask bit count", nMask);
     return true;
 }
