Index: trunk/ppMerge/src/ppMergeOptions.c
===================================================================
--- trunk/ppMerge/src/ppMergeOptions.c	(revision 5862)
+++ trunk/ppMerge/src/ppMergeOptions.c	(revision 6998)
@@ -1,78 +1,136 @@
-# include "ppMerge.h"
+#include <stdio.h>
+#include <pslib.h>
+#include <psmodules.h>
 
-// XXX EAM : optionally choose the mask image based on the detrend database
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// ppMergeOptions
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-bool ppMergeOptions (ppData *data, ppOptions *options, ppConfig *config) {
+// Free function
+static void mergeOptionsFree(ppMergeOptions *options // Options to free
+    )
+{
+    psFree(options->combine);
+}
 
-    bool status;
+// Allocator
+ppMergeOptions *ppMergeOptionsAlloc(void)
+{
+    ppMergeOptions *options = psAlloc(sizeof(ppMergeOptions)); // The options, to return
+    psMemSetDeallocator(options, (psFreeFunc)mergeOptionsFree);
 
-    // at what depth is the image read?
-    options->imageLoadDepth = PP_LOAD_NONE;
-    char *depth = psMetadataLookupPtr(NULL, config->recipe, "LOAD.DEPTH");
-    if (depth == NULL) {
-	psAbort ("merge", "load depth not specified");
+    options->rows = 0;
+    options->minElectrons = NAN;
+    options->zero = false;
+    options->scale = false;
+    options->exptime = false;
+    options->sample = 1;
+    options->background = PS_STAT_SAMPLE_MEDIAN;
+    options->onOff = 0;
+    options->combine = PS_STAT_SAMPLE_MEAN;
+    options->ref = 3.0;
+    options->iter = 1;
+    options->fracHigh = 0.0;
+    options->fracLow = 0.0;
+    options->nKeep = 1;
+    options->maskVal = 0xffff;
+
+    return options;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// ppMergeOptionsParse
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Parse a recipe option according to its type
+#define OPTION_PARSE(OPTION,MD,NAME,TYPE)                                                                    \
+{                                                                                                            \
+    psMetadataItem *item = psMetadataLookup(MD, NAME);                                                       \
+    if (item) {                                                                                              \
+        OPTION = psMetadataItemParse##TYPE(item);                                                            \
+    }                                                                                                        \
+}
+
+// Parse a statistic
+static psStatsOptions parseStat(psMetadata *source, // Source of the statistics option
+                                const char *name // Name of the statistics option
+    )
+{
+    bool mdok = true;                   // Status of MD lookup
+    const char *stat = psMetadataLookupStr(&mdok, source, name);  // The statistic string
+    if (!mdok || !stat || strlen(stat) == 0) {
+        return 0;
     }
-    if (!strcasecmp(depth, "FPA")) {
-	options->imageLoadDepth = PP_LOAD_FPA;
+    if (strcasecmp(stat, "MEAN") == 0 || strcasecmp(stat, "SAMPLE_MEAN") == 0) {
+        return PS_STAT_SAMPLE_MEAN;
     }
-    if (!strcasecmp(depth, "CHIP")) {
-	options->imageLoadDepth = PP_LOAD_CHIP;
+    if (strcasecmp(stat, "MEDIAN") == 0 || strcasecmp(stat, "SAMPLE_MEDIAN") == 0) {
+        return PS_STAT_SAMPLE_MEDIAN;
     }
-    if (!strcasecmp(depth, "CELL")) {
-	options->imageLoadDepth = PP_LOAD_CELL;
+    if (strcasecmp(stat, "ROBUST") == 0 || strcasecmp(stat, "ROBUST_MEDIAN") == 0) {
+        return PS_STAT_ROBUST_MEDIAN;
     }
-    if (options->imageLoadDepth == PP_LOAD_NONE) {
-	psAbort ("merge", "load depth not specified");
+    if (strcasecmp(stat, "FITTED") == 0 || strcasecmp(stat, "FITTED_MEAN") == 0) {
+        return PS_STAT_FITTED_MEAN;
+    }
+    if (strcasecmp(stat, "CLIPPED") == 0 || strcasecmp(stat, "CLIPPED_MEAN") == 0) {
+        return PS_STAT_CLIPPED_MEAN;
     }
 
-    // global pixel mask
-    options->doMask = false;
-    if (psMetadataLookupBool(NULL, config->recipe, "MASK")) {
-	data->mask->filename = psMetadataLookupStr(NULL, config->arguments, "-mask");
-        if (strlen(data->mask->filename) > 0) {
-            options->doMask = true;
-        } else {
-            psLogMsg("merge", PS_LOG_WARN, "Masking is desired, but no mask was supplied"
-		     " --- no masking will be performed.\n");
-        }
+    psError(PS_ERR_IO, true, "Unable to interpret statistic: %s\n", name);
+    return 0;
+}
+
+// Parse the options
+ppMergeOptions *ppMergeOptionsParse(ppConfig *config // Configuration
+    )
+{
+    ppMergeOptions *options = ppMergeOptionsAlloc(); // The merge options
+
+    // First, deal with the recipe.  These are parameters that will typically be constant for a camera.
+    OPTION_PARSE(options->rows,         config->recipe, "ROWS",      U16 );
+    OPTION_PARSE(options->minElectrons, config->recipe, "ELECTRONS", F32 );
+    OPTION_PARSE(options->sample,       config->recipe, "SAMPLE",    S32 );
+    OPTION_PARSE(options->rej,          config->recipe, "REJ",       F32 );
+    OPTION_PARSE(options->iter,         config->recipe, "ITER",      S32 );
+    OPTION_PARSE(options->fracHigh,     config->recipe, "FRACHIGH",  F32 );
+    OPTION_PARSE(options->fracLow,      config->recipe, "FRACLOW",   F32 );
+    OPTION_PARSE(options->nKeep,        config->recipe, "NKEEP",     S32 );
+    OPTION_PARSE(options->maskVal,      config->recipe, "MASKVAL",   U8  );
+    options->combine = parseStat(config->recipe, "COMBINE");
+    options->background = parseStat(config->recipe, "BACKGROUND");
+
+    // Now the command-line options.  These are parameters that depend on what type of frame is being combined
+
+    // Set options based on the type of calibration frame
+    const char *type = psMetadataLookupStr(NULL, config->arguments, "-type"); // The type of calibration frame
+    if (strcasecmp(type, "BIAS") == 0) {
+        options->zero = false;
+        options->scale = false;
+        options->exptime = false;
+    } else if (strcasecmp(type, "DARK") == 0) {
+        options->zero = false;
+        options->scale = false;
+        options->exptime = true;
+    } else if (strcasecmp(type, "FLAT") == 0) {
+        options->zero = false;
+        options->scale = true;
+        options->exptime = false;
+    } else if (strcasecmp(type, "FRINGE") == 0) {
+        options->zero = true;
+        options->scale = true;
+        options->exptime = false;
+    } else {
+        psLogMsg(__func__, PS_LOG_WARN, "Unrecognised image type: %s --- ignored.\n", type);
     }
 
-    // how do we calculate the merge stack?
-    psStatsOptions mergeStats = 0;
-    psString stat = psMetadataLookupStr(NULL, config->recipe, "MERGE.STAT");
-    if (! strcasecmp(stat, "MEAN")) {
-	mergeStats = PS_STAT_SAMPLE_MEAN;
-    } else if (! strcasecmp(stat, "MEDIAN")) {
-	mergeStats = PS_STAT_SAMPLE_MEDIAN;
-    } else {
-	psAbort ("merge", "MERGE.STAT (%s) is not one of MEAN, MEDIAN\n", stat);
-    }
-    options->combineParams = pmCombineParamsAlloc (mergeStats);
+    // Or you can set them individually
+    OPTION_PARSE(options->zero,    config->recipe, "-zero",    Bool);
+    OPTION_PARSE(options->scale,   config->recipe, "-scale",   Bool);
+    OPTION_PARSE(options->exptime, config->recipe, "-exptime", Bool);
 
-    // other merge stack options
-    options->applyZeroScale = psMetadataLookupBool(NULL, config->recipe, "MERGE.RESCALE");
+    // Number of on/off images
+    OPTION_PARSE(options->onoff, config->recipe, "-onoff", S32);
 
-    int nKeep = psMetadataLookupS32(&status, config->recipe, "MERGE.NKEEP");
-    if (status && nKeep > 0) {
-	options->combineParams->nKeep = nKeep;
-    }
-
-    float fracHigh = psMetadataLookupF32(&status, config->recipe, "MERGE.FRAC.HIGH");
-    if (status) {
-	options->combineParams->fracHigh = fracHigh;
-    }
-
-    float fracLow = psMetadataLookupF32(&status, config->recipe, "MERGE.FRAC.LOW");
-    if (status) {
-	options->combineParams->fracLow = fracLow;
-    }
-
-    // XXX need to set the masking value somehow...
-
-    // gain and readnoise come from camera parameters and depend on chip/cell
-    // XXX drop these from the options structure?
-    options->gain = 1.0;
-    options->readnoise = 0.0;
-
-    return true;
+    return options;
 }
