Index: /trunk/ippTools/src/Makefile.am
===================================================================
--- /trunk/ippTools/src/Makefile.am	(revision 15329)
+++ /trunk/ippTools/src/Makefile.am	(revision 15330)
@@ -14,5 +14,6 @@
 	warptool \
 	pzgetimfiles \
-	pztool 
+	pztool \
+	ttree
 
 pkginclude_HEADERS = \
@@ -65,4 +66,7 @@
 # for pxtools.h
 AM_CPPFLAGS = -I$(top_srcdir)/src$
+
+ttree_CFLAGS = $(PSLIB_CFLAGS) $(PSMODULES_CFLAGS) $(IPPDB_CFLAGS) 
+ttree_LDADD = $(PSLIB_LIBS) $(PSMODULES_LIBS) $(IPPDB_LIBS) libpxtools.la
 
 pztool_CFLAGS = $(PSLIB_CFLAGS) $(PSMODULES_CFLAGS) $(IPPDB_CFLAGS) 
Index: /trunk/ippTools/src/magictool.c
===================================================================
--- /trunk/ippTools/src/magictool.c	(revision 15329)
+++ /trunk/ippTools/src/magictool.c	(revision 15330)
@@ -296,4 +296,70 @@
 
 
+bool findBaseNodes(void *arg, pxNode *node)
+{
+    bool status = false;
+    psS64 done = psMetadataLookupS64(&status, node->data, "done");
+    if (!status) {
+        psAbort("failed to lookup value for done column");
+    }
+
+    if ((!pxNodeHasChildren(node)) && (!done)) {
+        // if this node has no child and it's not 'done', then push it's data
+        // onto the void *array
+        psArrayAdd((psArray *)arg, 0, node->data);
+        return false;
+    }
+    
+    return true;
+}
+
+
+bool findReadyNodes(void *arg, pxNode *node)
+{
+
+    if (pxNodeHasChildren(node)) {
+        psListIterator *iter = psListIteratorAlloc(node->children, 0, false);
+        psMetadata *work = psMetadataCopy(NULL, node->data);
+        psMetadataRemoveKey(work, "dep");
+        psMetadataRemoveKey(work, "done");
+        psMetadataRemoveKey(work, "uri");
+        pxNode *child = NULL;
+        while ((child = psListGetAndIncrement(iter))) {
+            psMetadata *data = child->data;
+
+            bool status = false;
+            psS32 done = psMetadataLookupS32(&status, data, "done");
+            if (!status) {
+                psAbort("failed to lookup value for done column");
+            }
+
+            if (!done) {
+                // if a child isn't "done", give up on this node and continue
+                // to crawl the tree
+                psFree(iter);
+                psFree(work);
+                return true;
+            }
+
+            char *uri = psMetadataLookupStr(&status, data, "uri");
+            if (!status) {
+                psAbort("failed to lookup value for uri column");
+            }
+
+            psMetadataAddStr(work, PS_LIST_TAIL, "uri", PS_META_DUPLICATE_OK, NULL, uri);
+
+        }
+        psFree(iter);
+        // if all this nodes children are done, then push it's data onto the
+        // void *array
+        psArrayAdd((psArray *)arg, 0, work);
+        psFree(work);
+        return false;
+    }
+    
+    return true;
+}
+
+
 static bool toprocessMode(pxConfig *config)
 {
@@ -307,5 +373,6 @@
     }
 
-    psString query = pxDataGet("magictool_toprocess.sql");
+    // look for "inputs" that need to processed
+    psString query = pxDataGet("magictool_toprocess_inputs.sql");
     if (!query) {
         psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
@@ -346,20 +413,110 @@
     if (!psArrayLength(output)) {
         psTrace("magictool", PS_LOG_INFO, "no rows found");
-        psFree(output);
+//        psFree(output);
+//        return true;
+    }
+
+    // look for tree nodes that need to be processed
+    query = pxDataGet("magictool_toprocess_tree.sql");
+    if (!query) {
+        psError(PXTOOLS_ERR_DATA, false, "failed to retreive SQL statement");
+        return false;
+    }
+
+
+    if (magic_id) {
+        psMetadata *where = psMetadataAlloc();
+        psMetadataAddS64(where, PS_LIST_TAIL, "magic_id", 0, "==", (psS64)atoll(magic_id));
+        psString whereClause = psDBGenerateWhereSQL(where, NULL);
+        psFree(where);
+        psStringAppend(&query, " %s", whereClause);
+        psFree(whereClause);
+    }
+
+    if (!p_psDBRunQuery(config->dbh, query)) {
+        psError(PS_ERR_UNKNOWN, false, "database error");
+        psFree(query);
+        return false;
+    }
+    psFree(query);
+
+    psArray *magicTree = p_psDBFetchResult(config->dbh);
+    if (!output) {
+        psErrorCode err = psErrorCodeLast();
+        switch (err) {
+            case PS_ERR_DB_CLIENT:
+                psError(PXTOOLS_ERR_SYS, false, "database error");
+            case PS_ERR_DB_SERVER:
+                psError(PXTOOLS_ERR_PROG, false, "database error");
+            default:
+                psError(PXTOOLS_ERR_PROG, false, "unknown error");
+        }
+
+        return false;
+    }
+    if (!psArrayLength(magicTree)) {
+        psTrace("magictool", PS_LOG_INFO, "no rows found");
+        psFree(magicTree);
         return true;
     }
-
-    psMetadata *deps = psMetadataAlloc();
-    // convert the array of metadata into a single flat metadata
-    for (long i = 0; i < psArrayLength(output); i++) {
-        psMetadataCopy(deps, output->data[i]);
-    }
+     
+    psHash *forest = psHashAlloc(psArrayLength(magicTree));
+
+    // convert the array of metadata into a pxTree structure
+    for (long i = 0; i < psArrayLength(magicTree); i++) {
+        psString node = psMetadataLookupStr(&status, magicTree->data[i], "node");
+        if (!status) {
+            psAbort("failed to lookup value for node column");
+        }
+
+        psString dep = psMetadataLookupStr(&status, magicTree->data[i], "dep");
+        if (!status) {
+            psAbort("failed to lookup value for dep column");
+        }
+
+        pxTreeBuilder(forest, node, dep, magicTree->data[i]);
+
+    }
+    psFree(magicTree);
+
+    // find the root of the tree
+    pxNode *root = psHashLookup(forest, "root");
+    psFree(forest);
+
+    pxTreePrint(stdout, root);
+    // crawl through the tree and look for un-"done" bottom nodes
+//    pxTreeCrawl(root, findBaseNodes, work);
+
+    // crawl through the tree and looking for nodes with children that are all
+    // "done"
+    pxTreeCrawl(root, findReadyNodes, output);
+    psFree(root);
+
+    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;
+        }
+    }
+
+    if (psArrayLength(output)) {
+        if (!convertIdToStr(output)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to convert id fields into a strings");
+            psFree(output);
+            return false;
+        }
+
+        // negative simple so the default is true
+        if (!ippdbPrintMetadatas(stdout, output, "magicMe", !simple)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to print array");
+            psFree(output);
+            return false;
+        }
+    }
+
     psFree(output);
-
-    pxNode *root = pxTreeFromMetadata(deps);
-    psFree(deps);
-
-    // silence unused warnings...
-    if (root) {}
 
     return true;
