/*
 * 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 *time = psTimeGetNow(PS_TIME_TAI);
    psString now = psTimeToISO(time);
    psFree(time);

    // -pending
    psMetadata *pendingArgs = psMetadataAlloc();
    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-exp_tag",  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_tag",
            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 (required)", 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);
    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-registered",  0,
            "time detrend run was registered", now);
    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-time_begin",  0,
            "detrend applyes to exposures taken during this peroid", NULL);
    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-time_end",  0,
            "detrend applyes to exposures taken during this peroid", NULL);
    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-use_begin",  0,
            "start of detrend run applicable peroid", NULL);
    psMetadataAddStr(definebytagArgs, PS_LIST_TAIL, "-use_end",  0,
            "end of detrend run applicable peroid", 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 (required)", NULL);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-workdir",  0,
            "define workdir (required)", NULL);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-inst",  0,
            "define camera", 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);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-registered",  0,
            "time detrend run was registered", now);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-time_begin",  0,
            "detrend applyes to exposures taken during this peroid", NULL);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-time_end",  0,
            "detrend applyes to exposures taken during this peroid", NULL);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-use_begin",  0,
            "start of detrend run applicable peroid", NULL);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-use_end",  0,
            "end of detrend run applicable peroid", 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);
    psMetadataAddStr(definebyqueryArgs, PS_LIST_TAIL, "-select_dateobs_begin", 0,
            "search for exposures by time (>=)", NULL);
    psMetadataAddStr(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_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);
    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, "-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 (required)", 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);
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-set_registered",  0,
            "time detrend run was registered", now);
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-set_time_begin",  0,
            "start of peroid to apply detrend too", NULL);
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-set_time_end",  0,
            "end of peroid to apply detrend too", NULL);
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-set_use_begin",  0,
            "start of detrend run applicable peroid", NULL);
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-set_use_end",  0,
            "end of detrend run applicable peroid", NULL);
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-filter_input_begin", 0,
            "filter input detrun exp to be in this peroid", NULL);
    psMetadataAddStr(definebydetrunArgs, PS_LIST_TAIL, "-filter_input_end", 0,
            "filter input detrun exp to be in this peroid", 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);

    // -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);

    // -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_tag",  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_tag",  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_tag",  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 (required)", NULL);
    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-recip",  0,
            "define recipe (required)", NULL);
    psMetadataAddF64(addprocessedimfileArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposue background", NAN);
    psMetadataAddF64(addprocessedimfileArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposue background stdev", NAN);
    psMetadataAddF64(addprocessedimfileArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposue background mean stdev", NAN);
    psMetadataAddStr(addprocessedimfileArgs, PS_LIST_TAIL, "-path_base",  0,
            "define banana 1", NULL);
    psMetadataAddS8(addprocessedimfileArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code (required)", 0);

    // -processedimfile
    psMetadata *processedimfileArgs = psMetadataAlloc();
    psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-det_id",  0,
            "search for detrend ID", NULL);
    psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-exp_tag",  0,
            "search for exp ID", NULL);
    psMetadataAddStr(processedimfileArgs, PS_LIST_TAIL, "-class_id",  0,
            "search for class ID", 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);

    // -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_tag",  0,
            "define detrend ID (required)", NULL);
    psMetadataAddStr(addprocessedexpArgs, PS_LIST_TAIL, "-recip",  0,
            "define recipe (required)", NULL);
    psMetadataAddF64(addprocessedexpArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposue background", NAN);
    psMetadataAddF64(addprocessedexpArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposue background stdev", NAN);
    psMetadataAddF64(addprocessedexpArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposue background mean stdev", NAN);
    psMetadataAddStr(addprocessedexpArgs, PS_LIST_TAIL, "-path_base",  0,
            "define banana 1", NULL);
    psMetadataAddS8(addprocessedexpArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code (required)", 0);

    // -proccessedexp
    psMetadata *processedexpArgs = psMetadataAlloc();
    psMetadataAddStr(processedexpArgs, PS_LIST_TAIL, "-det_id",  0,
            "define detrend ID (required)", NULL);
    psMetadataAddStr(processedexpArgs, PS_LIST_TAIL, "-exp_tag",  0,
            "define detrend ID (required)", 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);

    // -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 (required)", NULL);
    psMetadataAddF64(addstackedArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposue background", NAN);
    psMetadataAddF64(addstackedArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposue background stdev", NAN);
    psMetadataAddF64(addstackedArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposue background mean stdev", NAN);
    psMetadataAddStr(addstackedArgs, PS_LIST_TAIL, "-uri",  0,
            "define URI (required)", NULL);
    psMetadataAddS8(addstackedArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code (required)", 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);

    // -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);

    // -addnormstat
    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", NULL);
    psMetadataAddF32(addnormstatArgs, PS_LIST_TAIL, "-norm",  0,
            "define normal value (required)", NAN);
    psMetadataAddS8(addnormstatArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code (required)", 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 (required)", NULL);
    psMetadataAddF64(addnormalizedimfileArgs, PS_LIST_TAIL, "-bg", 0,
            "define exposue background", NAN);
    psMetadataAddF64(addnormalizedimfileArgs, PS_LIST_TAIL, "-bg_stdev", 0,
            "define exposue background stdev", NAN);
    psMetadataAddF64(addnormalizedimfileArgs, PS_LIST_TAIL, "-bg_mean_stdev", 0,
            "define exposue background mean stdev", NAN);
    psMetadataAddStr(addnormalizedimfileArgs, PS_LIST_TAIL, "-path_base", 0,
            "define banana 1", NULL);
    psMetadataAddS8(addnormalizedimfileArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code (required)", 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 exposue background", NAN);
    psMetadataAddF64(addnormalizedexpArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposue background stdev", NAN);
    psMetadataAddF64(addnormalizedexpArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposue background mean stdev", NAN);
    psMetadataAddStr(addnormalizedexpArgs, PS_LIST_TAIL, "-path_base",  0,
            "define banana 1", NULL);
    psMetadataAddS8(addnormalizedexpArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code (required)", 0);

    // -normalizedexp
    psMetadata *normalizedexpArgs = psMetadataAlloc();
    psMetadataAddStr(normalizedexpArgs, PS_LIST_TAIL, "-det_id",  0,
            "define detrend ID (required)", 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 exposue background", NAN);
    psMetadataAddF64(normalizedexpArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposue background stdev", NAN);
    psMetadataAddF64(normalizedexpArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposue background mean stdev", NAN);
    psMetadataAddStr(normalizedexpArgs, PS_LIST_TAIL, "-path_base",  0,
            "define banana 1", 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);

    // -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);

    // -normalizedimfile
    psMetadata *normalizedimfileArgs = psMetadataAlloc();
    psMetadataAddStr(normalizedimfileArgs, PS_LIST_TAIL, "-det_id",  0,
            "search for detrend ID (required)", 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);

    // -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_tag",  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 (required)", NULL);
    psMetadataAddStr(addresidimfileArgs, PS_LIST_TAIL, "-recip",  0,
            "define recipe (required)", NULL);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposue background", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposue background stdev", NAN);
    psMetadataAddF64(addresidimfileArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposue background mean stdev", NAN);
    psMetadataAddStr(addresidimfileArgs, PS_LIST_TAIL, "-path_base",  0,
            "define banana 1", NULL);
    psMetadataAddS8(addresidimfileArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code (required)", 0);

    // -residimfile
    psMetadata *residimfileArgs = psMetadataAlloc();
    psMetadataAddStr(residimfileArgs, PS_LIST_TAIL, "-det_id",  0,
            "search for detrend ID (required)", NULL);
    psMetadataAddS32(residimfileArgs, PS_LIST_TAIL, "-iteration",  0,
            "search for iteration number", 0);
    psMetadataAddStr(residimfileArgs, PS_LIST_TAIL, "-exp_tag",  0,
            "define detrend ID (required)", 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);

    // -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_tag",  0,
            "define detrend ID (required)", NULL);
    psMetadataAddStr(addresidexpArgs, PS_LIST_TAIL, "-recip",  0,
            "define recipe (required)", NULL);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposue background", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposue background stdev", NAN);
    psMetadataAddF64(addresidexpArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposue background mean stdev", NAN);
    psMetadataAddStr(addresidexpArgs, PS_LIST_TAIL, "-path_base",  0,
            "define banana 1", NULL);
    psMetadataAddS8(addresidexpArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code (required)", 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 (required)", NULL);
    psMetadataAddS32(residexpArgs, PS_LIST_TAIL, "-iteration",  0,
            "search for iteration number", 0);
    psMetadataAddStr(residexpArgs, PS_LIST_TAIL, "-exp_tag",  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);

    // -residdetrun
    psMetadata *residdetrunArgs = psMetadataAlloc();
    psMetadataAddBool(residdetrunArgs, PS_LIST_TAIL, "-simple",  0,
            "use the simple output format", false);
    psMetadataAddU64(residdetrunArgs, 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_tag",  0,
            "define exp ID", NULL);
    psMetadataAddStr(updateresidexpArgs, PS_LIST_TAIL, "-recip",  0,
            "define recipe", NULL);
    psMetadataAddF64(updateresidexpArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposue background", NAN);
    psMetadataAddF64(updateresidexpArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposue background stdev", NAN);
    psMetadataAddF64(updateresidexpArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposue background mean stdev", NAN);
    psMetadataAddStr(updateresidexpArgs, PS_LIST_TAIL, "-path_base",  0,
            "define banana 1", 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 exposue background", NAN);
    psMetadataAddF64(adddetrunsummaryArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposue background stdev", NAN);
    psMetadataAddF64(adddetrunsummaryArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposue background mean stdev", NAN);
    psMetadataAddS8(adddetrunsummaryArgs, PS_LIST_TAIL, "-code",  0,
            "set fault code (required)", 0);
    psMetadataAddBool(adddetrunsummaryArgs, PS_LIST_TAIL, "-accept",  0,
            "declare that this detrun iteration is accepted as a master", false);

    // -detrunsummary
    psMetadata *detrunsummaryArgs = psMetadataAlloc();
    psMetadataAddStr(detrunsummaryArgs, PS_LIST_TAIL, "-det_id",  0,
            "search for detrend ID", NULL);
    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);

    // -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_tag",  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 (required)", 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);
    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-registered",  0,
            "time detrend run was registered", now);
    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-time_begin",  0,
            "detrend applyes to exposures taken during this peroid", NULL);
    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-time_end",  0,
            "detrend applyes to exposures taken during this peroid", NULL);
    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-use_begin",  0,
            "start of detrend run applicable peroid", NULL);
    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-use_end",  0,
            "end of detrend run applicable peroid", NULL);
    psMetadataAddF64(register_detrendArgs, PS_LIST_TAIL, "-bg",  0,
            "define exposue background", NAN);
    psMetadataAddF64(register_detrendArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposue background stdev", NAN);
    psMetadataAddF64(register_detrendArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposue background mean stdev", NAN);
    psMetadataAddStr(register_detrendArgs, PS_LIST_TAIL, "-parent",  0,
            "define parent det_id", 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 exposue background", NAN);
    psMetadataAddF64(register_detrend_imfileArgs, PS_LIST_TAIL, "-bg_stdev",  0,
            "define exposue background stdev", NAN);
    psMetadataAddF64(register_detrend_imfileArgs, PS_LIST_TAIL, "-bg_mean_stdev",  0,
            "define exposue background mean stdev", NAN);
    psMetadataAddStr(register_detrend_imfileArgs, PS_LIST_TAIL, "-path_base",  0,
            "define banana 1", NULL);

    psFree(now);


#define PXTOOL_MODE(option, modeval, argset) \
{ \
    int N = 0; \
    if ((N = psArgumentGet (argc, argv, option))) { \
        psArgumentRemove (N, &argc, argv); \
        if (config->mode) { \
            psError(PS_ERR_UNKNOWN, true, "only one mode selection is allowed"); \
            psFree(argset); \
            psFree(argSets); \
            psFree(config); \
            return NULL; \
        } \
        config->mode = modeval; \
        config->args = psMemIncrRefCounter(argset); \
    } \
    if (!psMetadataAddMetadata(argSets, PS_LIST_TAIL, option, 0, NULL, argset)) {;\
        psError(PS_ERR_UNKNOWN, false, "failed to add argset for %s", option); \
    } \
    psFree(argset); \
}

    psMetadata *argSets = psMetadataAlloc();
    // find which mode we're running under
    PXTOOL_MODE("-pending",         DETTOOL_MODE_PENDING,       pendingArgs);
    PXTOOL_MODE("-definebytag",     DETTOOL_MODE_DEFINEBYTAG,   definebytagArgs);
    PXTOOL_MODE("-definebyquery",   DETTOOL_MODE_DEFINEBYQUERY, definebyqueryArgs);
    PXTOOL_MODE("-definebydetrun",  DETTOOL_MODE_DEFINEBYDETRUN, definebydetrunArgs);
    PXTOOL_MODE("-raw",             DETTOOL_MODE_RAW,           rawArgs);
    PXTOOL_MODE("-runs",            DETTOOL_MODE_RUNS,          runsArgs);
    PXTOOL_MODE("-childlessrun",    DETTOOL_MODE_CHILDLESSRUN,  childlessrunArgs);
    PXTOOL_MODE("-input",           DETTOOL_MODE_INPUT,         inputArgs);
    PXTOOL_MODE("-toprocessedimfile", DETTOOL_MODE_TOPROCESSEDIMFILE, toprocessedimfileArgs);
    PXTOOL_MODE("-addprocessedimfile", DETTOOL_MODE_ADDPROCESSEDIMFILE,  addprocessedimfileArgs);
    PXTOOL_MODE("-processedimfile", DETTOOL_MODE_PROCESSEDIMFILE, processedimfileArgs);
    PXTOOL_MODE("-toprocessedexp",  DETTOOL_MODE_TOPROCESSEDEXP,  toprocessedexpArgs);
    PXTOOL_MODE("-addprocessedexp", DETTOOL_MODE_ADDPROCESSEDEXP, addprocessedexpArgs);
    PXTOOL_MODE("-processedexp",    DETTOOL_MODE_PROCESSEDEXP, processedexpArgs);
    PXTOOL_MODE("-tostacked",       DETTOOL_MODE_TOSTACKED,     tostackedArgs);
    PXTOOL_MODE("-addstacked",      DETTOOL_MODE_ADDSTACKED,    addstackedArgs);
    PXTOOL_MODE("-stacked",         DETTOOL_MODE_STACKED,       stackedArgs);
    PXTOOL_MODE("-tonormalize",     DETTOOL_MODE_TONORMALIZE,   tonormalizeArgs);
    PXTOOL_MODE("-addnormalizedstat",     DETTOOL_MODE_ADDNORMALIZEDSTAT,   addnormstatArgs);
    PXTOOL_MODE("-tonormalizedstat",      DETTOOL_MODE_TONORMALIZEDSTAT,    tonormstatArgs);
    PXTOOL_MODE("-addnormalizedimfile", DETTOOL_MODE_ADDNORMALIZEDIMFILE,addnormalizedimfileArgs);
    PXTOOL_MODE("-normalizedimfile",DETTOOL_MODE_NORMALIZEDIMFILE, normalizedimfileArgs);
    PXTOOL_MODE("-tonormalizedexp", DETTOOL_MODE_TONORMALIZEDEXP, tonormalizedexpArgs);
    PXTOOL_MODE("-addnormalizedexp", DETTOOL_MODE_ADDNORMALIZEDEXP, addnormalizedexpArgs);
    PXTOOL_MODE("-normalizedexp",   DETTOOL_MODE_NORMALIZEDEXP, normalizedexpArgs);
    PXTOOL_MODE("-toresidimfile",   DETTOOL_MODE_TORESIDIMFILE, toresidimfileArgs);
    PXTOOL_MODE("-addresidimfile",  DETTOOL_MODE_ADDRESIDIMFILE,  addresidimfileArgs);
    PXTOOL_MODE("-residimfile",     DETTOOL_MODE_RESIDIMFILE,    residimfileArgs);
    PXTOOL_MODE("-toresidexp",      DETTOOL_MODE_TORESIDEXP,    toresidexpArgs);
    PXTOOL_MODE("-addresidexp",     DETTOOL_MODE_ADDRESIDEXP,  addresidexpArgs);
    PXTOOL_MODE("-residexp",        DETTOOL_MODE_RESIDEXP,     residexpArgs);
    PXTOOL_MODE("-residdetrun",     DETTOOL_MODE_RESIDDETRUN,  residdetrunArgs);
    PXTOOL_MODE("-updateresidexp", DETTOOL_MODE_UPDATERESIDEXP,updateresidexpArgs);
    PXTOOL_MODE("-adddetrunsummary", DETTOOL_MODE_ADDDETRUNSUMMARY,adddetrunsummaryArgs);
    PXTOOL_MODE("-detrunsummary", DETTOOL_MODE_DETRUNSUMMARY,detrunsummaryArgs);
    PXTOOL_MODE("-updatedetrun", DETTOOL_MODE_UPDATEDETRUN, updatedetrunArgs);
    PXTOOL_MODE("-rerun",           DETTOOL_MODE_RERUN,         rerunArgs);
    PXTOOL_MODE("-register_detrend", DETTOOL_MODE_REGISTER_DETREND, register_detrendArgs);
    PXTOOL_MODE("-register_detrend_imfile", DETTOOL_MODE_REGISTER_DETREND_IMFILE, register_detrend_imfileArgs);

    bool argErr = false;
    if (config->mode == DETTOOL_MODE_NONE) {
        argErr = true;
        fprintf (stderr, "mode argument is required\n");
    } else {
        if (! psArgumentParse(config->args, &argc, argv)) {
            argErr = true;
            fprintf (stderr, "error parsing arguments\n");
        }
        if (argc != 1) {
            fprintf (stderr, "extra arguments: ");
            for (int i = 1; i < argc; i++) {
                fprintf (stderr, "%s ", argv[i]);
            }
            fprintf (stderr, "\n");
            argErr = true;
        }
    }

    if (argErr) {
        printf("\nPan-STARRS Detrend Tool\n");
        printf("Usage: %s <mode> [<options>]\n\n", argv[0]);
        printf(" <mode> :\n\n");

        psMetadataIterator *iter = psMetadataIteratorAlloc(argSets, 0, NULL);
        psMetadataItem *item = NULL;
        while ((item = psMetadataGetAndIncrement(iter))) {
            if (!item->type == PS_DATA_METADATA) {
                psAbort("all options must be specified as a metadata");
            }

            fprintf(stdout, "%s ", item->name);
            psArgumentHelp(item->data.md);
        }
        psFree(iter);
        psFree(argSets);
        psFree(config);
        return NULL;
    }

    psFree(argSets);

    // 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);
    {
        int n = 0;
        bool status = false;
        if ((n = psMetadataLookupS32(&status, config->args, "-iteration"))) {
            if (!psMetadataAddS32(config->where, PS_LIST_TAIL, "iteration", 0, "==", n)) {
                psError(PS_ERR_UNKNOWN, false, "failed to add item iteration");
                psFree(config);
                return NULL;
            }
        }
    }
    addWhereStr(det_type);
    addWhereStr(exp_tag);
    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;
            }
        }
    }

    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;
    }

    // save argv/argc
    config->argv = argv;
    config->argc = argc;

    return config;
}
