Index: trunk/ippTools/src/difftool.c
===================================================================
--- trunk/ippTools/src/difftool.c	(revision 15376)
+++ trunk/ippTools/src/difftool.c	(revision 15415)
@@ -39,4 +39,5 @@
 static bool diffskyfileMode(pxConfig *config);
 static bool revertdiffskyfileMode(pxConfig *config);
+static bool definepoprunMode(pxConfig *config);
 
 static bool setdiffRunState(pxConfig *config, const char *diff_id, const char *state);
@@ -62,10 +63,11 @@
         MODECASE(DIFFTOOL_MODE_DEFINERUN,         definerunMode);
         MODECASE(DIFFTOOL_MODE_UPDATERUN,         updaterunMode);
-        MODECASE(DIFFTOOL_MODE_ADDINPUTSKYFILE,    addinputskyfileMode);
-        MODECASE(DIFFTOOL_MODE_INPUTSKYFILE,       inputskyfileMode);
-        MODECASE(DIFFTOOL_MODE_TODIFFSKYFILE,      todiffskyfileMode);
-        MODECASE(DIFFTOOL_MODE_ADDDIFFSKYFILE,     adddiffskyfileMode);
-        MODECASE(DIFFTOOL_MODE_DIFFSKYFILE,        diffskyfileMode);
-        MODECASE(DIFFTOOL_MODE_REVERTDIFFSKYFILE,  revertdiffskyfileMode);
+        MODECASE(DIFFTOOL_MODE_ADDINPUTSKYFILE,   addinputskyfileMode);
+        MODECASE(DIFFTOOL_MODE_INPUTSKYFILE,      inputskyfileMode);
+        MODECASE(DIFFTOOL_MODE_TODIFFSKYFILE,     todiffskyfileMode);
+        MODECASE(DIFFTOOL_MODE_ADDDIFFSKYFILE,    adddiffskyfileMode);
+        MODECASE(DIFFTOOL_MODE_DIFFSKYFILE,       diffskyfileMode);
+        MODECASE(DIFFTOOL_MODE_REVERTDIFFSKYFILE, revertdiffskyfileMode);
+        MODECASE(DIFFTOOL_MODE_DEFINEPOPRUN,      definepoprunMode);
         default:
             psAbort("invalid option (this should not happen)");
@@ -787,2 +789,201 @@
     return true;
 }
+
+
+
+
+
+static bool definepoprunMode(pxConfig *config)
+{
+    PS_ASSERT_PTR_NON_NULL(config, false);
+
+    // required options
+    bool status = false;
+    psString workdir = psMetadataLookupStr(&status, config->args, "-workdir");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -workdir");
+        return false;
+    }
+    if (!workdir) {
+        psError(PS_ERR_UNKNOWN, true, "-workdir is required");
+        return false;
+    }
+
+    psString skycell_id = psMetadataLookupStr(&status, config->args, "-skycell_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -skycell_id");
+        return false;
+    }
+    if (!skycell_id) {
+        psError(PS_ERR_UNKNOWN, true, "-skycell_id is required");
+        return false;
+    }
+
+    psString tess_id = psMetadataLookupStr(&status, config->args, "-tess_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -tess_id");
+        return false;
+    }
+    if (!tess_id) {
+        psError(PS_ERR_UNKNOWN, true, "-tess_id is required");
+        return false;
+    }
+
+    psString template_stack_id = psMetadataLookupStr(&status, config->args, "-template_stack_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -template_stack_id");
+        return false;
+    }
+    psString template_warp_id = psMetadataLookupStr(&status, config->args, "-template_warp_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -template_warp_id");
+        return false;
+    }
+    if (template_stack_id && template_warp_id) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Only one template can be defined.");
+        return false;
+    }
+    if (!template_stack_id && !template_warp_id) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                "No template has been defined (-template_stack_id or -template_warp_id)");
+        return false;
+    }
+
+    psString input_stack_id = psMetadataLookupStr(&status, config->args, "-input_stack_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -input_stack_id");
+        return false;
+    }
+    psString input_warp_id = psMetadataLookupStr(&status, config->args, "-input_warp_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -input_warp_id");
+        return false;
+    }
+    if (input_stack_id && input_warp_id) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Only one input can be defined.");
+        return false;
+    }
+    if (!input_stack_id && !input_warp_id) {
+        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
+                "No input has been defined (-input_stack_id or -input_warp_id)");
+        return false;
+    }
+
+    psString kind = NULL;
+
+    psTime *registered = NULL;
+    {
+        psString registeredStr = psMetadataLookupStr(&status, config->args, "-registered");
+        if (!status) {
+            psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -registered");
+            return false;
+        }
+        // pass through NULL as this is an optional field
+        if (registeredStr) {
+            registered = psTimeFromISO(registeredStr, PS_TIME_UTC);
+        } else {
+            registered = NULL;
+        }
+    }
+
+    bool simple = false;
+    {
+        bool status = false;
+        simple = psMetadataLookupBool(&status, config->args, "-simple");
+        if (!status) {
+            psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -simple");
+            return false;
+        }
+    }
+
+    diffRunRow *run = diffRunRowAlloc(
+            0,          // ID
+            "reg",      // state
+            workdir,
+            NULL,       // dvodb
+            registered,
+            skycell_id,
+            tess_id
+    );
+    psFree(registered);
+
+    if (!run) {
+        psError(PS_ERR_UNKNOWN, false, "failed to alloc diffRun object");
+        return true;
+    }
+
+
+    if (!psDBTransaction(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    if (!diffRunInsertObject(config->dbh, run)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(run);
+        return true;
+    }
+
+    // get the assigned diff_id
+    run->diff_id = psDBLastInsertID(config->dbh);
+
+    // Template
+    if (!diffInputSkyfileInsert(config->dbh,
+            run->diff_id,
+            true,
+            template_stack_id ? (psS64)atoll(template_stack_id) : PS_MAX_S64, // defined or NULL
+            template_warp_id ? (psS64)atoll(template_warp_id) : PS_MAX_S64, // defined or NULL
+            skycell_id,
+            tess_id,
+            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 ? (psS64)atoll(input_stack_id) : PS_MAX_S64, // defined or NULL
+            input_warp_id ? (psS64)atoll(input_warp_id) : PS_MAX_S64, // defined or NULL
+            skycell_id,
+            tess_id,
+            kind
+        )) {
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    char *query = "UPDATE diffRun SET state = 'run' WHERE diff_id = '%" PRId64 "'";
+    if (!p_psDBRunQuery(config->dbh, query, run->diff_id)) {
+        if (!psDBRollback(config->dbh)) {
+            psError(PS_ERR_UNKNOWN, false, "database error");
+        }
+        psError(PS_ERR_UNKNOWN, false,
+                "failed to set state to run for diff_id %" PRId64, run->diff_id);
+        return false;
+    }
+
+    // point of no return
+    if (!psDBCommit(config->dbh)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        return false;
+    }
+
+    if (!diffRunPrintObject(stdout, run, !simple)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to print object");
+            psFree(run);
+            return false;
+    }
+
+    psFree(run);
+
+    return true;
+}
