Index: trunk/ippTools/src/dettool.c
===================================================================
--- trunk/ippTools/src/dettool.c	(revision 7146)
+++ trunk/ippTools/src/dettool.c	(revision 7147)
@@ -440,4 +440,132 @@
     PS_ASSERT_PTR_NON_NULL(config, false);
 
-    return true;
-}
+    // find all detStackedImfile for det_id
+    // XXX det_id is requried as a simplification
+    psArray *stackedImfiles =
+        detStackedImfileSelectRowObjects(config->dbh, config->where, 0);
+    if (!stackedImfiles) {
+        psError(PS_ERR_UNKNOWN, false, "no detStackedImfile rows found");
+        return NULL;
+    }
+
+    // find all class_ids for the det_id's associated detInputExps
+    // find detInputExps in det_id
+    bool status = false;
+    psString det_id = psMetadataLookupStr(&status, config->args, "-det_id");
+    if (!status) {
+        psError(PS_ERR_UNKNOWN, false, "failed to lookup value for -det_id");
+        psFree(stackedImfiles);
+        return false;
+    }
+
+    psArray *inputExps = NULL;
+    {
+        psMetadata *where = psMetadataAlloc();
+        if (!psMetadataAddS32(where, PS_LIST_TAIL, "det_id", 0, "==",
+                (psS32)atoi(det_id))) {
+            psError(PS_ERR_UNKNOWN, false, "failed to add item det_id");
+            psFree(where);
+            psFree(stackedImfiles);
+            return false;
+        }
+        inputExps = detInputExpSelectRowObjects(config->dbh, where, 0);
+        psFree(where);
+    }
+    if (!inputExps) {
+        psError(PS_ERR_UNKNOWN, false, "no detInputExp rows found");
+    }
+
+    // find rawImfiles associated with detInputExps
+    psArray *rawImfiles = NULL;
+    {
+        psMetadata *where = psMetadataAlloc();
+        for (long i = 0; i < psArrayLength(inputExps); i++) {
+            if (!psMetadataAddStr(where, PS_LIST_TAIL, "exp_id", 0, "==",
+                    ((detInputExpRow *)inputExps->data[i])->exp_id)) {
+                psError(PS_ERR_UNKNOWN, false, "failed to add item exp_id");
+                psFree(where);
+                return false;
+            }
+        }
+        rawImfiles = rawImfileSelectRowObjects(config->dbh, where, 0);
+        // XXX this really should be sorted for uniqueness
+        psFree(where);
+    }
+    if (!rawImfiles) {
+        psError(PS_ERR_UNKNOWN, false, "no rawImfile rows found");
+    }
+
+    psArray *valid_class_ids = NULL;
+    {
+        // All this jumping through hoops is so that we end up with unique
+        // values. PP thinks that making multiple passes through this array and
+        // deleting matched elements would end up being more expensive then a
+        // double sort and stagger scheme. JH thinks it would be cheaper to
+        // just do a unqiue sort and delete.  So this is really just a cheap
+        // hack to avoid implimenting a unique sort function but at least it's
+        // stable.
+        psHash *hash = psHashAlloc(psArrayLength(rawImfiles));
+        for (long i = 0; i < psArrayLength(rawImfiles); i++) {
+            psHashAdd(hash,
+                ((rawImfileRow *)rawImfiles->data[i])->class_id,
+                ((rawImfileRow *)rawImfiles->data[i])->class_id
+            );
+        }
+        valid_class_ids = psHashToArray(hash); 
+        psFree(hash);
+    }
+    psFree(rawImfiles);
+    
+    // check class_ids for validity
+    for (long i = 0; i < psArrayLength(stackedImfiles); i++) {
+        bool valid = false;
+        for (long j = 0; j < psArrayLength(valid_class_ids); j++) {
+            if (strcmp(((detStackedImfileRow *)stackedImfiles->data[i])->class_id,
+                   (char *)valid_class_ids->data[j]) == 0) {
+                valid = true;
+                if (!psArrayRemove(valid_class_ids, valid_class_ids->data[j])) {
+                    psError(PS_ERR_UNKNOWN, false, "psArrayRemove() failed");
+                    psFree(stackedImfiles);
+                    psFree(valid_class_ids);
+                    return false;
+                }
+                j--; // must update loop index
+            }
+        }
+        if (!valid) {
+            psError(PS_ERR_UNKNOWN, true,
+        "class_id %s does not corespond to on contained in an detInputExp",
+            ((detStackedImfileRow *)stackedImfiles->data[i])->class_id);
+            psFree(stackedImfiles);
+            psFree(valid_class_ids);
+            return false;
+        }
+    }
+
+    // check for residual (unmatched) input imfile class_ids
+    if (psArrayLength(valid_class_ids)) {
+        psError(PS_ERR_UNKNOWN, true, "det_id frame is missing %d class_ids",
+            psArrayLength(valid_class_ids));
+        psFree(valid_class_ids);
+        return false;
+    }
+    psFree(valid_class_ids);
+
+    // print detStackedImfile if all class_ids are matched
+    psMetadata *output = psMetadataAlloc();
+    for (long i = 0; i < psArrayLength(stackedImfiles); i++) {
+        psMetadata *md = detStackedImfileMetadataFromObject(
+                stackedImfiles->data[i]);
+        psMetadataAddMetadata(
+            output, PS_LIST_TAIL, "detStackedImfile", PS_META_DUPLICATE_OK,
+            NULL, md
+        );
+    }
+
+    psString str = psMetadataConfigFormat(output); 
+    psFree(output);
+    fprintf(stdout, "%s\n", str);
+    psFree(str);
+  
+    return true;
+}
