Index: branches/bills_081204/ippTools/src/difftool.c
===================================================================
--- branches/bills_081204/ippTools/src/difftool.c	(revision 20890)
+++ branches/bills_081204/ippTools/src/difftool.c	(revision 20903)
@@ -47,4 +47,5 @@
 
 static bool setdiffRunState(pxConfig *config, psS64 diff_id, const char *state);
+static bool diffRunComplete(pxConfig *config);
 
 # define MODECASE(caseName, func) \
@@ -108,8 +109,8 @@
     // required options
     PXOPT_LOOKUP_STR(workdir, config->args, "-workdir", true, false);
-    PXOPT_LOOKUP_STR(skycell_id, config->args, "-skycell_id", true, false);
     PXOPT_LOOKUP_STR(tess_id, config->args, "-tess_id", true, false);
     PXOPT_LOOKUP_STR(label, config->args, "-label", false, false);
     PXOPT_LOOKUP_STR(reduction, config->args, "-reduction", false, false);
+    PXOPT_LOOKUP_S64(exp_id, config->args, "-exp_id", false, false);
 
     // default
@@ -125,5 +126,5 @@
             NULL,       // dvodb
             registered,
-            skycell_id,
+            exp_id,
             tess_id
     );
@@ -178,26 +179,32 @@
 
     // optional
-    PXOPT_LOOKUP_S64(stack_id, config->args, "-stack_id", false, false);
-    PXOPT_LOOKUP_S64(warp_id, config->args, "-warp_id", false, false);
-    PXOPT_LOOKUP_STR(kind, config->args, "-kind", false, false);
-
-    // defaults to false
-    PXOPT_LOOKUP_BOOL(template, config->args, "-template", false);
-
-    // must provide either stack_id or warp_id but not BOTH
-    if (!(stack_id || warp_id)) {
-        psError(PS_ERR_UNKNOWN, true, "either -stack_id or -warp_id must be specified");
-        return false;
-    }
-    if (stack_id && warp_id) {
-        psError(PS_ERR_UNKNOWN, true, "either -stack_id or -warp_id must be specified");
-        return false;
-    }
-
-    // if a warp_id was provided we need to lookup the skycell_id and tess_id
-    // from the warpRun
-    psString skycell_id = NULL;
+    PXOPT_LOOKUP_S64(stack1, config->args, "-stack1", false, false);
+    PXOPT_LOOKUP_S64(stack2, config->args, "-stack2", false, false);
+    PXOPT_LOOKUP_S64(warp1, config->args, "-warp1", false, false);
+    PXOPT_LOOKUP_S64(warp2, config->args, "-warp2", false, false);
+    PXOPT_LOOKUP_STR(skycell_id, config->args, "-skycell_id", true, false);
+
+    // must provide either stack1 or warp1 but not BOTH
+    if (!(stack1 || warp1)) {
+        psError(PS_ERR_UNKNOWN, true, "either -stack1 or -warp1 must be specified");
+        return false;
+    }
+    if (stack1 && warp1) {
+        psError(PS_ERR_UNKNOWN, true, "either -stack1 or -warp1 must be specified");
+        return false;
+    }
+    // must provide either stack2 or warp2 but not BOTH
+    if (!(stack2 || warp2)) {
+        psError(PS_ERR_UNKNOWN, true, "either -stack2 or -warp2 must be specified");
+        return false;
+    }
+    if (stack2 && warp2) {
+        psError(PS_ERR_UNKNOWN, true, "either -stack2 or -warp2 must be specified");
+        return false;
+    }
+
+    // if a warp1 was provided we need to lookup the and tess_id from the diffRun
     psString tess_id = NULL;
-    if (warp_id) {
+    if (warp1) {
         if (!p_psDBRunQuery(config->dbh, "SELECT * from diffRun WHERE diff_id = %" PRId64, diff_id)) {
             psError(PS_ERR_UNKNOWN, false, "database error");
@@ -217,5 +224,4 @@
 
         diffRunRow *run = diffRunObjectFromMetadata(output->data[0]);
-        skycell_id = run->skycell_id;
         tess_id = run->tess_id;
     }
@@ -228,10 +234,10 @@
     if (!diffInputSkyfileInsert(config->dbh,
             diff_id,
-            template,
-            stack_id ? stack_id : PS_MAX_S64, // defined or NULL
-            warp_id ? warp_id : PS_MAX_S64, // defined or NULL
+            warp1 ? warp1 : PS_MAX_S64, // defined or NULL
+            warp2 ? warp2 : PS_MAX_S64, // defined or NULL
+            stack1 ? stack1 : PS_MAX_S64, // defined or NULL
+            stack2 ? stack2 : PS_MAX_S64, // defined or NULL
             skycell_id,
-            tess_id,
-            kind
+            tess_id
         )) {
         if (!psDBRollback(config->dbh)) {
@@ -300,5 +306,4 @@
     PXOPT_COPY_STR(config->args, where, "-skycell_id", "skycell_id", "==");
     PXOPT_COPY_STR(config->args, where,  "-tess_id", "tess_id", "==");
-    PXOPT_COPY_STR(config->args, where,  "-kind", "kind", "==");
 
     PXOPT_LOOKUP_U64(limit, config->args, "-limit", false, false);
@@ -349,5 +354,5 @@
     }
 
-    if (!p_psDBRunQuery(config->dbh, query, whereClause, whereClause)) {
+    if (!p_psDBRunQuery(config->dbh, query, whereClause, whereClause, whereClause, whereClause)) {
         psError(PS_ERR_UNKNOWN, false, "database error");
         psFree(whereClause);
@@ -471,4 +476,5 @@
 
     PXOPT_LOOKUP_S64(diff_id, config->args, "-diff_id", true, false); // required
+    PXOPT_LOOKUP_STR(skycell_id, config->args, "-skycell_id", true, false);
     PXOPT_LOOKUP_S16(code, config->args, "-code", false, false);
     PXOPT_LOOKUP_STR(uri, config->args, "-uri", (code == 0), false);
@@ -503,4 +509,5 @@
     if (!diffSkyfileInsert(config->dbh,
                            diff_id,
+                           skycell_id,
                            uri,
                            path_base,
@@ -533,5 +540,5 @@
     }
 
-    if (!setdiffRunState(config, diff_id, "full")) {
+    if (!diffRunComplete(config)) {
         if (!psDBRollback(config->dbh)) {
             psError(PS_ERR_UNKNOWN, false, "database error");
@@ -546,4 +553,5 @@
         return false;
     }
+
 
     return true;
@@ -762,4 +770,5 @@
                          psS64 template_warp_id, // Warp identifier for template image, PS_MAX_S64 for none
                          psS64 template_stack_id, // Stack identifier for template image, PS_MAX_S64 for none
+                         psS64 exp_id, // exposure id for input_warp_id (if defined)
                          pxConfig *config // Configuration
                          )
@@ -791,5 +800,5 @@
             NULL,       // dvodb
             registered,
-            skycell_id,
+            exp_id,
             tess_id
     );
@@ -817,27 +826,10 @@
     if (!diffInputSkyfileInsert(config->dbh,
             run->diff_id,
-            true,
+            input_warp_id,
+            template_warp_id,
+            input_stack_id,
             template_stack_id,
-            template_warp_id,
             skycell_id,
-            tess_id,
-            NULL    // kind
-        )) {
-        if (!psDBRollback(config->dbh)) {
-            psError(PS_ERR_UNKNOWN, false, "database error");
-        }
-        psError(PS_ERR_UNKNOWN, false, "database error");
-        return false;
-    }
-
-    // Input
-    if (!diffInputSkyfileInsert(config->dbh,
-            run->diff_id,
-            false,
-            input_stack_id,
-            input_warp_id,
-            skycell_id,
-            tess_id,
-            NULL    // kind
+            tess_id
         )) {
         if (!psDBRollback(config->dbh)) {
@@ -887,4 +879,5 @@
     PXOPT_LOOKUP_S64(input_warp_id, config->args, "-input_warp_id", false, false);
     PXOPT_LOOKUP_S64(input_stack_id, config->args, "-input_stack_id", false, false);
+    PXOPT_LOOKUP_S64(exp_id, config->args, "-exp_id", false, false);
     PXOPT_LOOKUP_BOOL(simple, config->args, "-simple", false);
 
@@ -906,4 +899,9 @@
         psError(PS_ERR_BAD_PARAMETER_VALUE, true,
                 "No input has been defined (-input_stack_id or -input_warp_id)");
+        return false;
+    }
+    if (input_warp_id && !exp_id) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                "-exp_id is required with -input_warp_id.");
         return false;
     }
@@ -916,4 +914,5 @@
                       template_warp_id ? template_warp_id : PS_MAX_S64,
                       template_stack_id ? template_stack_id : PS_MAX_S64,
+                      exp_id,
                       config)) {
         psError(PS_ERR_UNKNOWN, false, "failed to create populated diffRun");
@@ -945,5 +944,4 @@
     PXOPT_COPY_STR(config->args, warpWhere, "-filter", "rawExp.filter", "==");
     PXOPT_COPY_STR(config->args, warpWhere, "-warp_label", "warpRun.label", "==");
-    PXOPT_COPY_STR(config->args, warpWhere,  "-kind", "warpsToDiff.kind", "==");
     PXOPT_COPY_F32(config->args, warpWhere,  "-good_frac", "warpSkyfile.good_frac", ">=");
     PXOPT_COPY_STR(config->args, stackWhere, "-stack_label", "stackRun.label", "==");
@@ -1048,7 +1046,12 @@
             continue;
         }
+        psS64 exp_id = psMetadataLookupS64(&mdok, row, "exp_id");
+        if (!mdok) {
+            psWarning("exp_id not found --- ignoring row %ld", i);
+            continue;
+        }
 
         if (!populatedrun(list, workdir, skycell_id, tess_id, label, reduction, warp_id,
-                          PS_MAX_S64, PS_MAX_S64, stack_id, config)) {
+                          PS_MAX_S64, PS_MAX_S64, stack_id, exp_id, config)) {
             psWarning("Unable to add run for %s,%s,%" PRId64 ",%" PRId64, skycell_id, tess_id,
                       warp_id, stack_id);
@@ -1274,2 +1277,47 @@
 }
 
+static bool diffRunComplete(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    // look for completed diffRuns
+    psString query = pxDataGet("difftool_completed_runs.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *output = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+    if (!psArrayLength(output)) {
+        psTrace("difftool", PS_LOG_INFO, "no rows found");
+        psFree(output);
+        return true;
+    }
+    for (long i = 0; i < psArrayLength(output); i++) {
+        psMetadata *row = output->data[i];
+
+        psS64 diff_id = psMetadataLookupS64(NULL, row, "diff_id");
+
+        // set diffRun.state to 'stop'
+        if (!setdiffRunState(config, diff_id, "full")) {
+            psError(PS_ERR_UNKNOWN, false, "failed to change diffRun.state for diff_id: %" PRId64,
+                diff_id);
+            psFree(output);
+            return false;
+        }
+    }
+
+    return true;
+}
+
