Index: trunk/psModules/src/camera/pmFPAfileDefine.c
===================================================================
--- trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 13669)
+++ trunk/psModules/src/camera/pmFPAfileDefine.c	(revision 13704)
@@ -93,16 +93,16 @@
 }
 
-// define a pmFPAfile, bind to the optional fpa if supplied
-pmFPAfile *pmFPAfileDefineOutput(const pmConfig *config, pmFPA *fpa, const char *name)
-{
-    PS_ASSERT_PTR_NON_NULL(config, NULL);
-    PS_ASSERT_PTR_NON_NULL(config->files, NULL);
-    PS_ASSERT_PTR_NON_NULL(config->camera, NULL);
-    PS_ASSERT_STRING_NON_EMPTY(name, NULL);
-
+// Define an output pmFPAfile
+static pmFPAfile *fpaFileDefineOutput(const pmConfig *config, // Configuration
+                                      pmFPA *fpa, // Optional FPA to bind
+                                      const char *name, // Name of file rule
+                                      const char *cameraName, // Name of camera configuration to use
+                                      const char *formatName // Name of camera format to use
+    )
+{
     bool status;
 
     // select the FILERULES from the camera config
-    psMetadata *filerules = psMetadataLookupPtr (&status, config->camera, "FILERULES");
+    psMetadata *filerules = psMetadataLookupPtr(&status, config->camera, "FILERULES");
     if (filerules == NULL) {
         psError(PS_ERR_IO, true, "Can't find FILERULES in the CAMERA configuration!");
@@ -112,5 +112,5 @@
     // select the name from the FILERULES
     // check for alias name (type == STR, name is aliased name)
-    const char *realname = psMetadataLookupStr (&status, filerules, name);
+    const char *realname = psMetadataLookupStr(&status, filerules, name);
     if (!realname || strlen(realname) == 0) {
         realname = name;
@@ -123,12 +123,12 @@
     }
 
-    pmFPAfile *file = pmFPAfileAlloc ();
+    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->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) {
@@ -153,17 +153,40 @@
     }
 
-    psMetadata *camera;                 // Camera to use
-    if (fpa && fpa->camera) {
-        camera = (psMetadata*)fpa->camera; // Casting away const, so I can put it in the file
+    // 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;
+        }
     } else {
-        camera = config->camera;
+        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);
 
-    // select the format list from the selected camera
-    const char *formatName = psMetadataLookupStr (&status, data, "FILE.FORMAT");
-    if (!formatName || strcmp(formatName, "NONE") == 0) {
-        // Try to get by with the default
-        formatName = config->formatName;
+    // Use the format we were told to, the format specified in the file rule, or default to the default format
+    if (!formatName || strlen(formatName) == 0) {
+        // select the format list from the selected camera
+        formatName = psMetadataLookupStr(&status, data, "FILE.FORMAT");
+        if (!formatName || strcmp(formatName, "NONE") == 0) {
+            // Try to get by with the default
+            formatName = config->formatName;
+        }
     }
     psMetadata *formats = psMetadataLookupMetadata(&status, file->camera, "FORMATS"); // List of formats
@@ -177,5 +200,9 @@
     file->format = psMemIncrRefCounter(format);
 
-    file->fpa = psMemIncrRefCounter(fpa);
+    if (fpa) {
+        file->fpa = psMemIncrRefCounter(fpa);
+    } else {
+        file->fpa = pmFPAConstruct(file->camera);
+    }
 
     file->fileLevel = pmFPAPHULevel(format);
@@ -219,4 +246,14 @@
 }
 
+// define a pmFPAfile, bind to the optional fpa if supplied
+pmFPAfile *pmFPAfileDefineOutput(const pmConfig *config, pmFPA *fpa, const char *name)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+    PS_ASSERT_PTR_NON_NULL(config->files, NULL);
+    PS_ASSERT_PTR_NON_NULL(config->camera, NULL);
+    PS_ASSERT_STRING_NON_EMPTY(name, NULL);
+
+    return fpaFileDefineOutput(config, fpa, name, NULL, NULL);
+}
 
 // search for argname on the config->argument list
@@ -245,5 +282,5 @@
     psArray *infiles = psMetadataLookupPtr(&status, config->arguments, argname);
     if (!status) {
-	if (success) *success = true;
+        if (success) *success = true;
         return NULL;
     }
@@ -415,5 +452,5 @@
     if (!status) {
         // this is not an error: this just means no matching argument was supplied
-	if (success) *success = true;
+        if (success) *success = true;
         return NULL;
     }
@@ -545,5 +582,5 @@
     if (!status) {
         psTrace("psModules.camera", 5, "Failed to find %s in argument list", argname);
-	if (success) *success = true;
+        if (success) *success = true;
         return NULL;
     }
@@ -679,5 +716,5 @@
         // don't free the file here: it is left on config->files
         // to be used optionally by pmFPAfileDefineFromDetDB (or others)
-	if (success) *success = true;
+        if (success) *success = true;
         return NULL;
     }
@@ -908,4 +945,34 @@
 }
 
+pmFPAfile *pmFPAfileDefineSkycell(const pmConfig *config, pmFPA *fpa, const char *filename)
+{
+    PS_ASSERT_PTR_NON_NULL(config, NULL);
+    PS_ASSERT_STRING_NON_EMPTY(filename, NULL);
+    PS_ASSERT_STRING_NON_EMPTY(config->cameraName, NULL);
+    PS_ASSERT_STRING_NON_EMPTY(config->formatName, NULL);
+
+    pmFPAfile *file;                    // The new file
+
+    if (config->cameraName[0] == '_' &&
+        strcmp(config->cameraName + strlen(config->cameraName) - 8, "-SKYCELL") == 0) {
+        // The input camera is already a skycell
+        file = fpaFileDefineOutput(config, fpa, filename, config->cameraName, "SKYCELL");
+    } else {
+        // Find the correct camera configuration
+        psString cameraName = NULL;         // Name of the new (automatically-generated) camera configuration
+        psStringAppend(&cameraName, "_%s-SKYCELL", config->cameraName);
+
+        file = fpaFileDefineOutput(config, fpa, filename, cameraName, "SKYCELL");
+        psFree(cameraName);
+    }
+
+    // Ensure everything is written out at the appropriate level
+    file->fileLevel = PM_FPA_LEVEL_FPA;
+    file->dataLevel = PM_FPA_LEVEL_FPA;
+    file->freeLevel = PM_FPA_LEVEL_FPA;
+
+    return file;
+}
+
 pmFPAfile *pmFPAfileDefineChipMosaic(const pmConfig *config, pmFPA *src, const char *filename)
 {
@@ -916,66 +983,21 @@
     PS_ASSERT_STRING_NON_EMPTY(config->formatName, NULL);
 
+    pmFPAfile *file;                    // The new file
     if (config->cameraName[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);
-        psFree (file->camera);
-        psFree (file->format);
-        psFree (file->fpa);
-        file->camera = psMemIncrRefCounter(config->camera);
-        file->format = psMemIncrRefCounter(config->format);
-        file->fpa = pmFPAConstruct(file->camera);
-        return file;
-    }
-
-    // Find the correct camera configuration
-    bool mdok;                          // Status of MD lookup
-    psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->site, "CAMERAS"); // Camera configurations
-    if (!mdok || !cameras) {
-        psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the site configuration.\n");
-        return NULL;
-    }
-    psString name = NULL;               // Name of the new (automatically-generated) camera configuration
-    psStringAppend(&name, "_%s-CHIP", config->cameraName);
-    psMetadata *camera = psMetadataLookupMetadata(&mdok, cameras, name); // 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", name);
-        psFree(name);
-        return NULL;
-    }
-    psFree(name);
-
-    // Need to look up the format of the same name, but under the mosaic camera
-    psMetadata *formats = psMetadataLookupMetadata(&mdok, camera, "FORMATS"); // The FORMATS
-    if (!mdok || !formats) {
-        psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find FORMATS in camera configuration %s.\n",
-                config->cameraName);
-        return NULL;
-    }
-    psMetadata *format = psMetadataLookupMetadata(&mdok, formats, config->formatName); // The format
-    if (!mdok || !format) {
-        psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find camera format %s within camera %s.\n",
-                config->formatName, config->cameraName);
-        return NULL;
-    }
-
-    pmFPA *fpa = pmFPAConstruct(camera);
-    if (!fpa) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to generate mosaicked camera.\n");
-        return NULL;
-    }
-    pmFPAfile *file = pmFPAfileDefineOutput(config, fpa, filename);
-    if (!file) {
-        psErrorStackPrint(stderr, "file %s not defined\n", filename);
-        return NULL;
-    }
+        file = fpaFileDefineOutput(config, NULL, filename, config->cameraName, config->formatName);
+    } else {
+        psString cameraName = NULL;         // Name of the new (automatically-generated) camera configuration
+        psStringAppend(&cameraName, "_%s-CHIP", config->cameraName);
+
+        // Find the correct camera configuration
+        file = fpaFileDefineOutput(config, NULL, filename, cameraName, config->formatName);
+        psFree(cameraName);
+    }
+
     file->src = src; // inherit output elements from this source pmFPA
+
     file->mosaicLevel = PM_FPA_LEVEL_CHIP; // don't do any I/O on this at a lower level
-
-    psFree (file->format);
-    file->format = psMemIncrRefCounter(format);
-
-    psFree(fpa);
 
     return file;
@@ -989,74 +1011,29 @@
     PS_ASSERT_STRING_NON_EMPTY(config->cameraName, NULL);
 
+    pmFPAfile *file;                    // The new file
     if (config->cameraName[0] == '_' &&
             strcmp(config->cameraName + strlen(config->cameraName) - 4 , "-FPA") == 0) {
         // The input camera has already been mosaicked to this level
-        pmFPAfile *file = pmFPAfileDefineOutput(config, NULL, filename);
-        psFree (file->camera);
-        psFree (file->format);
-        psFree (file->fpa);
-        file->camera = psMemIncrRefCounter(config->camera);
-        file->format = psMemIncrRefCounter(config->format);
-        file->fpa = pmFPAConstruct(file->camera);
-        return file;
-    }
-
-    // Find the correct camera configuration
-    bool mdok;                          // Status of MD lookup
-    psMetadata *cameras = psMetadataLookupMetadata(&mdok, config->site, "CAMERAS"); // Camera configurations
-    if (!mdok || !cameras) {
-        psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find CAMERAS in the site configuration.\n");
-        return NULL;
-    }
-    psString original;                  // Name of the original camera configuration
-    psString name = NULL;               // Name of the new (automatically-generated) camera configuration
-    if (config->cameraName[0] == '_' &&
+        file = fpaFileDefineOutput(config, NULL, filename, config->cameraName, config->formatName);
+    } else {
+
+        psString original;                  // Name of the original camera configuration
+        if (config->cameraName[0] == '_' &&
             strcmp(config->cameraName + strlen(config->cameraName) - 5 , "-CHIP") == 0) {
-        // It's a chip mosaic; we need to get the original name
-        original = psStringNCopy(config->cameraName + 1, strlen(config->cameraName) - 6);
-    } else {
-        original = psMemIncrRefCounter(config->cameraName);
-    }
-    psStringAppend(&name, "_%s-FPA", original);
-    psFree(original);
-    psMetadata *camera = psMetadataLookupMetadata(&mdok, cameras, name); // 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", name);
-        psFree(name);
-        return NULL;
-    }
-    psFree(name);
-
-    // Need to look up the format of the same name, but under the mosaic camera
-    psMetadata *formats = psMetadataLookupMetadata(&mdok, camera, "FORMATS"); // The FORMATS
-    if (!mdok || !formats) {
-        psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find FORMATS in camera configuration %s.\n",
-                config->cameraName);
-        return NULL;
-    }
-    psMetadata *format = psMetadataLookupMetadata(&mdok, formats, config->formatName); // The format
-    if (!mdok || !format) {
-        psError(PS_ERR_UNEXPECTED_NULL, true, "Unable to find camera format %s within camera %s.\n",
-                config->formatName, config->cameraName);
-        return NULL;
-    }
-
-    pmFPA *fpa = pmFPAConstruct(camera);
-    if (!fpa) {
-        psError(PS_ERR_UNEXPECTED_NULL, false, "Unable to generate mosaicked camera.\n");
-        return NULL;
-    }
-    pmFPAfile *file = pmFPAfileDefineOutput(config, fpa, filename);
-    if (!file) {
-        psErrorStackPrint(stderr, "file %s not defined\n", filename);
-        return NULL;
-    }
+            // It's a chip mosaic; we need to get the original name
+            original = psStringNCopy(config->cameraName + 1, strlen(config->cameraName) - 6);
+        } else {
+            original = psMemIncrRefCounter(config->cameraName);
+        }
+        psString cameraName = NULL;
+        psStringAppend(&cameraName, "_%s-FPA", original);
+
+        file = fpaFileDefineOutput(config, NULL, filename, cameraName, config->formatName);
+        psFree(cameraName);
+    }
+
     file->src = src; // inherit output elements from this source pmFPA
+
     file->mosaicLevel = PM_FPA_LEVEL_FPA; // don't do any I/O on this at a lower level
-    psFree (file->format);
-    file->format = psMemIncrRefCounter(format);
-
-    psFree(fpa);
 
     return file;
