Index: trunk/psModules/src/camera/pmFPAfileDefine.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 15131)
+++ trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 15180)
@@ -8,4 +8,5 @@
 #include <pslib.h>
 
+#include "pmErrorCodes.h"
 #include "pmConfig.h"
 #include "pmDetrendDB.h"
@@ -19,4 +20,79 @@
 #include "pmFPAConstruct.h"
 
+
+// Get the file rule of interest
+// Look up the name of the set of file rules to use, get that set from the site configuration, and return the
+// appropriate rule from the set.
+static psMetadata *getFileRule(const pmConfig *config, // Configuration
+                               const psMetadata *camera, // Camera configuration of interest
+                               const char *name // Name of rule to read
+    )
+{
+    assert(config);
+    assert(config->site);
+
+    psMetadataItem *item = psMetadataLookup(camera, "FILERULES"); // Item with the file rule of interest
+    if (!item) {
+        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to find FILERULES in the camera configuration.");
+        return NULL;
+    }
+
+    psMetadata *filerules = NULL;       // File rules from the site configuration
+    switch (item->type) {
+      case PS_DATA_METADATA:
+        // It's what we're after
+        filerules = item->data.md;
+        break;
+      case PS_DATA_STRING: {
+          // It's the name of a file --- read the file, and store it for future use
+          if (!pmConfigFileRead(&filerules, item->data.str, "filerules")) {
+              psError(PM_ERR_CONFIG, false, "Trouble reading reading file rules from %s  --- "
+                      "ignored.\n", item->data.str);
+              psFree(filerules);
+              return NULL;
+          }
+
+          // Muck around under the hood to replace the filename with the metadata; don't try this at home,
+          // kids
+          item->type = PS_DATA_METADATA;
+          psFree(item->data.str);
+          item->data.md = filerules;
+          break;
+      }
+      default:
+        psError(PS_ERR_BAD_PARAMETER_TYPE, true,
+                "Unexpected type for %s (%x) in FILERULES in SITE configuration.",
+                name, item->type);
+        return NULL;
+    }
+
+    // select the name from the FILERULES
+    // check for alias name (type == STR, name is aliased name)
+    bool mdok;                          // Status of MD lookup
+    const char *realname = psMetadataLookupStr(&mdok, filerules, name); // Name of file rule to look up
+    if (!realname || strlen(realname) == 0) {
+        realname = name;
+    }
+
+    return psMetadataLookupMetadata(NULL, filerules, realname);
+}
+
+// Parse an option from a metadata, returning the appropriate integer value
+static int parseOptionInt(const psMetadata *md, // Metadata containing the option
+                          const char *name, // Option name
+                          const char *source, // Description of source, for warning messages
+                          int defaultValue // Default value
+                          )
+{
+    psMetadataItem *item = psMetadataLookup(md, name); // Item with the value of interest
+    if (!item) {
+        psWarning("Unable to find value for %s in %s --- set to %d.", name, source, defaultValue);
+        return defaultValue;
+    }
+    int value = psMetadataItemParseS32(item); // Value of interst
+    return value;
+}
+
+
 // define an input-type pmFPAfile, bind to the optional fpa if supplied
 pmFPAfile *pmFPAfileDefineInput(const pmConfig *config, pmFPA *fpa, const char *name)
@@ -30,20 +106,7 @@
     char *type;
 
-    // select the FILERULES from config->camera
-    psMetadata *filerules = psMetadataLookupPtr (&status, config->camera, "FILERULES");
-    if (filerules == NULL) {
-        psError(PS_ERR_IO, true, "Can't find FILERULES in the CAMERA configuration!");
-        return NULL;
-    }
-
-    // select the name from the FILERULES
-    // check for alias name (type == STR, name is aliased name)
-    const char *realname = psMetadataLookupStr (&status, filerules, name);
-    if (!realname || strlen(realname) == 0) {
-        realname = name;
-    }
-
-    psMetadata *data = psMetadataLookupPtr (&status, filerules, realname);
-    if (data == NULL) {
+    const psMetadata *camera = (fpa ? fpa->camera : config->camera); // Camera configuration for this file
+    psMetadata *data = getFileRule(config, camera, name); // File rule
+    if (!data) {
         psError(PS_ERR_IO, true, "Can't find file rule %s!", name);
         return NULL;
@@ -76,7 +139,10 @@
     file->freeLevel = file->dataLevel;
 
-    if (fpa != NULL) {
+    if (fpa) {
         file->fpa = psMemIncrRefCounter(fpa);
         file->camera = psMemIncrRefCounter((psMetadata *)fpa->camera);
+        file->cameraName = psMemIncrRefCounter(config->cameraName); // XXX Is this the correct thing to do?
+    } else {
+        file->camera = psMemIncrRefCounter(config->camera);
         file->cameraName = psMemIncrRefCounter(config->cameraName);
     }
@@ -103,42 +169,4 @@
 {
     bool status;
-
-    // select the FILERULES from the camera config
-    psMetadata *filerules = psMetadataLookupPtr(&status, config->camera, "FILERULES");
-    if (filerules == NULL) {
-        psError(PS_ERR_IO, true, "Can't find FILERULES in the CAMERA configuration!");
-        return NULL;
-    }
-
-    // select the name from the FILERULES
-    // check for alias name (type == STR, name is aliased name)
-    const char *realname = psMetadataLookupStr(&status, filerules, name);
-    if (!realname || strlen(realname) == 0) {
-        realname = name;
-    }
-
-    psMetadata *data = psMetadataLookupPtr (&status, filerules, realname);
-    if (data == NULL) {
-        psError(PS_ERR_IO, true, "Can't find file rule %s!", name);
-        return NULL;
-    }
-
-    pmFPAfile *file = pmFPAfileAlloc();
-
-    // save the name of this pmFPAfile
-    file->name = psStringCopy(name);
-
-    file->filerule = psMemIncrRefCounter(psMetadataLookupStr(&status, data, "FILENAME.RULE"));
-
-    const char *type = psMetadataLookupStr(&status, data, "FILE.TYPE");
-    file->type = pmFPAfileTypeFromString(type);
-    if (file->type == PM_FPA_FILE_NONE) {
-        psError(PS_ERR_IO, true, "FILE.TYPE is not defined for %s\n", name);
-        psFree(file);
-        return NULL;
-    }
-
-    file->mode = PM_FPA_MODE_WRITE;
-    file->save = false;
 
     // Use the camera we were told to, the camera of the provided FPA, or default to the default camera
@@ -169,4 +197,56 @@
         }
     }
+
+    psMetadata *data = getFileRule(config, camera, name); // File rule
+    if (!data) {
+        psError(PS_ERR_IO, true, "Can't find file rule %s!", name);
+        return NULL;
+    }
+
+    pmFPAfile *file = pmFPAfileAlloc();
+
+    // save the name of this pmFPAfile
+    file->name = psStringCopy(name);
+
+    file->filerule = psMemIncrRefCounter(psMetadataLookupStr(&status, data, "FILENAME.RULE"));
+
+    const char *type = psMetadataLookupStr(&status, data, "FILE.TYPE");
+    file->type = pmFPAfileTypeFromString(type);
+    if (file->type == PM_FPA_FILE_NONE) {
+        psError(PS_ERR_IO, true, "FILE.TYPE is not defined for %s\n", name);
+        psFree(file);
+        return NULL;
+    }
+
+    file->mode = PM_FPA_MODE_WRITE;
+    file->save = false;
+
+    // Use the camera we were told to, the camera of the provided FPA, or default to the default camera
+    psMetadata *camera;                 // Camera configuration
+    if (!cameraName || strlen(cameraName) == 0) {
+        if (fpa && fpa->camera) {
+            camera = (psMetadata*)fpa->camera; // Casting away const, so I can put it in the file
+        } else {
+            camera = config->camera;
+            cameraName = config->cameraName;
+        }
+    } else {
+        bool mdok;                      // Status of MD lookup
+        psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->site, "CAMERAS"); // Known cameras
+        if (!mdok || !cameras) {
+            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the site configuration.\n");
+            return NULL;
+        }
+        camera = psMetadataLookupMetadata(&mdok, cameras, cameraName); // Camera configuration of interest
+        if (!mdok || !camera) {
+            psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find automatically generated "
+                    "camera configuration %s in site configuration.\n", cameraName);
+            return NULL;
+        }
+
+        if (fpa && fpa->camera && fpa->camera != camera) {
+            psAbort("Camera of bound FPA is not the requested camera --- there is an inconsistency!");
+        }
+    }
     file->camera = psMemIncrRefCounter(camera);
     file->cameraName = psMemIncrRefCounter(cameraName);
@@ -175,10 +255,10 @@
     # if (0)
     if (cameraName) {
-	if (!strcmp(cameraName + strlen(cameraName) - 5, "-CHIP")) {
-	    file->mosaicLevel = PM_FPA_LEVEL_CHIP;
-	}
-	if (!strcmp(cameraName + strlen(cameraName) - 5, "-FPA")) {
-	    file->mosaicLevel = PM_FPA_LEVEL_FPA;
-	}
+        if (!strcmp(cameraName + strlen(cameraName) - 5, "-CHIP")) {
+            file->mosaicLevel = PM_FPA_LEVEL_CHIP;
+        }
+        if (!strcmp(cameraName + strlen(cameraName) - 5, "-FPA")) {
+            file->mosaicLevel = PM_FPA_LEVEL_FPA;
+        }
     }
     # endif
@@ -209,4 +289,42 @@
         file->fpa = pmFPAConstruct(file->camera);
     }
+
+    // Get FITS output scheme
+    const char *fitsType = psMetadataLookupStr(&status, data, "FITS.TYPE"); // Name of FITS scheme to use
+    if (fitsType && strcasecmp(fitsType, "NONE") != 0) {
+        psMetadata *fitsTypes = psMetadataLookupMetadata(&status, camera, "FITS"); // The FITS schemes
+        if (!fitsTypes) {
+            psWarning("Unable to find FITS in camera configuration --- compression disabled.");
+            goto COMPRESSION_DONE;
+        }
+        psMetadata *scheme = psMetadataLookupMetadata(NULL, fitsTypes, fitsType); // FITS scheme
+        if (!scheme) {
+            psWarning("Unable to find %s in FITS in camera configuration --- compression disabled.",
+                      fitsType);
+            goto COMPRESSION_DONE;
+        }
+        const char *typeString = psMetadataLookupStr(NULL, scheme, "COMPRESSION"); // Compression type
+        if (!typeString || strlen(typeString) == 0) {
+            psWarning("Can't find COMPRESSION in FITS scheme %s --- compression disabled.", fitsType);
+            goto COMPRESSION_DONE;
+        }
+        psFitsCompressionType type = psFitsCompressionTypeFromString(typeString); // Compression type enum
+
+        psString source = NULL;         // Source of options
+        psStringAppend(&source, "%s in FITS in camera %s", fitsType, cameraName);
+        psVector *tile = psVectorAlloc(3, PS_TYPE_S32); // Tile sizes
+        file->bitpix = parseOptionInt(scheme, "BITPIX", source, 0); // Bits per pixel
+        tile->data.S32[0] = parseOptionInt(scheme, "TILE.X", source, 0); // Tiling in x
+        tile->data.S32[1] = parseOptionInt(scheme, "TILE.Y", source, 1); // Tiling in y
+        tile->data.S32[2] = parseOptionInt(scheme, "TILE.Z", source, 1); // Tiling in z
+        int noise = parseOptionInt(scheme, "NOISE", source, 16); // Noise bits
+        int hscale = parseOptionInt(scheme, "HSCALE", source, 0); // Scaling for HCOMPRESS
+        int hsmooth = parseOptionInt(scheme, "HSMOOTH", source, 0); // Smoothing for HCOMPRESS
+        psFree(source);
+
+        file->compression = psFitsCompressionAlloc(type, tile, noise, hscale, hsmooth);
+        psFree(tile);
+    }
+COMPRESSION_DONE:
 
     file->fileLevel = pmFPAPHULevel(format);
