0d1ffc7e1c162f115ffa1622a70535b99c465ee0
kate
  Tue Jan 20 18:12:40 2015 -0800
Add inputFieldMetaTables setting to trackDb.  It provides a way to add meta tables to non-composites (same functionality as subGroupMetaTables setting).  Used in details of DNase clusters, to replace cv.ra and metaDb.  refs #14353
diff --git src/hg/hgc/peakClusters.c src/hg/hgc/peakClusters.c
index 48e31e7..316375b 100644
--- src/hg/hgc/peakClusters.c
+++ src/hg/hgc/peakClusters.c
@@ -68,54 +68,55 @@
 	count += 1;
 	sum += sqlDouble(row[signalCol]);
 	}
     sqlFreeResult(&sr);
     hFreeConn(&conn);
     }
 
 if (count > 0)
     return sum/count;
 else
     return 0;
 }
 
 static void printControlledVocabFields(char **row, int fieldCount, 
 	struct slName *fieldList, char *vocabFile, struct hash *vocabHash)
-/* Print out fields from row, linking them to controlled vocab if need be. */
+/* Print out fields from row, linking them to controlled vocab if need be. 
+ * If vocabFile is NULL, the vocabHash is a metaHash, so links + mouseovers are
+ * generated differently */
 {
 int i;
 struct slName *field;
 for (i=0, field = fieldList; i<fieldCount; ++i, field = field->next)
     {
+    char *link = NULL;
     char *fieldVal = row[i];
     if (vocabFile && hashLookup(vocabHash, field->name))
         {
-	char *link = controlledVocabLink(vocabFile, "term", 
-		fieldVal, fieldVal, fieldVal, "");
-	webPrintLinkCell(link);
+        // controlled vocabulary
+        link = controlledVocabLink(vocabFile, "term", fieldVal, fieldVal, fieldVal, "");
         }
-    else
-	webPrintLinkCell(fieldVal);
+    else if (!vocabFile && vocabHash != NULL)
+        {
+        // meta tables
+        struct hash *fieldHash = hashFindVal(vocabHash, field->name);
+        if (fieldHash != NULL)
+            link = metaVocabLink(fieldHash, fieldVal, fieldVal);
+
         }
+    webPrintLinkCell(link != NULL ? link : fieldVal);
     }
-
-struct hash *getVocabHash(char *fileName)
-/* Get vocabulary term hash */
-{
-struct hash *hash = raTagVals(fileName, "type");
-hashAdd(hash, "cellType", NULL);	/* Will the kludge never end, no, never! */
-return hash;
 }
 
 static void printMetadataForTable(char *table)
 /* If table exists, _and_ tdb associated with it exists, print out
  * a metadata link that expands on click.  Otherwise print "unavailable" */
 {
 webPrintLinkCellStart();
 struct trackDb *tdb = hashFindVal(trackHash, table);
 if (tdb == NULL)
     printf("%s info n/a", table);
 else
     compositeMetadataToggle(database, tdb, "metadata", TRUE, FALSE);
 webPrintLinkCellEnd();
 }
 
@@ -123,49 +124,78 @@
                                 struct slName *fieldList)
 /* Construct query in dyString to return contents of inputTrackTable ordered appropriately */
 {
 struct dyString *fields = dyStringNew(0);
 struct slName *field;
 sqlDyStringPrintf(query, "select tableName ");
 for (field = fieldList; field != NULL; field = field->next)
     sqlDyStringPrintfFrag(fields, ",%s", field->name);
 sqlDyStringPrintf(query, "%-s from %s", fields->string, inputTrackTable);
 if (fieldList != NULL)
     // skip leading comma
     dyStringPrintf(query, " order by %s", fields->string+1);
 dyStringFree(&fields);
 }
 
+static struct hash *getVocabHash(char *fileName)
+/* Get vocabulary term hash */
+{
+struct hash *hash = raTagVals(fileName, "type");
+hashAdd(hash, "cellType", NULL);	/* Will the kludge never end, no, never! */
+return hash;
+}
 
-static void printPeakClusterInfo(struct sqlConnection *conn, char *inputTrackTable, 
-                                struct slName *fieldList, char *vocab, struct bed *cluster)
-/* Print an HTML table showing sources with hits in the cluster, along with signal.
-   If cluster is NULL, show all sources assayed */
+static void getVocab(struct trackDb *tdb, struct cart *cart, 
+                        char **vocabFile, struct hash **vocabHash)
+/* Get vocabulary info from trackDb settings (CV or meta tables) */
 {
-char *vocabFile = NULL;
-struct hash *vocabHash = NULL;
+
+char *file = NULL;
+struct hash *hash = NULL;
+char *vocab = trackDbSetting(tdb, "controlledVocabulary");
+struct hash *metaHash = metaBasicFromSetting(tdb, cart, "inputFieldMetaTables");
 if (vocab)
     {
-    vocabFile = cloneFirstWord(vocab);
-    vocabHash = getVocabHash(vocabFile);
+    file = cloneFirstWord(vocab);
+    hash = getVocabHash(file);
+    }
+else if (metaHash)
+    {
+    hash = metaHash;
+    }
+if (vocabFile != NULL)
+    *vocabFile = file;
+if (hash != NULL)
+    *vocabHash = hash;
 }
 
+static void printPeakClusterInfo(struct trackDb *tdb, struct cart *cart,
+                                struct sqlConnection *conn, char *inputTrackTable, 
+                                struct slName *fieldList, struct bed *cluster)
+/* Print an HTML table showing sources with hits in the cluster, along with signal.
+   If cluster is NULL, show all sources assayed */
+{
+
 /* Make the SQL query to get the table and all other fields we want to show
  * from inputTrackTable. */
 struct dyString *query = dyStringNew(0);
 queryInputTrackTable(query, inputTrackTable, fieldList);
 
+char *vocabFile = NULL;
+struct hash *vocabHash = NULL;
+getVocab(tdb, cart, &vocabFile, &vocabHash);
+
 int displayNo = 0;
 int fieldCount = slCount(fieldList);
 struct sqlResult *sr = sqlGetResult(conn, query->string);
 char **row;
 while ((row = sqlNextRow(sr)) != NULL)
     {
     double signal = 0;
     if (cluster != NULL)
         {
         char *table = row[0];
         signal = getSignalAt(table, cluster);
         if (signal == 0)
             continue;
         }
     printf("</TR><TR>\n");
@@ -262,33 +292,32 @@
 }
 
 void doPeakClusterListItemsAssayed()
 /* Put up a page that shows all experiments associated with a cluster track. */
 {
 struct trackDb *clusterTdb = tdbForTableArg();
 cartWebStart(cart, database, "List of items assayed in %s", clusterTdb->shortLabel);
 struct sqlConnection *conn = hAllocConn(database);
 
 char *inputTableFieldDisplay = trackDbSetting(clusterTdb, "inputTableFieldDisplay");
 webPrintLinkTableStart();
 if (inputTableFieldDisplay)
     {
     struct slName *fieldList = stringToSlNames(inputTableFieldDisplay);
     printClusterTableHeader(fieldList, FALSE, FALSE, FALSE);
-    char *vocab = trackDbSetting(clusterTdb, "controlledVocabulary");
     char *inputTrackTable = trackDbRequiredSetting(clusterTdb, "inputTrackTable");
-    printPeakClusterInfo(conn, inputTrackTable, fieldList, vocab, NULL);
+    printPeakClusterInfo(clusterTdb, cart, conn, inputTrackTable, fieldList, NULL);
     //http://genome-test.cse.ucsc.edu/cgi-bin/hgTables?db=hg38&hgta_table=uwEnc2DnasePeaksWgEncodeEH000507
     }
 else
     errAbort("Missing required trackDb setting %s for track %s", "inputTableFieldDisplay", 
                 clusterTdb->track);
 webPrintLinkTableEnd();
 hFreeConn(&conn);
 }
 
 void doPeakClusters(struct trackDb *tdb, char *item)
 /* Display detailed info about a cluster of DNase peaks from other tracks. */
 {
 int start = cartInt(cart, "o");
 char *table = tdb->table;
 int rowOffset = hOffsetPastBin(database, seqName, table);
@@ -303,44 +332,43 @@
 	"select * from %s where  name = '%s' and chrom = '%s' and chromStart = %d",
 	table, item, seqName, start);
 sr = sqlGetResult(conn, query);
 row = sqlNextRow(sr);
 if (row != NULL)
     cluster = bedLoadN(row+rowOffset, 5);
 sqlFreeResult(&sr);
 
 if (cluster != NULL)
     {
     /* Get list of subgroups to display */
     char *inputTableFieldDisplay = trackDbSetting(tdb, "inputTableFieldDisplay");
     if (inputTableFieldDisplay != NULL)
         {
 	struct slName *fieldList = stringToSlNames(inputTableFieldDisplay);
-	char *vocab = trackDbSetting(tdb, "controlledVocabulary");
 	char *inputTrackTable = trackDbRequiredSetting(tdb, "inputTrackTable");
 
 	/* Print out some information about the cluster overall. */
 	printf("<B>Items in Cluster:</B> %s of %d<BR>\n", cluster->name, 
 	    sqlRowCount(conn, sqlCheckIdentifier(inputTrackTable)));
 	printf("<B>Cluster Score (out of 1000):</B> %d<BR>\n", cluster->score);
 	printPos(cluster->chrom, cluster->chromStart, cluster->chromEnd, NULL, TRUE, NULL);
 
 	/* In a new section put up list of hits. */
 	webNewSection("List of Items in Cluster");
 	webPrintLinkTableStart();
 	printClusterTableHeader(fieldList, FALSE, FALSE, TRUE);
-	printPeakClusterInfo(conn, inputTrackTable, fieldList, vocab, cluster);
+	printPeakClusterInfo(tdb, cart, conn, inputTrackTable, fieldList, cluster);
 	}
     else
 	errAbort("Missing required trackDb setting %s for track %s",
 	    "inputTableFieldDisplay", tdb->track);
     webPrintLinkTableEnd();
     }
 printf("<A HREF=\"%s&g=htcListItemsAssayed&table=%s\" TARGET_blank>", hgcPathAndSettings(),
 	tdb->track);
 printf("List all items assayed");
 printf("</A><BR>\n");
 webNewSection("Track Description");
 printTrackHtml(tdb);
 hFreeConn(&conn);
 }