Index: trunk/ippTools/src/Makefile.am
===================================================================
--- trunk/ippTools/src/Makefile.am	(revision 7038)
+++ trunk/ippTools/src/Makefile.am	(revision 7048)
@@ -1,3 +1,11 @@
-bin_PROGRAMS = pxadmin pzsearch p0search p1search p2search pzgetexp pzgetimfiles
+bin_PROGRAMS = \
+	pxadmin \
+	pzsearch \
+	p0search \
+	p1search \
+	p2search \
+	dettool \
+	pzgetexp \
+	pzgetimfiles
 
 include_HEADERS = pxtools.h
@@ -10,5 +18,6 @@
 	p0search.h \
 	p1search.h \
-	p2search.h
+	p2search.h \
+	dettool.h
 
 lib_LTLIBRARIES = libpxtools.la
@@ -73,4 +82,10 @@
     pzgetimfilesConfig.c
 
+dettool_CFLAGS = $(PSLIB_CFLAGS) $(PSMODULES_CFLAGS) $(METADATADB_CFLAGS) $(pxtools_CFLAGS)
+dettool_LDADD = $(PSLIB_LIBS) $(PSMODULES_LIBS) $(METADATADB_LIBS) $(top_builddir)/src/libpxtools.la
+dettool_SOURCES = \
+    dettool.c \
+    dettoolConfig.c
+
 clean-local:
 	-rm -f TAGS
Index: trunk/ippTools/src/dettool.c
===================================================================
--- trunk/ippTools/src/dettool.c	(revision 7048)
+++ trunk/ippTools/src/dettool.c	(revision 7048)
@@ -0,0 +1,120 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "pxtools.h"
+#include "p1search.h"
+
+static bool pendingMode(pxConfig *config);
+static bool defineMode(pxConfig *config);
+static p1PendingExpRow *rawScienceTop1PendingExp(pxConfig *config, rawScienceExpRow *raw);
+
+int main(int argc, char **argv)
+{
+    pxConfig *config = p1searchConfig(NULL, argc, argv);
+
+    switch (config->mode) {
+        case PX_MODE_PENDING:
+            if (!pendingMode(config)) {
+                goto FAIL;
+            }
+            break;
+        case PX_MODE_DEFINE:
+            if (!defineMode(config)) {
+                goto FAIL;
+            }
+            break;
+        default:
+            psAbort(argv[0], "invalid option (this should not happen)");
+    }
+
+    exit(EXIT_SUCCESS);
+
+FAIL:
+    psFree(config);
+    exit(EXIT_FAILURE);
+}
+
+static bool pendingMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    // return all p1PendingExp rows unless there CLI search options
+    psArray *p1PendingExp = p1PendingExpSelectRowObjects(
+        config->dbh,
+        config->where ? config->where : NULL,
+        0
+    );
+    if (!p1PendingExp) {
+        psError(PS_ERR_UNKNOWN, false, "no p1PendingExp found");
+        return false;
+    }
+
+    psMetadata *output = psMetadataAlloc();
+
+    for (long i = 0; i < psArrayLength(p1PendingExp); i++) {
+        psMetadata *md = p1PendingExpMetadataFromObject(p1PendingExp->data[i]);
+        psMetadataAddMetadata(output, PS_LIST_TAIL, "p1PendingExp",
+            PS_META_DUPLICATE_OK, NULL, md);
+        psFree(md);
+    }
+
+    psString str = psMetadataConfigFormat(output);
+    psFree(output);
+
+    fprintf(stdout, "%s\n", str);
+    psFree(str);
+
+    return true;
+}
+
+static bool defineMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+    
+    // return all rawScienceExp rows unless there CLI search options
+    psArray *rawScienceExps = rawScienceExpSelectRowObjects(
+        config->dbh,
+        config->where ? config->where : NULL,
+        0
+    );
+
+    if (!rawScienceExps) {
+        psError(PS_ERR_UNKNOWN, false, "no rawScienceExp rows found");
+        return true;
+    }
+
+    // insert the rawScienceExps into p1PendingExp
+    // XXX for the being we're going to skip checking for duplicate entries
+    // XXX this will have to implimented unless duplicate key insertion 
+    // XXX support is implimented in psDB
+    for (long i = 0; i < psArrayLength(rawScienceExps); i++) {
+        p1PendingExpRow * new = rawScienceTop1PendingExp(
+                                            config, rawScienceExps->data[i]);
+        if (!p1PendingExpInsertObject(config->dbh, new)) {
+            psError(PS_ERR_UNKNOWN, false, "dbh access failed");
+            return false; 
+        }
+        psFree(new);
+    }
+
+    return true;
+}
+
+static p1PendingExpRow *rawScienceTop1PendingExp(pxConfig *config, rawScienceExpRow *raw)
+{
+    return p1PendingExpRowAlloc(
+        raw->exp_id,
+        raw->camera,
+        raw->telescope,
+        raw->exp_type,
+//        newExp->class,
+        raw->imfiles,
+        raw->filter,
+        raw->stats,
+        "my recipe",                    //recipe
+        0xff                            // XXX calc version number
+    );
+}
Index: trunk/ippTools/src/dettool.h
===================================================================
--- trunk/ippTools/src/dettool.h	(revision 7048)
+++ trunk/ippTools/src/dettool.h	(revision 7048)
@@ -0,0 +1,8 @@
+#ifndef P1SEARCH_H
+#define P1SEARCH_H 1
+
+#include "pxtools.h"
+
+pxConfig *p1searchConfig(pxConfig *config, int argc, char **argv);
+
+#endif // P1SEARCH_H
Index: trunk/ippTools/src/dettoolConfig.c
===================================================================
--- trunk/ippTools/src/dettoolConfig.c	(revision 7048)
+++ trunk/ippTools/src/dettoolConfig.c	(revision 7048)
@@ -0,0 +1,197 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pmConfig.h>
+
+#include "pxtools.h"
+
+// this function can not fail -- exits on error
+
+pxConfig *p1searchConfig(pxConfig *config, int argc, char **argv) {
+    if (!config) {
+        config = pxConfigAlloc();
+    }
+
+    // setup site config
+    config->modules = pmConfigRead(&argc, argv);
+    if (!config->modules) {
+        psError(PS_ERR_UNKNOWN, false, "Can't find site configuration");
+        exit(EXIT_FAILURE);
+    }
+
+    // CLI options
+    // modes
+    psMetadata *args = psMetadataAlloc();
+    psMetadataAddStr(args , PS_LIST_TAIL, "-pending", 0,
+        "examine pending image table, write ppImage output", NULL);
+    psMetadataAddStr(args , PS_LIST_TAIL, "-define",  0,
+        "update pending image table", NULL);
+
+    // -pending search
+    psMetadata *pendingArgs = psMetadataAlloc();
+    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-exp_id",  0,
+        "define exposure ID", NULL);
+    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-inst",  0,
+        "define camera of interest", NULL);
+    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-telescope",  0,
+        "define telescope of interest", NULL);
+    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-exp_type",  0,
+        "define exposure type", NULL);
+    psMetadataAddS32(pendingArgs, PS_LIST_TAIL, "-imfiles",  0,
+        "define number of imfiles", 0);
+    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-filter",  0,
+        "define filter of interest", NULL);
+    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-stats",  0,
+        "define stats of interest", NULL);
+    psMetadataAddStr(pendingArgs, PS_LIST_TAIL, "-recipe",  0,
+        "define recipe of interest", NULL);
+    psMetadataAddS32(pendingArgs, PS_LIST_TAIL, "-p1_version",  0,
+        "define p1_version of interest", 0);
+
+    // -define inputs
+    psMetadata *defineArgs = psMetadataAlloc();
+    psMetadataAddStr(defineArgs, PS_LIST_TAIL, "-exp_id",  0,
+        "define class", NULL);
+    psMetadataAddStr(defineArgs, PS_LIST_TAIL, "-inst",  0,
+        "define camera of interest", NULL);
+    psMetadataAddStr(defineArgs, PS_LIST_TAIL, "-telescope",  0,
+        "define camera of interest", NULL);
+    psMetadataAddStr(defineArgs, PS_LIST_TAIL, "-exp_type",  0,
+        "define class", NULL);
+    psMetadataAddS32(defineArgs, PS_LIST_TAIL, "-imfiles",  0,
+        "define number of imfiles", 0);
+    psMetadataAddStr(defineArgs, PS_LIST_TAIL, "-filter",  0,
+        "define filter of interest", NULL);
+    psMetadataAddStr(defineArgs, PS_LIST_TAIL, "-stats",  0,
+        "define stats of interest", NULL);
+    // these two are inputs NOT search parameters
+    psMetadataAddStr(defineArgs, PS_LIST_TAIL, "-recipe",  0,
+        "define recipe of interest", NULL);
+    psMetadataAddS32(defineArgs, PS_LIST_TAIL, "-p1_version",  0,
+        "define p1_version of interest", 0);
+
+    // find which mode we're running under
+    int N = 0;
+    config->mode = PX_MODE_NONE;
+    if ((N = psArgumentGet (argc, argv, "-pending"))) {
+        psArgumentRemove (N, &argc, argv);
+        if (config->mode) {
+            psError(PS_ERR_UNKNOWN, true, "only one mode selection is allowed");
+        }
+        config->mode = PX_MODE_PENDING;
+    }
+    if ((N = psArgumentGet (argc, argv, "-define"))) {
+        psArgumentRemove (N, &argc, argv);
+        if (config->mode) {
+            psError(PS_ERR_UNKNOWN, true, "only one mode selection is allowed");
+        }
+        config->mode = PX_MODE_DEFINE;
+    }
+
+    // parse CLI for these options
+    psMetadata *argSet = NULL;
+    switch (config->mode) {
+        case PX_MODE_PENDING:
+            argSet = pendingArgs;
+            break;
+        case PX_MODE_DEFINE:
+            argSet = defineArgs;
+            break;
+        default:
+            argSet = args;
+    }
+    psMemIncrRefCounter(argSet);
+
+    bool argErr = false;
+    if (config->mode == PX_MODE_NONE) {
+        argErr = true;
+        fprintf (stderr, "mode argument is required\n");
+    } else if (! psArgumentParse(argSet, &argc, argv) || argc != 1) {
+        argErr = true;
+        fprintf (stderr, "error parsing arguments\n");
+    }
+
+    if (argErr) {
+        printf("\nPan-STARRS Phase 1 Search Tool\n");
+        printf("Usage: %s <mode> [<options>]\n\n", argv[0]);
+        printf(" <mode> : -pending | -define\n\n");
+        fprintf (stdout, "-pending ");
+        psArgumentHelp(pendingArgs);
+        fprintf (stdout, "-define ");
+        psArgumentHelp(defineArgs);
+        psFree(args);
+        psFree(pendingArgs);
+        psFree(defineArgs);
+        exit(EXIT_FAILURE);
+    }
+
+    psFree(args);
+    psFree(pendingArgs);
+    psFree(defineArgs);
+
+    // setup search criterion
+#define addWhereStr(name) \
+    if ((str = psMetadataLookupStr(&status, argSet, "-" #name))) { \
+        if (!psMetadataAddStr(where, PS_LIST_TAIL, #name, 0, "==", str)) {\
+            psError(PS_ERR_UNKNOWN, false, "failed to add item " #name); \
+            psFree(where); \
+            exit(EXIT_FAILURE); \
+        } \
+    }
+
+    // generate SQL where claus
+    psMetadata *where = psMetadataAlloc();
+
+{
+    psString str = NULL;
+    int n = 0;
+    bool status = false;
+
+    addWhereStr(exp_id);
+    // convert '-inst' to 'camera'
+    if ((str = psMetadataLookupStr(&status, argSet, "-inst"))) {
+        if (!psMetadataAddStr(where, PS_LIST_TAIL, "camera", 0, "==", str)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to add item camera");
+            psFree(where);
+            exit(EXIT_FAILURE);
+        }
+    }
+    addWhereStr(telescope);
+    addWhereStr(exp_type);
+    if ((n = psMetadataLookupS32(&status, argSet, "-imfiles"))) {
+        if (!psMetadataAddS32(where, PS_LIST_TAIL, "imfiles", 0, "==", n)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to add item imfiles");
+            psFree(where);
+            exit(EXIT_FAILURE);
+        }
+    }
+    addWhereStr(filter);
+    addWhereStr(stats);
+    addWhereStr(recipe);
+    if ((n = psMetadataLookupS32(&status, argSet, "-p1_version"))) {
+        if (!psMetadataAddS32(where, PS_LIST_TAIL, "p1_version", 0, "==", n)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to add item p1_version");
+            psFree(where);
+            exit(EXIT_FAILURE);
+        }
+    }
+}
+    psFree(argSet);
+
+    if (where->list->n < 1) {
+        psFree(where);
+        where = NULL;
+    }
+
+    config->where = where;
+
+    // define Database handle, if used
+    config->dbh = pmConfigDB(config->modules);
+    if (!config->dbh) {
+        psError(PS_ERR_UNKNOWN, false, "Can't configure database");
+        exit(EXIT_FAILURE);
+    }
+
+    return config;
+}
