/*
 * dettoolConfig.c
 *
 * Copyright (C) 2006  Joshua Hoblitt
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * program; see the file COPYING. If not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <psmodules.h>

#include "pxtools.h"
#include "dettool.h"

pxConfig *dettoolConfig(pxConfig *config, int argc, char **argv)
{
    if (!config) {
        config = pxConfigAlloc();
    }

    pmConfigReadParamsSet(false);

    // setup site config
    config->modules = pmConfigRead(&argc, argv, NULL);
    if (!config->modules) {
        psError(PS_ERR_UNKNOWN, false, "Can't find site configuration");
        psFree(config);
        return NULL;
    }

    psTime *now = psTimeGetNow(PS_TIME_TAI);

    // -pending
    psMetadata *pendingArgs = psMetadataAlloc();
    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-exp_id",  0,
            "search by exposure ID", NULL);
    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-exp_type",  0,
            "search by exposure type", NULL);
    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-inst",  0,
            "search by camera", NULL);
    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-telescope",  0,
            "search by telescope", NULL);
    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-filter",  0,
            "search by filter", NULL);
    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-uri",  0,
            "search by URL", NULL);
    psMetadataAddBool(pendingArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -definebytag
    psMetadata *definebytagArgs = psMetadataAlloc();
    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-exp_id",
            PS_META_DUPLICATE_OK,
            "include this exposure (multiple OK, required)", NULL);
    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-det_type",  0,
            "define the type of detrend run (required)", NULL);
    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-mode",  0,
            "define the mode of this detrend run", "master");
    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-filelevel",  0,
            "define filelevel", NULL);
    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-workdir",  0,
            "define workdir (required)", NULL);
    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-inst",  0,
            "define camera", NULL);
    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-telescope",  0,
            "define telescope", NULL);
    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-exp_type",  0,
            "define exposure type", NULL);
    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-filter",  0,
            "define filter ", NULL);
    psMetadataAddF32(definebytagArgs, PS_LIST_TAIL, "-airmass_min",  0,
            "define min airmass", NAN);
    psMetadataAddF32(definebytagArgs, PS_LIST_TAIL, "-airmass_max",  0,
            "define max airmass", NAN);
    psMetadataAddF32(definebytagArgs, PS_LIST_TAIL, "-exp_time_min",  0,
            "define min exposure time", NAN);
    psMetadataAddF32(definebytagArgs, PS_LIST_TAIL, "-exp_time_max",  0,
            "define max exposure time", NAN);
    psMetadataAddF64(definebytagArgs, PS_LIST_TAIL, "-ccd_temp_min",  0,
            "define min ccd tempature", NAN);
    psMetadataAddF64(definebytagArgs, PS_LIST_TAIL, "-ccd_temp_max",  0,
            "define max ccd tempature", NAN);
    psMetadataAddF64(definebytagArgs, PS_LIST_TAIL, "-posang_min",  0,
            "define min rotator position angle", NAN);
    psMetadataAddF64(definebytagArgs, PS_LIST_TAIL, "-posang_max",  0,
            "define max rotator position angle", NAN);
    psMetadataAddF64(definebytagArgs, PS_LIST_TAIL, "-solang_min",  0,
            "define min solar angle", NAN);
    psMetadataAddF64(definebytagArgs, PS_LIST_TAIL, "-solang_max",  0,
            "define max solar angle", NAN);
    psMetadataAddTime(definebytagArgs, PS_LIST_TAIL, "-registered",  0,
            "time detrend run was registered", now);
    psMetadataAddTime(definebytagArgs, PS_LIST_TAIL, "-time_begin",  0,
            "detrend applies to exposures taken during this period", NULL);
    psMetadataAddTime(definebytagArgs, PS_LIST_TAIL, "-time_end",  0,
            "detrend applies to exposures taken during this period", NULL);
    psMetadataAddTime(definebytagArgs, PS_LIST_TAIL, "-use_begin",  0,
            "start of detrend run applicable period", NULL);
    psMetadataAddTime(definebytagArgs, PS_LIST_TAIL, "-use_end",  0,
            "end of detrend run applicable period", NULL);
    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-reduction",  0,
            "define reduction class for processing", NULL);
    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-label",  0,
            "define detrun label", NULL);
    psMetadataAddBool(definebytagArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -definebyquery
    psMetadata *definebyqueryArgs = psMetadataAlloc();
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-det_type",  0,
            "define the type of detrend run (required)", NULL);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-mode",  0,
            "define the mode of this detrend run", "master");
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-filelevel",  0,
            "define filelevel", NULL);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-workdir",  0,
            "define workdir (required)", NULL);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-inst",  0,
            "define camera (required)", NULL);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-telescope",  0,
            "define telescope", NULL);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-filter",  0,
            "define filter ", NULL);
    psMetadataAddF32(definebyqueryArgs, PS_LIST_TAIL, "-airmass_min",  0,
            "define min airmass", NAN);
    psMetadataAddF32(definebyqueryArgs, PS_LIST_TAIL, "-airmass_max",  0,
            "define max airmass", NAN);
    psMetadataAddF32(definebyqueryArgs, PS_LIST_TAIL, "-exp_time_min",  0,
            "define min exposure time", NAN);
    psMetadataAddF32(definebyqueryArgs, PS_LIST_TAIL, "-exp_time_max",  0,
            "define max exposure time", NAN);
    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-ccd_temp_min",  0,
            "define min ccd tempature", NAN);
    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-ccd_temp_max",  0,
            "define max ccd tempature", NAN);
    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-posang_min",  0,
            "define min rotator position angle", NAN);
    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-posang_max",  0,
            "define max rotator position angle", NAN);
    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-solang_min",  0,
            "define min solar angle", NAN);
    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-solang_max",  0,
            "define max solar angle", NAN);
    psMetadataAddTime(definebyqueryArgs, PS_LIST_TAIL, "-registered",  0,
            "time detrend run was registered", now);
    psMetadataAddTime(definebyqueryArgs, PS_LIST_TAIL, "-time_begin",  0,
            "detrend applies to exposures taken during this period", NULL);
    psMetadataAddTime(definebyqueryArgs, PS_LIST_TAIL, "-time_end",  0,
            "detrend applies to exposures taken during this period", NULL);
    psMetadataAddTime(definebyqueryArgs, PS_LIST_TAIL, "-use_begin",  0,
            "start of detrend run applicable period", NULL);
    psMetadataAddTime(definebyqueryArgs, PS_LIST_TAIL, "-use_end",  0,
            "end of detrend run applicable period", NULL);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-select_exp_type",  0,
            "search for exp_type", NULL);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-select_inst",  0,
            "search for camera", NULL);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-select_telescope",  0,
            "search for telescope", NULL);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-select_filter",  0,
            "search for filter", NULL);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-select_uri",  0,
            "search for uri", NULL);
    psMetadataAddTime(definebyqueryArgs, PS_LIST_TAIL, "-select_dateobs_begin", 0,
            "search for exposures by time (>=)", NULL);
    psMetadataAddTime(definebyqueryArgs, PS_LIST_TAIL, "-select_dateobs_end", 0,
            "search for exposures by time (<)", NULL);
    psMetadataAddF32(definebyqueryArgs, PS_LIST_TAIL, "-select_airmass_min",  0,
            "define min airmass", NAN);
    psMetadataAddF32(definebyqueryArgs, PS_LIST_TAIL, "-select_airmass_max",  0,
            "define max airmass", NAN);
    psMetadataAddF32(definebyqueryArgs, PS_LIST_TAIL, "-select_sat_pixel_frac_max",  0,
            "define max fraction of saturated pixels", NAN);
    psMetadataAddF32(definebyqueryArgs, PS_LIST_TAIL, "-select_exp_time_min",  0,
            "define min exposure time", NAN);
    psMetadataAddF32(definebyqueryArgs, PS_LIST_TAIL, "-select_exp_time_max",  0,
            "define max exposure time", NAN);
    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_ccd_temp_min",  0,
            "define min ccd tempature", NAN);
    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_ccd_temp_max",  0,
            "define max ccd tempature", NAN);
    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_posang_min",  0,
            "define min rotator position angle", NAN);
    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_posang_max",  0,
            "define max rotator position angle", NAN);
    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_solang_min",  0,
            "define min solar angle", NAN);
    psMetadataAddF64(definebyqueryArgs, PS_LIST_TAIL, "-select_solang_max",  0,
            "define max solar angle", NAN);
    psMetadataAddBool(definebyqueryArgs, PS_LIST_TAIL, "-pretend",  0,
            "print the exposures that would be included in the detrend run and exit", false);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-reduction",  0,
            "define reduction class for processing", NULL);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-label",  0,
            "define detrun label", NULL);
    psMetadataAddBool(definebyqueryArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -definebydetrun
    psMetadata *definebydetrunArgs = psMetadataAlloc();
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-det_id",  0,
            "det ID to base a new detRun on (required)", NULL);
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-set_det_type",  0,
            "define the type of detrend run", NULL);
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-set_mode",  0,
            "define the mode of this detrend run", "master");
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-set_exp_type",  0,
            "define exposure type", NULL);
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-set_filelevel",  0,
            "define filelevel", NULL);
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-set_workdir",  0,
            "define workdir", NULL);
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-set_filter",  0,
            "define filter ", NULL);
    psMetadataAddF32(definebydetrunArgs, PS_LIST_TAIL, "-set_airmass_min",  0,
            "define airmass", NAN);
    psMetadataAddF32(definebydetrunArgs, PS_LIST_TAIL, "-set_airmass_max",  0,
            "define airmass", NAN);
    psMetadataAddF32(definebydetrunArgs, PS_LIST_TAIL, "-set_exp_time_min",  0,
            "define exposure time", NAN);
    psMetadataAddF32(definebydetrunArgs, PS_LIST_TAIL, "-set_exp_time_max",  0,
            "define exposure time", NAN);
    psMetadataAddF64(definebydetrunArgs, PS_LIST_TAIL, "-set_ccd_temp_min",  0,
            "define ccd tempature", NAN);
    psMetadataAddF64(definebydetrunArgs, PS_LIST_TAIL, "-set_ccd_temp_max",  0,
            "define ccd tempature", NAN);
    psMetadataAddF64(definebydetrunArgs, PS_LIST_TAIL, "-set_posang_min",  0,
            "define rotator position angle", NAN);
    psMetadataAddF64(definebydetrunArgs, PS_LIST_TAIL, "-set_posang_max",  0,
            "define rotator position angle", NAN);
    psMetadataAddTime(definebydetrunArgs, PS_LIST_TAIL, "-set_registered",  0,
            "time detrend run was registered", now);
    psMetadataAddTime(definebydetrunArgs, PS_LIST_TAIL, "-set_time_begin",  0,
            "start of period to apply detrend too", NULL);
    psMetadataAddTime(definebydetrunArgs, PS_LIST_TAIL, "-set_time_end",  0,
            "end of period to apply detrend too", NULL);
    psMetadataAddTime(definebydetrunArgs, PS_LIST_TAIL, "-set_use_begin",  0,
            "start of detrend run applicable period", NULL);
    psMetadataAddTime(definebydetrunArgs, PS_LIST_TAIL, "-set_use_end",  0,
            "end of detrend run applicable period", NULL);
    psMetadataAddF64(definebydetrunArgs, PS_LIST_TAIL, "-set_solang_min",  0,
            "define solar angle", NAN);
    psMetadataAddF64(definebydetrunArgs, PS_LIST_TAIL, "-set_solang_max",  0,
            "define solar angle", NAN);
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-filter_input_begin", 0,
            "filter input detrun exp to be in this period", NULL);
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-filter_input_end", 0,
            "filter input detrun exp to be in this period", NULL);
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-set_reduction",  0,
            "define reduction class for processing", NULL);
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-set_label",  0,
            "define detrun label", NULL);
    psMetadataAddBool(definebydetrunArgs, PS_LIST_TAIL, "-simple", 0,
            "use the simple output format", false);

    // -makecorrection
    psMetadata *makecorrectionArgs = psMetadataAlloc();
    psMetadataAddStr(makecorrectionArgs, PS_LIST_TAIL, "-det_id",  0,
            "det ID to be corrected (required)", NULL);
    psMetadataAddBool(makecorrectionArgs, PS_LIST_TAIL, "-simple", 0,
            "use the simple output format", false);

    // -tocorrectexp
    psMetadata *tocorrectexpArgs = psMetadataAlloc();
    psMetadataAddU64(tocorrectexpArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(tocorrectexpArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -tocorrectimfile
    psMetadata *tocorrectimfileArgs = psMetadataAlloc();
    psMetadataAddStr(tocorrectimfileArgs, PS_LIST_TAIL, "-det_id", 0,
            "search for detrend ID", NULL);
    psMetadataAddU64(tocorrectimfileArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(tocorrectimfileArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -addcorrectimfile
    psMetadata *addcorrectimfileArgs = psMetadataAlloc();
    psMetadataAddStr(addcorrectimfileArgs, PS_LIST_TAIL, "-det_id",  0,
            "define detrend ID (required)", NULL);
    psMetadataAddStr(addcorrectimfileArgs, PS_LIST_TAIL, "-class_id",  0,
            "search for class ID (required)", NULL);
    psMetadataAddStr(addcorrectimfileArgs, PS_LIST_TAIL, "-uri",  0,
            "define resid file URI", NULL);
    psMetadataAddF64(addcorrectimfileArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposure background", NAN);
    psMetadataAddF64(addcorrectimfileArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposure background stdev", NAN);
    psMetadataAddF64(addcorrectimfileArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposure background mean stdev", NAN);
    psMetadataAddF64(addcorrectimfileArgs, PS_LIST_TAIL, "-user_1",  0,
            "define user statistic (1)", NAN);
    psMetadataAddF64(addcorrectimfileArgs, PS_LIST_TAIL, "-user_2",  0,
            "define user statistic (2)", NAN);
    psMetadataAddF64(addcorrectimfileArgs, PS_LIST_TAIL, "-user_3",  0,
            "define user statistic (3)", NAN);
    psMetadataAddF64(addcorrectimfileArgs, PS_LIST_TAIL, "-user_4",  0,
            "define user statistic (4)", NAN);
    psMetadataAddF64(addcorrectimfileArgs, PS_LIST_TAIL, "-user_5",  0,
            "define user statistic (5)", NAN);
    psMetadataAddStr(addcorrectimfileArgs, PS_LIST_TAIL, "-path_base",  0,
            "define base output location", NULL);

    // -runs
    psMetadata *runsArgs = psMetadataAlloc();
    psMetadataAddStr(runsArgs, PS_LIST_TAIL, "-det_type",  0,
            "search for type of detrend run", NULL);
    psMetadataAddBool(runsArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);
    psMetadataAddBool(runsArgs, PS_LIST_TAIL, "-active",  0,
            "only return active detRuns", false);
    psMetadataAddU64(runsArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddStr(runsArgs, PS_LIST_TAIL, "-det_id", 0,
            "search for detrend ID", NULL);

    psMetadataAddStr(runsArgs, PS_LIST_TAIL, "-inst", 0,
            "search for camera (instrument)", NULL);
    psMetadataAddStr(runsArgs, PS_LIST_TAIL, "-telescope", 0,
            "search for telescope", NULL);
    psMetadataAddStr(runsArgs, PS_LIST_TAIL, "-filter", 0,
            "search for filter", NULL);

    psMetadataAddF32(runsArgs, PS_LIST_TAIL, "-airmass", 0,
            "match airmass", NAN);
    psMetadataAddF32(runsArgs, PS_LIST_TAIL, "-exp_time", 0,
            "match exp time", NAN);
    psMetadataAddF32(runsArgs, PS_LIST_TAIL, "-ccd_temp", 0,
            "match ccd temp", NAN);
    psMetadataAddF64(runsArgs, PS_LIST_TAIL, "-posang", 0,
            "match posang", NAN);

    // -childlessrun
    psMetadata *childlessrunArgs = psMetadataAlloc();
    psMetadataAddStr(childlessrunArgs, PS_LIST_TAIL, "-det_type",  0,
            "search for type of detrend run", NULL);
    psMetadataAddU64(childlessrunArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(childlessrunArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -input
    psMetadata *inputArgs = psMetadataAlloc();
    psMetadataAddStr(inputArgs, PS_LIST_TAIL, "-det_id", 0,
            "search for detrend ID", NULL);
    psMetadataAddS32(inputArgs, PS_LIST_TAIL, "-iteration",  0,
            "define iteration number", 0);
    psMetadataAddStr(inputArgs, PS_LIST_TAIL, "-exp_id",  0,
            "search for exp ID", NULL);
    psMetadataAddBool(inputArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -raw
    psMetadata *rawArgs = psMetadataAlloc();
    psMetadataAddBool(rawArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -toprocessedimfile
    psMetadata *toprocessedimfileArgs = psMetadataAlloc();
    psMetadataAddStr(toprocessedimfileArgs, PS_LIST_TAIL, "-det_id",  0,
            "search for detrend ID", NULL);
    psMetadataAddStr(toprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,
            "search for exp ID", NULL);
    psMetadataAddStr(toprocessedimfileArgs, PS_LIST_TAIL, "-class_id",  0,
            "search for class ID", NULL);
    psMetadataAddU64(toprocessedimfileArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(toprocessedimfileArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -addprocessedimfile
    psMetadata *addprocessedimfileArgs = psMetadataAlloc();
    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-det_id",  0,
            "define detrend ID (required)", NULL);
    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,
            "define exp ID (required)", NULL);
    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-class_id",  0,
            "define class ID (required)", NULL);
    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-uri",  0,
            "define URI", NULL);
    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-recip",  0,
            "define recipe", NULL);
    psMetadataAddF64(addprocessedimfileArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposure background", NAN);
    psMetadataAddF64(addprocessedimfileArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposure background stdev", NAN);
    psMetadataAddF64(addprocessedimfileArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposure background mean stdev", NAN);
    psMetadataAddF64(addprocessedimfileArgs, PS_LIST_TAIL, "-fringe_0",  0,
            "define fringe slope (0th term)", NAN);
    psMetadataAddF64(addprocessedimfileArgs, PS_LIST_TAIL, "-fringe_1",  0,
            "define fringe slope (1st term)", NAN);
    psMetadataAddF64(addprocessedimfileArgs, PS_LIST_TAIL, "-fringe_2",  0,
            "define fringe slope (2nd term)", NAN);
    psMetadataAddF64(addprocessedimfileArgs, PS_LIST_TAIL, "-user_1",  0,
            "define user statistic (1)", NAN);
    psMetadataAddF64(addprocessedimfileArgs, PS_LIST_TAIL, "-user_2",  0,
            "define user statistic (2)", NAN);
    psMetadataAddF64(addprocessedimfileArgs, PS_LIST_TAIL, "-user_3",  0,
            "define user statistic (3)", NAN);
    psMetadataAddF64(addprocessedimfileArgs, PS_LIST_TAIL, "-user_4",  0,
            "define user statistic (4)", NAN);
    psMetadataAddF64(addprocessedimfileArgs, PS_LIST_TAIL, "-user_5",  0,
            "define user statistic (5)", NAN);
    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-path_base",  0,
            "define base output location", NULL);
    psMetadataAddS16(addprocessedimfileArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code", 0);

    // -processedimfile
    psMetadata *processedimfileArgs = psMetadataAlloc();
    psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-det_id",  0,
            "search for detrend ID", NULL);
    psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,
            "search for exp ID", NULL);
    psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-class_id",  0,
            "search for class ID", NULL);
    psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-select_state",  0,
            "search for state", NULL);
    psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-select_mode",  0,
            "search for mode", NULL);
    psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-chip",  0,
            "restrict results to completed 'chip' sets", false);
    psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-exp",  0,
            "restrict results to complete 'exposures'", false);
    psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-included",  0,
            "restrict results to exposures 'includeded' in the current iteration", false);
    psMetadataAddU64(processedimfileArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-faulted",  0,
            "only return imfiles with a fault status set", false);
    psMetadataAddBool(processedimfileArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -revertprocessedimfile
    psMetadata *revertprocessedimfileArgs = psMetadataAlloc();
    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-det_id",  0,
            "search for detrend ID (required)", NULL);
    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-exp_id",  0,
            "search by exposure ID", NULL);
    psMetadataAddStr(revertprocessedimfileArgs, PS_LIST_TAIL, "-class_id",  0,
            "search by class ID", NULL);
    psMetadataAddS16(revertprocessedimfileArgs, PS_LIST_TAIL, "-code",  0,
            "search by fault code", 0);

    // -toprocessedexp
    psMetadata *toprocessedexpArgs = psMetadataAlloc();
    psMetadataAddU64(toprocessedexpArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(toprocessedexpArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -addproccessedexp
    psMetadata *addprocessedexpArgs = psMetadataAlloc();
    psMetadataAddStr(addprocessedexpArgs, PS_LIST_TAIL, "-det_id",  0,
            "define detrend ID (required)", NULL);
    psMetadataAddStr(addprocessedexpArgs, PS_LIST_TAIL, "-exp_id",  0,
            "define detrend ID (required)", NULL);
    psMetadataAddStr(addprocessedexpArgs, PS_LIST_TAIL, "-recip",  0,
            "define recipe", NULL);
    psMetadataAddF64(addprocessedexpArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposure background", NAN);
    psMetadataAddF64(addprocessedexpArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposure background stdev", NAN);
    psMetadataAddF64(addprocessedexpArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposure background mean stdev", NAN);
    psMetadataAddF64(addprocessedexpArgs, PS_LIST_TAIL, "-fringe_0",  0,
            "define fringe slope (0th term)", NAN);
    psMetadataAddF64(addprocessedexpArgs, PS_LIST_TAIL, "-fringe_1",  0,
            "define fringe slope (1st term)", NAN);
    psMetadataAddF64(addprocessedexpArgs, PS_LIST_TAIL, "-fringe_2",  0,
            "define fringe slope (2nd term)", NAN);
    psMetadataAddF64(addprocessedexpArgs, PS_LIST_TAIL, "-user_1",  0,
            "define user statistic (1)", NAN);
    psMetadataAddF64(addprocessedexpArgs, PS_LIST_TAIL, "-user_2",  0,
            "define user statistic (2)", NAN);
    psMetadataAddF64(addprocessedexpArgs, PS_LIST_TAIL, "-user_3",  0,
            "define user statistic (3)", NAN);
    psMetadataAddF64(addprocessedexpArgs, PS_LIST_TAIL, "-user_4",  0,
            "define user statistic (4)", NAN);
    psMetadataAddF64(addprocessedexpArgs, PS_LIST_TAIL, "-user_5",  0,
            "define user statistic (5)", NAN);
    psMetadataAddStr(addprocessedexpArgs, PS_LIST_TAIL, "-path_base",  0,
            "define base output location", NULL);
    psMetadataAddS16(addprocessedexpArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code", 0);

    // -proccessedexp
    psMetadata *processedexpArgs = psMetadataAlloc();
    psMetadataAddStr(processedexpArgs, PS_LIST_TAIL, "-det_id",  0,
            "define detrend ID", NULL);
    psMetadataAddStr(processedexpArgs, PS_LIST_TAIL, "-exp_id",  0,
            "define detrend ID", NULL);
    psMetadataAddU64(processedexpArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(processedexpArgs, PS_LIST_TAIL, "-faulted",  0,
            "only return imfiles with a fault status set", false);
    psMetadataAddBool(processedexpArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -revertprocessedexp
    psMetadata *revertprocessedexpArgs = psMetadataAlloc();
    psMetadataAddStr(revertprocessedexpArgs, PS_LIST_TAIL, "-det_id",  0,
            "search by detrend ID (required)", NULL);
    psMetadataAddStr(revertprocessedexpArgs, PS_LIST_TAIL, "-exp_id",  0,
            "search by exposure ID", NULL);
    psMetadataAddS16(revertprocessedexpArgs, PS_LIST_TAIL, "-code",  0,
            "search by fault code", 0);

    // -tostacked
    psMetadata *tostackedArgs = psMetadataAlloc();
    psMetadataAddU64(tostackedArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(tostackedArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -addstacked
    psMetadata *addstackedArgs = psMetadataAlloc();
    psMetadataAddStr(addstackedArgs, PS_LIST_TAIL, "-det_id",  0,
            "define detrend ID (required)", NULL);
    psMetadataAddS32(addstackedArgs, PS_LIST_TAIL, "-iteration",  0,
            "define iteration number", 0);
    psMetadataAddStr(addstackedArgs, PS_LIST_TAIL, "-class_id",  0,
            "define class ID (required)", NULL);
    psMetadataAddStr(addstackedArgs, PS_LIST_TAIL, "-recip",  0,
            "define recipe", NULL);
    psMetadataAddF64(addstackedArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposure background", NAN);
    psMetadataAddF64(addstackedArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposure background stdev", NAN);
    psMetadataAddF64(addstackedArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposure background mean stdev", NAN);
    psMetadataAddF64(addstackedArgs, PS_LIST_TAIL, "-user_1",  0,
            "define user statistic (1)", NAN);
    psMetadataAddF64(addstackedArgs, PS_LIST_TAIL, "-user_2",  0,
            "define user statistic (2)", NAN);
    psMetadataAddF64(addstackedArgs, PS_LIST_TAIL, "-user_3",  0,
            "define user statistic (3)", NAN);
    psMetadataAddF64(addstackedArgs, PS_LIST_TAIL, "-user_4",  0,
            "define user statistic (4)", NAN);
    psMetadataAddF64(addstackedArgs, PS_LIST_TAIL, "-user_5",  0,
            "define user statistic (5)", NAN);
    psMetadataAddStr(addstackedArgs, PS_LIST_TAIL, "-uri",  0,
            "define URI", NULL);
    psMetadataAddS16(addstackedArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code", 0);

    // -stacked
    psMetadata *stackedArgs = psMetadataAlloc();
    psMetadataAddStr(stackedArgs, PS_LIST_TAIL, "-det_id",  0,
            "search for detrend ID", NULL);
    psMetadataAddS32(stackedArgs, PS_LIST_TAIL, "-iteration",  0,
            "search for iteration number", 0);
    psMetadataAddStr(stackedArgs, PS_LIST_TAIL, "-class_id",  0,
            "search for class ID", NULL);
    psMetadataAddStr(stackedArgs, PS_LIST_TAIL, "-recip",  0,
            "search for recipe", NULL);
    psMetadataAddU64(stackedArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(stackedArgs, PS_LIST_TAIL, "-faulted",  0,
            "only return imfiles with a fault status set", false);
    psMetadataAddBool(stackedArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -revertstacked
    psMetadata *revertstackedArgs= psMetadataAlloc();
    psMetadataAddStr(revertstackedArgs, PS_LIST_TAIL, "-det_id",  0,
            "search for detrend ID (required)", NULL);
    psMetadataAddS32(revertstackedArgs, PS_LIST_TAIL, "-iteration",  0,
            "search by iteration number", 0);
    psMetadataAddStr(revertstackedArgs, PS_LIST_TAIL, "-class_id",  0,
            "search by class ID", NULL);
    psMetadataAddS16(revertstackedArgs, PS_LIST_TAIL, "-code",  0,
            "search by fault code", 0);

    // -tonormalize
    psMetadata *tonormalizeArgs = psMetadataAlloc();
    psMetadataAddU64(tonormalizeArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(tonormalizeArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -addnormalizedstat
    psMetadata *addnormstatArgs = psMetadataAlloc();
    psMetadataAddStr(addnormstatArgs, PS_LIST_TAIL, "-det_id",  0,
            "define detrend ID (required)", NULL);
    psMetadataAddS32(addnormstatArgs, PS_LIST_TAIL, "-iteration",  0,
            "define iteration number", 0);
    psMetadataAddStr(addnormstatArgs, PS_LIST_TAIL, "-class_id",  0,
            "define class ID (required)", NULL);
    psMetadataAddF32(addnormstatArgs, PS_LIST_TAIL, "-norm",  0,
            "define normal value (required)", NAN);
    psMetadataAddS16(addnormstatArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code", 0);

    // -normalizedstat
    psMetadata *normalizedstatArgs = psMetadataAlloc();
    psMetadataAddStr(normalizedstatArgs, PS_LIST_TAIL, "-det_id",  0,
            "search by detrend ID", NULL);
    psMetadataAddS32(normalizedstatArgs, PS_LIST_TAIL, "-iteration",  0,
            "search by iteration number", 0);
    psMetadataAddStr(normalizedstatArgs, PS_LIST_TAIL, "-class_id",  0,
            "search by class ID", NULL);
    psMetadataAddU64(normalizedstatArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(normalizedstatArgs, PS_LIST_TAIL, "-faulted",  0,
            "only return imfiles with a fault status set", false);
    psMetadataAddBool(normalizedstatArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -revertnormalizedstat
    psMetadata *revertnormalizedstatArgs= psMetadataAlloc();
    psMetadataAddStr(revertnormalizedstatArgs, PS_LIST_TAIL, "-det_id",  0,
            "search by detrend ID (required)", NULL);
    psMetadataAddS32(revertnormalizedstatArgs, PS_LIST_TAIL, "-iteration",  0,
            "search by iteration number", 0);
    psMetadataAddStr(revertnormalizedstatArgs, PS_LIST_TAIL, "-class_id",  0,
            "search by class ID", NULL);
    psMetadataAddS16(revertnormalizedstatArgs, PS_LIST_TAIL, "-code",  0,
            "search by fault code", 0);

    // -tonormstat
    psMetadata *tonormstatArgs = psMetadataAlloc();
    psMetadataAddU64(tonormstatArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(tonormstatArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -addnormalizedimfile
    psMetadata *addnormalizedimfileArgs = psMetadataAlloc();
    psMetadataAddStr(addnormalizedimfileArgs, PS_LIST_TAIL, "-det_id", 0,
            "define detrend ID (required)", NULL);
    psMetadataAddS32(addnormalizedimfileArgs, PS_LIST_TAIL, "-iteration", 0,
            "define iteration number", 0);
    psMetadataAddStr(addnormalizedimfileArgs, PS_LIST_TAIL, "-class_id", 0,
            "define class ID (required)", NULL);
    psMetadataAddStr(addnormalizedimfileArgs, PS_LIST_TAIL, "-uri", 0,
            "define URI", NULL);
    psMetadataAddF64(addnormalizedimfileArgs, PS_LIST_TAIL, "-bg", 0,
            "define exposure background", NAN);
    psMetadataAddF64(addnormalizedimfileArgs, PS_LIST_TAIL, "-bg_stdev", 0,
            "define exposure background stdev", NAN);
    psMetadataAddF64(addnormalizedimfileArgs, PS_LIST_TAIL, "-bg_mean_stdev", 0,
            "define exposure background mean stdev", NAN);
    psMetadataAddF64(addnormalizedimfileArgs, PS_LIST_TAIL, "-user_1",  0,
            "define user statistic (1)", NAN);
    psMetadataAddF64(addnormalizedimfileArgs, PS_LIST_TAIL, "-user_2",  0,
            "define user statistic (2)", NAN);
    psMetadataAddF64(addnormalizedimfileArgs, PS_LIST_TAIL, "-user_3",  0,
            "define user statistic (3)", NAN);
    psMetadataAddF64(addnormalizedimfileArgs, PS_LIST_TAIL, "-user_4",  0,
            "define user statistic (4)", NAN);
    psMetadataAddF64(addnormalizedimfileArgs, PS_LIST_TAIL, "-user_5",  0,
            "define user statistic (5)", NAN);
    psMetadataAddStr(addnormalizedimfileArgs, PS_LIST_TAIL, "-path_base", 0,
            "define base output location", NULL);
    psMetadataAddS16(addnormalizedimfileArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code", 0);

    // -normalizedimfile
    psMetadata *normalizedimfileArgs = psMetadataAlloc();
    psMetadataAddStr(normalizedimfileArgs, PS_LIST_TAIL, "-det_id",  0,
            "search for detrend ID", NULL);
    psMetadataAddS32(normalizedimfileArgs, PS_LIST_TAIL, "-iteration",  0,
            "search for iteration number", 0);
    psMetadataAddStr(normalizedimfileArgs, PS_LIST_TAIL, "-class_id",  0,
            "search for class ID", NULL);
    psMetadataAddStr(normalizedimfileArgs, PS_LIST_TAIL, "-recip",  0,
            "search for recipe", NULL);
    psMetadataAddU64(normalizedimfileArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(normalizedimfileArgs, PS_LIST_TAIL, "-faulted",  0,
            "only return imfiles with a fault status set", false);
    psMetadataAddBool(normalizedimfileArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -revertnormalizedimfile
    psMetadata *revertnormalizedimfileArgs = psMetadataAlloc();
    psMetadataAddStr(revertnormalizedimfileArgs, PS_LIST_TAIL, "-det_id", 0,
            "search by detrend ID (required)", NULL);
    psMetadataAddS32(revertnormalizedimfileArgs, PS_LIST_TAIL, "-iteration", 0,
            "search by iteration number", 0);
    psMetadataAddStr(revertnormalizedimfileArgs, PS_LIST_TAIL, "-class_id", 0,
            "search by class ID", NULL);
    psMetadataAddS16(revertnormalizedimfileArgs, PS_LIST_TAIL, "-code",  0,
            "search by fault code", 0);

    // -tonormalizedexp
    psMetadata *tonormalizedexpArgs = psMetadataAlloc();
    psMetadataAddU64(tonormalizedexpArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(tonormalizedexpArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -addnormalizedexp
    psMetadata *addnormalizedexpArgs = psMetadataAlloc();
    psMetadataAddStr(addnormalizedexpArgs, PS_LIST_TAIL, "-det_id",  0,
            "define detrend ID (required)", NULL);
    psMetadataAddS32(addnormalizedexpArgs, PS_LIST_TAIL, "-iteration",  0,
            "define iteration number", 0);
    psMetadataAddStr(addnormalizedexpArgs, PS_LIST_TAIL, "-recip",  0,
            "search for recipe", NULL);
    psMetadataAddF64(addnormalizedexpArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposure background", NAN);
    psMetadataAddF64(addnormalizedexpArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposure background stdev", NAN);
    psMetadataAddF64(addnormalizedexpArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposure background mean stdev", NAN);

    psMetadataAddF64(addnormalizedexpArgs, PS_LIST_TAIL, "-user_1",  0,
            "define user statistic (1)", NAN);
    psMetadataAddF64(addnormalizedexpArgs, PS_LIST_TAIL, "-user_2",  0,
            "define user statistic (2)", NAN);
    psMetadataAddF64(addnormalizedexpArgs, PS_LIST_TAIL, "-user_3",  0,
            "define user statistic (3)", NAN);
    psMetadataAddF64(addnormalizedexpArgs, PS_LIST_TAIL, "-user_4",  0,
            "define user statistic (4)", NAN);
    psMetadataAddF64(addnormalizedexpArgs, PS_LIST_TAIL, "-user_5",  0,
            "define user statistic (5)", NAN);

    psMetadataAddStr(addnormalizedexpArgs, PS_LIST_TAIL, "-path_base",  0,
            "define base output location", NULL);
    psMetadataAddS16(addnormalizedexpArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code", 0);

    // -normalizedexp
    psMetadata *normalizedexpArgs = psMetadataAlloc();
    psMetadataAddStr(normalizedexpArgs, PS_LIST_TAIL, "-det_id",  0,
            "define detrend ID", NULL);
    psMetadataAddS32(normalizedexpArgs, PS_LIST_TAIL, "-iteration",  0,
            "define iteration number", 0);
    psMetadataAddStr(normalizedexpArgs, PS_LIST_TAIL, "-recip",  0,
            "search for recipe", NULL);
    psMetadataAddF64(normalizedexpArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposure background", NAN);
    psMetadataAddF64(normalizedexpArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposure background stdev", NAN);
    psMetadataAddF64(normalizedexpArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposure background mean stdev", NAN);
    psMetadataAddStr(normalizedexpArgs, PS_LIST_TAIL, "-path_base",  0,
            "define base output location", NULL);
    psMetadataAddU64(normalizedexpArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(normalizedexpArgs, PS_LIST_TAIL, "-faulted",  0,
            "only return imfiles with a fault status set", false);
    psMetadataAddBool(normalizedexpArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -revertnormalizedexp
    psMetadata *revertnormalizedexpArgs = psMetadataAlloc();
    psMetadataAddStr(revertnormalizedexpArgs, PS_LIST_TAIL, "-det_id", 0,
            "search by detrend ID (required)", NULL);
    psMetadataAddS32(revertnormalizedexpArgs, PS_LIST_TAIL, "-iteration", 0,
            "search by iteration number", 0);
    psMetadataAddS16(revertnormalizedexpArgs, PS_LIST_TAIL, "-code",  0,
            "search by fault code", 0);

    // -toresidimfile
    psMetadata *toresidimfileArgs = psMetadataAlloc();
    psMetadataAddU64(toresidimfileArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(toresidimfileArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -toresidexp
    psMetadata *toresidexpArgs = psMetadataAlloc();
    psMetadataAddU64(toresidexpArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(toresidexpArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -addresidimfile
    psMetadata *addresidimfileArgs = psMetadataAlloc();
    psMetadataAddStr(addresidimfileArgs, PS_LIST_TAIL, "-det_id",  0,
            "define detrend ID (required)", NULL);
    psMetadataAddS32(addresidimfileArgs, PS_LIST_TAIL, "-iteration",  0,
            "define iteration number", 0);
    psMetadataAddStr(addresidimfileArgs, PS_LIST_TAIL, "-exp_id",  0,
            "define detrend ID (required)", NULL);
    psMetadataAddStr(addresidimfileArgs, PS_LIST_TAIL, "-class_id",  0,
            "define class ID (required)", NULL);
    psMetadataAddStr(addresidimfileArgs, PS_LIST_TAIL, "-uri",  0,
            "define resid file URI", NULL);
    psMetadataAddStr(addresidimfileArgs, PS_LIST_TAIL, "-recip",  0,
            "define recipe", NULL);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposure background", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposure background stdev", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposure background mean stdev", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-bg_skewness",  0,
            "define exposure background skewness", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-bg_kurtosis",  0,
            "define exposure background kurtosis", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-bin_stdev",  0,
            "define exposure background binned stdev", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-fringe_0",  0,
            "define fringe slope (0th term)", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-fringe_1",  0,
            "define fringe slope (1st term)", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-fringe_2",  0,
            "define fringe slope (2nd term)", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-fringe_resid_0",  0,
            "define fringe residual (0th term)", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-fringe_resid_1",  0,
            "define fringe residual (1st term)", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-fringe_resid_2",  0,
            "define fringe residual (2nd term)", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-user_1",  0,
            "define user statistic (1)", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-user_2",  0,
            "define user statistic (2)", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-user_3",  0,
            "define user statistic (3)", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-user_4",  0,
            "define user statistic (4)", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-user_5",  0,
            "define user statistic (5)", NAN);
    psMetadataAddStr(addresidimfileArgs, PS_LIST_TAIL, "-path_base",  0,
            "define base output location", NULL);
    psMetadataAddS16(addresidimfileArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code", 0);

    // -residimfile
    psMetadata *residimfileArgs = psMetadataAlloc();
    psMetadataAddStr(residimfileArgs, PS_LIST_TAIL, "-det_id",  0,
            "search for detrend ID", NULL);
    psMetadataAddS32(residimfileArgs, PS_LIST_TAIL, "-iteration",  0,
            "search for iteration number", 0);
    psMetadataAddStr(residimfileArgs, PS_LIST_TAIL, "-exp_id",  0,
            "define detrend ID", NULL);
    psMetadataAddStr(residimfileArgs, PS_LIST_TAIL, "-class_id",  0,
            "search for class ID", NULL);
    psMetadataAddStr(residimfileArgs, PS_LIST_TAIL, "-recip",  0,
            "search for recipe", NULL);
    psMetadataAddU64(residimfileArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(residimfileArgs, PS_LIST_TAIL, "-faulted",  0,
            "only return imfiles with a fault status set", false);
    psMetadataAddBool(residimfileArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);
    psMetadataAddStr(residimfileArgs, PS_LIST_TAIL, "-select_state",  0,
            "search for state", NULL);

    // -revertresidimfile
    psMetadata *revertresidimfileArgs =  psMetadataAlloc();
    psMetadataAddStr(revertresidimfileArgs, PS_LIST_TAIL, "-det_id", 0,
            "search by detrend ID (required)", NULL);
    psMetadataAddS32(revertresidimfileArgs, PS_LIST_TAIL, "-iteration", 0,
            "search by iteration number", 0);
    psMetadataAddStr(revertresidimfileArgs, PS_LIST_TAIL, "-exp_id",  0,
            "search by detrend ID", NULL);
    psMetadataAddStr(revertresidimfileArgs, PS_LIST_TAIL, "-class_id",  0,
            "search for class ID", NULL);
    psMetadataAddS16(revertresidimfileArgs, PS_LIST_TAIL, "-code",  0,
            "search by fault code", 0);

    // -addresidexp
    psMetadata *addresidexpArgs = psMetadataAlloc();
    psMetadataAddStr(addresidexpArgs, PS_LIST_TAIL, "-det_id",  0,
            "define detrend ID (required)", NULL);
    psMetadataAddS32(addresidexpArgs, PS_LIST_TAIL, "-iteration",  0,
            "define iteration number", 0);
    psMetadataAddStr(addresidexpArgs, PS_LIST_TAIL, "-exp_id",  0,
            "define detrend ID (required)", NULL);
    psMetadataAddStr(addresidexpArgs, PS_LIST_TAIL, "-recip",  0,
            "define recipe", NULL);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposure background", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposure background stdev", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposure background mean stdev", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-bg_skewness",  0,
            "define exposure background skewness", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-bg_kurtosis",  0,
            "define exposure background kurtosis", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-bin_stdev",  0,
            "define exposure background binned stdev", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-fringe_0",  0,
            "define fringe slope (0th term)", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-fringe_1",  0,
            "define fringe slope (1st term)", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-fringe_2",  0,
            "define fringe slope (2nd term)", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-fringe_resid_0",  0,
            "define fringe residual (0th term)", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-fringe_resid_1",  0,
            "define fringe residual (1st term)", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-fringe_resid_2",  0,
            "define fringe residual (2nd term)", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-user_1",  0,
            "define user statistic (1)", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-user_2",  0,
            "define user statistic (2)", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-user_3",  0,
            "define user statistic (3)", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-user_4",  0,
            "define user statistic (4)", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-user_5",  0,
            "define user statistic (5)", NAN);
    psMetadataAddStr(addresidexpArgs, PS_LIST_TAIL, "-path_base",  0,
            "define base output location", NULL);
    psMetadataAddS16(addresidexpArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code", 0);
    psMetadataAddBool(addresidexpArgs, PS_LIST_TAIL, "-reject",  0,
            "exposure is not to be stacked in the next iteration", false);

    // -residexp
    psMetadata *residexpArgs = psMetadataAlloc();
    psMetadataAddStr(residexpArgs, PS_LIST_TAIL, "-det_id",  0,
            "search for detrend ID", NULL);
    psMetadataAddS32(residexpArgs, PS_LIST_TAIL, "-iteration",  0,
            "search for iteration number", 0);
    psMetadataAddStr(residexpArgs, PS_LIST_TAIL, "-exp_id",  0,
            "search for exp ID", NULL);
    psMetadataAddStr(residexpArgs, PS_LIST_TAIL, "-recip",  0,
            "search for recipe", NULL);
    psMetadataAddU64(residexpArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);
    psMetadataAddBool(residexpArgs, PS_LIST_TAIL, "-faulted",  0,
            "only return imfiles with a fault status set", false);
    psMetadataAddBool(residexpArgs, PS_LIST_TAIL, "-reject",  0,
            "search for acceptable residuals", false);
    psMetadataAddBool(residexpArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -revertresidexp
    psMetadata *revertresidexpArgs = psMetadataAlloc();
    psMetadataAddStr(revertresidexpArgs, PS_LIST_TAIL, "-det_id", 0,
            "search by detrend ID (required)", NULL);
    psMetadataAddS32(revertresidexpArgs, PS_LIST_TAIL, "-iteration", 0,
            "search by iteration number", 0);
    psMetadataAddStr(revertresidexpArgs, PS_LIST_TAIL, "-exp_id",  0,
            "search by detrend ID", NULL);
    psMetadataAddS16(revertresidexpArgs, PS_LIST_TAIL, "-code",  0,
            "search by fault code", 0);

    // -todetrunsummary
    psMetadata *todetrunsummaryArgs = psMetadataAlloc();
    psMetadataAddBool(todetrunsummaryArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);
    psMetadataAddU64(todetrunsummaryArgs, PS_LIST_TAIL, "-limit",  0,
            "limit result set to N items", 0);

    // -updateresidexp
    psMetadata *updateresidexpArgs = psMetadataAlloc();
    psMetadataAddStr(updateresidexpArgs, PS_LIST_TAIL, "-det_id",  0,
            "define detrend ID", NULL);
    psMetadataAddS32(updateresidexpArgs, PS_LIST_TAIL, "-iteration",  0,
            "define iteration number", 0);
    psMetadataAddStr(updateresidexpArgs, PS_LIST_TAIL, "-exp_id",  0,
            "define exp ID", NULL);
    psMetadataAddStr(updateresidexpArgs, PS_LIST_TAIL, "-recip",  0,
            "define recipe", NULL);
    psMetadataAddF64(updateresidexpArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposure background", NAN);
    psMetadataAddF64(updateresidexpArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposure background stdev", NAN);
    psMetadataAddF64(updateresidexpArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposure background mean stdev", NAN);
    psMetadataAddStr(updateresidexpArgs, PS_LIST_TAIL, "-path_base",  0,
            "define base output location", NULL);
    psMetadataAddBool(updateresidexpArgs, PS_LIST_TAIL, "-reject",  0,
            "exposure is not to be stacked in the next iteration", false);

    // -adddetrunsummary
    psMetadata *adddetrunsummaryArgs = psMetadataAlloc();
    psMetadataAddStr(adddetrunsummaryArgs, PS_LIST_TAIL, "-det_id",  0,
            "define detrend ID (required)", NULL);
    psMetadataAddS32(adddetrunsummaryArgs, PS_LIST_TAIL, "-iteration",  0,
            "define iteration number", 0);
    psMetadataAddF64(adddetrunsummaryArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposure background", NAN);
    psMetadataAddF64(adddetrunsummaryArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposure background stdev", NAN);
    psMetadataAddF64(adddetrunsummaryArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposure background mean stdev", NAN);
    psMetadataAddS16(adddetrunsummaryArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code", 0);
    psMetadataAddBool(adddetrunsummaryArgs, PS_LIST_TAIL, "-accept",  0,
            "declare that this detrun iteration is accepted as a master", false);
    psMetadataAddBool(adddetrunsummaryArgs, PS_LIST_TAIL, "-again",  0,
            "start a new iteration of this detrend run", false);

    // -detrunsummary
    psMetadata *detrunsummaryArgs = psMetadataAlloc();
    psMetadataAddStr(detrunsummaryArgs, PS_LIST_TAIL, "-det_id",  0,
            "search for detrend ID", NULL);
    psMetadataAddU64(detrunsummaryArgs, PS_LIST_TAIL, "-limit",  0,
                     "limit result set to N items", 0);
    psMetadataAddS32(detrunsummaryArgs, PS_LIST_TAIL, "-iteration",  0,
            "search for iteration number", 0);
    psMetadataAddBool(detrunsummaryArgs, PS_LIST_TAIL, "-faulted",  0,
            "only return imfiles with a fault status set", false);
    psMetadataAddBool(detrunsummaryArgs, PS_LIST_TAIL, "-reject",  0,
            "search for acceptable residuals", false);
    psMetadataAddBool(detrunsummaryArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -revertdetrunsummary
    psMetadata *revertdetrunsummaryArgs = psMetadataAlloc();
    psMetadataAddStr(revertdetrunsummaryArgs, PS_LIST_TAIL, "-det_id", 0,
            "search by detrend ID (required)", NULL);
    psMetadataAddS32(revertdetrunsummaryArgs, PS_LIST_TAIL, "-iteration", 0,
            "search by iteration number", 0);
    psMetadataAddS16(revertdetrunsummaryArgs, PS_LIST_TAIL, "-code",  0,
            "search by fault code", 0);

    // -updatedetrun
    psMetadata *updatedetrunArgs = psMetadataAlloc();
    psMetadataAddStr(updatedetrunArgs, PS_LIST_TAIL, "-det_id",  0,
            "search for detrend master for detrend ID (required)", NULL);
    psMetadataAddBool(updatedetrunArgs, PS_LIST_TAIL, "-again",  0,
            "start a new iteration of this detrend run", false);
    psMetadataAddStr(updatedetrunArgs, PS_LIST_TAIL, "-state",  0,
            "set the state of this detrend run", false);

    // -rerun
    psMetadata *rerunArgs = psMetadataAlloc();
    psMetadataAddStr(rerunArgs, PS_LIST_TAIL, "-det_id",  0,
            "search for detrend master for detrend ID (required)", NULL);
    psMetadataAddStr(rerunArgs, PS_LIST_TAIL, "-exp_id",  PS_META_DUPLICATE_OK,
            "include this exposure (multiple OK, required)", NULL);

    // -register_detrend
    psMetadata *register_detrendArgs = psMetadataAlloc();
    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-det_type",  0,
            "define the type of detrend run (required)", NULL);
    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-mode",  0,
            "define the mode of this detrend run", "master");
    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-filelevel",  0,
            "define filelevel (required)", NULL);
    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-workdir",  0,
            "define workdir", NULL);
    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-inst",  0,
            "define camera", NULL);
    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-telescope",  0,
            "define telescope", NULL);
    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-exp_type",  0,
            "define exposure type", NULL);
    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-filter",  0,
            "define filter ", NULL);
    psMetadataAddF32(register_detrendArgs, PS_LIST_TAIL, "-airmass_min",  0,
            "define min airmass", NAN);
    psMetadataAddF32(register_detrendArgs, PS_LIST_TAIL, "-airmass_max",  0,
            "define max airmass", NAN);
    psMetadataAddF32(register_detrendArgs, PS_LIST_TAIL, "-exp_time_min",  0,
            "define min exposure time", NAN);
    psMetadataAddF32(register_detrendArgs, PS_LIST_TAIL, "-exp_time_max",  0,
            "define max exposure time", NAN);
    psMetadataAddF64(register_detrendArgs, PS_LIST_TAIL, "-ccd_temp_min",  0,
            "define min ccd tempature", NAN);
    psMetadataAddF64(register_detrendArgs, PS_LIST_TAIL, "-ccd_temp_max",  0,
            "define max ccd tempature", NAN);
    psMetadataAddF64(register_detrendArgs, PS_LIST_TAIL, "-posang_min",  0,
            "define min rotator position angle", NAN);
    psMetadataAddF64(register_detrendArgs, PS_LIST_TAIL, "-posang_max",  0,
            "define max rotator position angle", NAN);
    psMetadataAddF64(register_detrendArgs, PS_LIST_TAIL, "-solang_min",  0,
            "define min solar angle", NAN);
    psMetadataAddF64(register_detrendArgs, PS_LIST_TAIL, "-solang_max",  0,
            "define max solar angle", NAN);
    psMetadataAddTime(register_detrendArgs, PS_LIST_TAIL, "-registered",  0,
            "time detrend run was registered", now);
    psMetadataAddTime(register_detrendArgs, PS_LIST_TAIL, "-time_begin",  0,
            "detrend applies to exposures taken during this period", NULL);
    psMetadataAddTime(register_detrendArgs, PS_LIST_TAIL, "-time_end",  0,
            "detrend applies to exposures taken during this period", NULL);
    psMetadataAddTime(register_detrendArgs, PS_LIST_TAIL, "-use_begin",  0,
            "start of detrend run applicable period", NULL);
    psMetadataAddTime(register_detrendArgs, PS_LIST_TAIL, "-use_end",  0,
            "end of detrend run applicable period", NULL);
    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-parent",  0,
            "define parent det_id", NULL);
    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-label",  0,
            "define detrun label", NULL);
    psMetadataAddBool(register_detrendArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);

    // -register_detrend_imfile
    psMetadata *register_detrend_imfileArgs = psMetadataAlloc();
    psMetadataAddStr(register_detrend_imfileArgs, PS_LIST_TAIL, "-det_id",  0,
            "define detrend ID (required)", NULL);
    psMetadataAddStr(register_detrend_imfileArgs, PS_LIST_TAIL, "-class_id",  0,
            "search for class ID (required)", NULL);
    psMetadataAddStr(register_detrend_imfileArgs, PS_LIST_TAIL, "-uri",  0,
            "define resid file URI (required)", NULL);
    psMetadataAddF64(register_detrend_imfileArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposure background", NAN);
    psMetadataAddF64(register_detrend_imfileArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposure background stdev", NAN);
    psMetadataAddF64(register_detrend_imfileArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposure background mean stdev", NAN);
    psMetadataAddF64(register_detrend_imfileArgs, PS_LIST_TAIL, "-user_1",  0,
            "define user statistic (1)", NAN);
    psMetadataAddF64(register_detrend_imfileArgs, PS_LIST_TAIL, "-user_2",  0,
            "define user statistic (2)", NAN);
    psMetadataAddF64(register_detrend_imfileArgs, PS_LIST_TAIL, "-user_3",  0,
            "define user statistic (3)", NAN);
    psMetadataAddF64(register_detrend_imfileArgs, PS_LIST_TAIL, "-user_4",  0,
            "define user statistic (4)", NAN);
    psMetadataAddF64(register_detrend_imfileArgs, PS_LIST_TAIL, "-user_5",  0,
            "define user statistic (5)", NAN);
    psMetadataAddStr(register_detrend_imfileArgs, PS_LIST_TAIL, "-path_base",  0,
            "define base output location", NULL);

    psFree(now);

    psMetadata *argSets = psMetadataAlloc();
    psMetadata *modes = psMetadataAlloc();

    PXOPT_ADD_MODE("-pending",         "list active detruns", DETTOOL_MODE_PENDING,       pendingArgs);
    PXOPT_ADD_MODE("-definebytag",     "", DETTOOL_MODE_DEFINEBYTAG,   definebytagArgs);
    PXOPT_ADD_MODE("-definebyquery",   "", DETTOOL_MODE_DEFINEBYQUERY, definebyqueryArgs);
    PXOPT_ADD_MODE("-definebydetrun",  "", DETTOOL_MODE_DEFINEBYDETRUN, definebydetrunArgs);
    PXOPT_ADD_MODE("-makecorrection",  "", DETTOOL_MODE_MAKECORRECTION, makecorrectionArgs);
    PXOPT_ADD_MODE("-tocorrectexp",    "", DETTOOL_MODE_TOCORRECTEXP, tocorrectexpArgs);
    PXOPT_ADD_MODE("-tocorrectimfile", "", DETTOOL_MODE_TOCORRECTIMFILE, tocorrectimfileArgs);
    PXOPT_ADD_MODE("-addcorrectimfile", "", DETTOOL_MODE_ADDCORRECTIMFILE, addcorrectimfileArgs);
    PXOPT_ADD_MODE("-raw",             "", DETTOOL_MODE_RAW,           rawArgs);
    PXOPT_ADD_MODE("-runs",            "", DETTOOL_MODE_RUNS,          runsArgs);
    PXOPT_ADD_MODE("-childlessrun",    "", DETTOOL_MODE_CHILDLESSRUN,  childlessrunArgs);
    PXOPT_ADD_MODE("-input",           "", DETTOOL_MODE_INPUT,         inputArgs);
    PXOPT_ADD_MODE("-toprocessedimfile", "", DETTOOL_MODE_TOPROCESSEDIMFILE, toprocessedimfileArgs);
    PXOPT_ADD_MODE("-addprocessedimfile", "", DETTOOL_MODE_ADDPROCESSEDIMFILE,  addprocessedimfileArgs);
    PXOPT_ADD_MODE("-processedimfile", "", DETTOOL_MODE_PROCESSEDIMFILE, processedimfileArgs);
    PXOPT_ADD_MODE("-revertprocessedimfile", "", DETTOOL_MODE_REVERTPROCESSEDIMFILE, revertprocessedimfileArgs);
    PXOPT_ADD_MODE("-toprocessedexp",  "", DETTOOL_MODE_TOPROCESSEDEXP,  toprocessedexpArgs);
    PXOPT_ADD_MODE("-addprocessedexp", "", DETTOOL_MODE_ADDPROCESSEDEXP, addprocessedexpArgs);
    PXOPT_ADD_MODE("-revertprocessedexp", "", DETTOOL_MODE_REVERTPROCESSEDEXP, revertprocessedexpArgs);
    PXOPT_ADD_MODE("-processedexp",    "", DETTOOL_MODE_PROCESSEDEXP, processedexpArgs);
    PXOPT_ADD_MODE("-tostacked",       "", DETTOOL_MODE_TOSTACKED,     tostackedArgs);
    PXOPT_ADD_MODE("-addstacked",      "", DETTOOL_MODE_ADDSTACKED,    addstackedArgs);
    PXOPT_ADD_MODE("-stacked",         "", DETTOOL_MODE_STACKED,       stackedArgs);
    PXOPT_ADD_MODE("-revertstacked",   "", DETTOOL_MODE_REVERTSTACKED,  revertstackedArgs);
    PXOPT_ADD_MODE("-tonormalize",     "", DETTOOL_MODE_TONORMALIZE,   tonormalizeArgs);
    PXOPT_ADD_MODE("-addnormalizedstat",     "", DETTOOL_MODE_ADDNORMALIZEDSTAT,   addnormstatArgs);
    PXOPT_ADD_MODE("-normalizedstat",  "", DETTOOL_MODE_NORMALIZEDSTAT,   normalizedstatArgs);
    PXOPT_ADD_MODE("-revertnormalizedstat",  "", DETTOOL_MODE_REVERTNORMALIZEDSTAT,   revertnormalizedstatArgs);

    PXOPT_ADD_MODE("-tonormalizedstat",      "", DETTOOL_MODE_TONORMALIZEDSTAT,    tonormstatArgs);
    PXOPT_ADD_MODE("-addnormalizedimfile", "", DETTOOL_MODE_ADDNORMALIZEDIMFILE,addnormalizedimfileArgs);
    PXOPT_ADD_MODE("-normalizedimfile","", DETTOOL_MODE_NORMALIZEDIMFILE, normalizedimfileArgs);
    PXOPT_ADD_MODE("-revertnormalizedimfile","", DETTOOL_MODE_REVERTNORMALIZEDIMFILE, revertnormalizedimfileArgs);
    PXOPT_ADD_MODE("-tonormalizedexp", "", DETTOOL_MODE_TONORMALIZEDEXP, tonormalizedexpArgs);
    PXOPT_ADD_MODE("-addnormalizedexp", "", DETTOOL_MODE_ADDNORMALIZEDEXP, addnormalizedexpArgs);
    PXOPT_ADD_MODE("-normalizedexp",   "", DETTOOL_MODE_NORMALIZEDEXP, normalizedexpArgs);
    PXOPT_ADD_MODE("-revertnormalizedexp","", DETTOOL_MODE_REVERTNORMALIZEDEXP, revertnormalizedexpArgs);
    PXOPT_ADD_MODE("-toresidimfile",   "", DETTOOL_MODE_TORESIDIMFILE, toresidimfileArgs);
    PXOPT_ADD_MODE("-addresidimfile",  "", DETTOOL_MODE_ADDRESIDIMFILE, addresidimfileArgs);
    PXOPT_ADD_MODE("-residimfile",     "", DETTOOL_MODE_RESIDIMFILE, residimfileArgs);
    PXOPT_ADD_MODE("-revertresidimfile", "", DETTOOL_MODE_REVERTRESIDIMFILE, revertresidimfileArgs);
    PXOPT_ADD_MODE("-toresidexp",      "", DETTOOL_MODE_TORESIDEXP,    toresidexpArgs);
    PXOPT_ADD_MODE("-addresidexp",     "", DETTOOL_MODE_ADDRESIDEXP,  addresidexpArgs);
    PXOPT_ADD_MODE("-residexp",        "", DETTOOL_MODE_RESIDEXP,     residexpArgs);
    PXOPT_ADD_MODE("-revertresidexp",  "", DETTOOL_MODE_REVERTRESIDEXP, revertresidexpArgs);
    PXOPT_ADD_MODE("-todetrunsummary",  "", DETTOOL_MODE_TODETRUNSUMMARY,  todetrunsummaryArgs);
    PXOPT_ADD_MODE("-updateresidexp", "", DETTOOL_MODE_UPDATERESIDEXP,updateresidexpArgs);
    PXOPT_ADD_MODE("-adddetrunsummary", "", DETTOOL_MODE_ADDDETRUNSUMMARY,adddetrunsummaryArgs);
    PXOPT_ADD_MODE("-detrunsummary", "", DETTOOL_MODE_DETRUNSUMMARY,detrunsummaryArgs);
    PXOPT_ADD_MODE("-revertdetrunsummary", "", DETTOOL_MODE_REVERTDETRUNSUMMARY, revertdetrunsummaryArgs);
    PXOPT_ADD_MODE("-updatedetrun", "", DETTOOL_MODE_UPDATEDETRUN, updatedetrunArgs);
    PXOPT_ADD_MODE("-rerun",           "", DETTOOL_MODE_RERUN,         rerunArgs);
    PXOPT_ADD_MODE("-register_detrend", "", DETTOOL_MODE_REGISTER_DETREND, register_detrendArgs);
    PXOPT_ADD_MODE("-register_detrend_imfile", "", DETTOOL_MODE_REGISTER_DETREND_IMFILE, register_detrend_imfileArgs);

    if (!pxGetOptions(stderr, argc, argv, config, modes, argSets)) {
        psError(PS_ERR_UNKNOWN, false, "option parsing failed");
        psFree(argSets);
        psFree(modes);
        psFree(config);
        return NULL;
    }

    psFree(argSets);
    psFree(modes);

    // setup search criterion
#define addWhereStr(name) \
{ \
    psString str = NULL; \
    bool status = false; \
    if ((str = psMetadataLookupStr(&status, config->args, "-" #name))) { \
        if (!psMetadataAddStr(config->where, PS_LIST_TAIL, #name, 0, "==", str)) {\
            psError(PS_ERR_UNKNOWN, false, "failed to add item " #name); \
            psFree(config); \
            return NULL; \
        } \
    } \
}

    // generate SQL where clause
    config->where = psMetadataAlloc();

    addWhereStr(det_id);
    {
        // XXX this is broke because you can't specify -iteration 0
        psMetadataItem *item = psMetadataLookup(config->args, "-iteration");
        if (item && psStrcasestr(item->comment, "found")) {
            if (!psMetadataAddS32(config->where, PS_LIST_TAIL, "iteration", 0, "==", item->data.S32)) {
                psError(PS_ERR_UNKNOWN, false, "failed to add item iteration");
                psFree(config);
                return NULL;
            }
        }
    }
    addWhereStr(det_type);
    addWhereStr(exp_id);
    addWhereStr(class_id);
    // convert '-inst' to 'camera'
    {
        psString str = NULL;
        bool status = false;
        if ((str = psMetadataLookupStr(&status, config->args, "-inst"))) {
            if (!psMetadataAddStr(config->where, PS_LIST_TAIL, "camera", 0, "==", str)) {
                psError(PS_ERR_UNKNOWN, false, "failed to add item camera");
                psFree(config);
                return NULL;
            }
        }
    }
    addWhereStr(telescope);
    addWhereStr(exp_type);
    {
        int n = 0;
        bool status = false;
        if ((n = psMetadataLookupS32(&status, config->args, "-imfiles"))) {
            if (!psMetadataAddS32(config->where, PS_LIST_TAIL, "imfiles", 0, "==", n)) {
                psError(PS_ERR_UNKNOWN, false, "failed to add item imfiles");
                psFree(config);
                return NULL;
            }
        }
    }
    addWhereStr(filter);
    addWhereStr(recipe);
    {
        int n = 0;
        bool status = false;
        if ((n = psMetadataLookupS32(&status, config->args, "-guide_version"))) {
            if (!psMetadataAddS32(config->where, PS_LIST_TAIL, "guide_version", 0, "==", n)) {
                psError(PS_ERR_UNKNOWN, false, "failed to add item guide_version");
                psFree(config);
                return NULL;
            }
        }
    }
    {
        bool boolean = false;
        bool status = false;

        // map reject -> !accept
        if ((boolean = psMetadataLookupBool(&status, config->args, "-reject"))) {
            if (!psMetadataAddBool(config->where, PS_LIST_TAIL, "accept", 0, "==", !boolean)) {
                psError(PS_ERR_UNKNOWN, false, "failed to add item reject");
                psFree(config);
                return NULL;
            }
        }
    }

    // convert '-code' to 'fault'
    {
        psS16 fault = 0;
        bool status = false;
        if ((fault = psMetadataLookupS16(&status, config->args, "-code"))) {
            if (!psMetadataAddS16(config->where, PS_LIST_TAIL, "fault", 0, "==", fault)) {
                psError(PS_ERR_UNKNOWN, false, "failed to add item fault");
                psFree(config);
                return NULL;
            }
        }
    }

    if (config->where->list->n < 1) {
        psFree(config->where);
        config->where = NULL;
    }

    // define Database handle, if used
    // do this last so we don't setup a connection before CLI options are
    // validated
    config->dbh = pmConfigDB(config->modules);
    if (!config->dbh) {
        psError(PS_ERR_UNKNOWN, false, "Can't configure database");
        psFree(config);
        return NULL;
    }

    return config;
}
