Index: /trunk/ippTools/src/Makefile.am
===================================================================
--- /trunk/ippTools/src/Makefile.am	(revision 16241)
+++ /trunk/ippTools/src/Makefile.am	(revision 16242)
@@ -31,5 +31,6 @@
 	pxtools.h \
 	pxtoolsErrorCodes.h \
-	pxtree.h 
+	pxtree.h \
+	pxwarp.h
 
 noinst_HEADERS = \
@@ -56,16 +57,17 @@
 libpxtools_la_LDFLAGS   = -release $(PACKAGE_VERSION)
 libpxtools_la_SOURCES   = \
+	pxcam.c \
+	pxchip.c \
+	pxconfig.c \
+	pxdata.c \
+	pxerrors.c \
+	pxfault.c \
+	pxio.c \
+	pxregister.c \
+	pxtables.c \
+	pxtag.c \
 	pxtoolsErrorCodes.c \
-	pxerrors.c \
-	pxconfig.c \
-	pxfault.c \
-	pxtables.c \
-	pxdata.c \
-	pxio.c \
-	pxtag.c \
-	pxregister.c \
-	pxchip.c \
 	pxtree.c \
-	pxcam.c
+	pxwarp.c
 
 # for pxtools.h
Index: /trunk/ippTools/src/camtool.c
===================================================================
--- /trunk/ippTools/src/camtool.c	(revision 16241)
+++ /trunk/ippTools/src/camtool.c	(revision 16242)
@@ -27,4 +27,5 @@
 
 #include "pxtools.h"
+#include "pxwarp.h"
 #include "camtool.h"
 
@@ -485,5 +486,4 @@
         code
     );
-    psFree(pendingRow);
 
     if (!camProcessedExpInsertObject(config->dbh, row)) {
@@ -494,4 +494,5 @@
         psError(PS_ERR_UNKNOWN, false, "database error");
         psFree(row);
+        psFree(pendingRow);
         return false;
     }
@@ -501,8 +502,41 @@
         psError(PS_ERR_UNKNOWN, false, "failed to change camRun.state for cam_id: %" PRId64, row->cam_id);
         psFree(row);
-        return false;
-    }
-
+        psFree(pendingRow);
+        return false;
+    }
+
+    // should we stop here or proceed on to the warp stage?
+    // NULL for end_stage means go as far as possible
+    // we can't start a warp run unlesss tess_id is defined
+    if ((pendingRow->end_stage && psStrcasestr(pendingRow->end_stage, "cam"))
+        || pendingRow->tess_id == NULL) {
+        psFree(row);
+        psFree(pendingRow);
+        if (!psDBCommit(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+            return false;
+        }
+
+        return true;
+    }
     psFree(row);
+    // else continue on...
+
+    if (!pxwarpQueueByCamID(config,
+            pendingRow->cam_id,
+            pendingRow->workdir,
+            pendingRow->dvodb,
+            pendingRow->tess_id,
+            pendingRow->end_stage
+    )) {
+        // rollback
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        psError(PS_ERR_UNKNOWN, false, "failed to queue new warpRun");
+        psFree(pendingRow);
+        return false;
+    }
+    psFree(pendingRow);
 
     if (!psDBCommit(config->dbh)) {
Index: /trunk/ippTools/src/pxwarp.c
===================================================================
--- /trunk/ippTools/src/pxwarp.c	(revision 16242)
+++ /trunk/ippTools/src/pxwarp.c	(revision 16242)
@@ -0,0 +1,95 @@
+/*
+ * pxwarp.c
+ *
+ * Copyright (C) 2007-2008  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 <stdlib.h>
+#include <ippdb.h>
+#include <string.h>
+
+#include "pxtools.h"
+#include "pxwarp.h"
+
+bool pxwarpRunSetState(pxConfig *config, psS64 warp_id, const char *state)
+{
+    PS_ASSERT_PTR_NON_NULL(state, false);
+
+    // check that state is a valid string value
+    if (!(
+            (strncmp(state, "run", 4) == 0)
+            || (strncmp(state, "stop", 5) == 0)
+            || (strncmp(state, "reg", 4) == 0)
+        )
+    ) {
+        psError(PS_ERR_UNKNOWN, false,
+                "invalid warpRun state: %s", state);
+        return false;
+    }
+
+    char *query = "UPDATE warpRun SET state = '%s' WHERE warp_id = %" PRId64;
+    if (!p_psDBRunQuery(config->dbh, query, state, warp_id)) {
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to change state for warp_id %" PRId64, warp_id);
+        return false;
+    }
+
+    return true;
+}
+
+
+bool pxwarpQueueByCamID(pxConfig *config,
+                    psS64 cam_id,
+                    char *workdir,
+                    char *dvodb,
+                    char *tess_id,
+                    char *end_stage)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    if (!warpRunInsert(config->dbh,
+        0,          // ID
+        "warp",     // mode
+        "run",      // state
+        workdir,
+        "dirty",    // workdir_state
+        dvodb,
+        tess_id,
+        end_stage,
+        NULL        // registered
+    )) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return true;
+    }
+
+    psS64 warp_id = psDBLastInsertID(config->dbh);
+
+    // depend on the f-keys to make sure we have a valid cam_id
+    if (!warpInputExpInsert(config->dbh,
+        warp_id,
+        cam_id,
+        false       // magiced
+    )) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    return true;
+}
Index: /trunk/ippTools/src/pxwarp.h
===================================================================
--- /trunk/ippTools/src/pxwarp.h	(revision 16242)
+++ /trunk/ippTools/src/pxwarp.h	(revision 16242)
@@ -0,0 +1,36 @@
+/*
+ * pxwarp.h
+ *
+ * Copyright (C) 2007-2008  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.
+ */
+
+#ifndef PXWARP_H
+#define PXWARP_H 1
+
+#include <pslib.h>
+
+#include "pxtools.h"
+
+bool pxwarpRunSetState(pxConfig *config, psS64 warp_id, const char *state);
+
+bool pxwarpQueueByCamID(pxConfig *config,
+                    psS64 cam_id,
+                    char *workdir,
+                    char *dvodb,
+                    char *tess_id,
+                    char *end_stage);
+
+#endif // PXWARP_H
Index: /trunk/ippTools/src/warptool.c
===================================================================
--- /trunk/ippTools/src/warptool.c	(revision 16241)
+++ /trunk/ippTools/src/warptool.c	(revision 16242)
@@ -30,4 +30,5 @@
 #include "pxtools.h"
 #include "warptool.h"
+#include "pxwarp.h"
 
 static psS64 definerunMode(pxConfig *config);
@@ -46,5 +47,4 @@
 
 static bool parseAndInsertSkyCellMap(pxConfig *config, const char *mapfile);
-static bool setwarpRunState(pxConfig *config, psS64 warp_id, const char *state);
 static bool isValidMode(pxConfig *config, const char *mode);
 bool warpCompletedRuns(pxConfig *config);
@@ -200,5 +200,5 @@
         return false;
     }
-    if (!setwarpRunState(config, warp_id, "run")) {
+    if (!pxwarpRunSetState(config, warp_id, "run")) {
         // rollback
         if (!psDBRollback(config->dbh)) {
@@ -227,5 +227,5 @@
     if (state) {
         // set detRun.state to state
-        return setwarpRunState(config, (psS64)atoll(warp_id), state);
+        return pxwarpRunSetState(config, (psS64)atoll(warp_id), state);
     }
 
@@ -999,31 +999,4 @@
 
 
-static bool setwarpRunState(pxConfig *config, psS64 warp_id, const char *state)
-{
-    PS_ASSERT_PTR_NON_NULL(state, false);
-
-    // check that state is a valid string value
-    if (!(
-            (strncmp(state, "run", 4) == 0)
-            || (strncmp(state, "stop", 5) == 0)
-            || (strncmp(state, "reg", 4) == 0)
-        )
-    ) {
-        psError(PS_ERR_UNKNOWN, false,
-                "invalid warpRun state: %s", state);
-        return false;
-    }
-
-    char *query = "UPDATE warpRun SET state = '%s' WHERE warp_id = %" PRId64;
-    if (!p_psDBRunQuery(config->dbh, query, state, warp_id)) {
-        psError(PS_ERR_UNKNOWN, false,
-                "failed to change state for warp_id %" PRId64, warp_id);
-        return false;
-    }
-
-    return true;
-}
-
-
 static bool isValidMode(pxConfig *config, const char *mode)
 {
