3b48412a1e8b3124093c30330c3730e4e4522ca0
braney
  Sun Sep 2 13:01:35 2018 -0700
libify custom bigbed labels so they can be used in hgFind reports #21963

diff --git src/hg/hgTracks/bedTrack.c src/hg/hgTracks/bedTrack.c
index e98e835..344ec58 100644
--- src/hg/hgTracks/bedTrack.c
+++ src/hg/hgTracks/bedTrack.c
@@ -3,109 +3,50 @@
 /* Copyright (C) 2013 The Regents of the University of California 
  * See README in this or parent directory for licensing information. */
 
 #include "common.h"
 #include "jksql.h"
 #include "bed.h"
 #include "hdb.h"
 #include "bedCart.h"
 #include "bbiFile.h"
 #include "bigBed.h"
 #include "hgTracks.h"
 #include "cds.h"
 #include "bedTabix.h"
 #include "obscure.h"
 #include "bigBedFilter.h"
+#include "bigBedLabel.h"
 
 #define SEQ_DELIM '~'
 
 struct bed *bedLoadPairedTagAlign(char **row)
 /* Load first six fields of bed.
  * Add ~seq1~seq2 to end of name
  * Then remove the sequence to extra field when we convert to linkedFeature.
  * Assumes seq1 and seq2 are in row[6] and row[7], as they would be with a
  * pairedTagAlign type (hg/lib/encode/pairedTagAlign.as). It would be good to be
  * able to check these columns exist but we dont have the sqlResult here. */
 {
 char buf[1024];
 struct bed *ret = bedLoad6(row);
 safef(buf, sizeof(buf), "%s%c%s%c%s", ret->name, SEQ_DELIM, row[6], SEQ_DELIM, row[7]);
 freez(&(ret->name));
 ret->name = cloneString(buf);
 return ret;
 }
 
-static void calculateLabelFields(struct track *track)
-/* Figure out which fields are available to label a bigBed track. */
-{
-struct bbiFile *bbi = fetchBbiForTrack(track);
-struct asObject *as = bigBedAsOrDefault(bbi);
-struct slPair *labelList = buildFieldList(track->tdb, "labelFields",  as);
-
-if (labelList == NULL)
-    {
-    // There is no labelFields entry in the trackDb.
-    // If there is a name, use it by default, otherwise no label by default 
-    if (track->bedSize > 3)
-        slAddHead(&track->labelColumns, slIntNew(3));
-    }
-else if (sameString(labelList->name, "none"))
-    return;  // no label
-else
-    {
-    // what has the user said to use as a label
-    char cartVar[1024];
-    safef(cartVar, sizeof cartVar, "%s.label", track->tdb->track);
-    struct hashEl *labelEl = cartFindPrefix(cart, cartVar);
-    struct hash *onHash = newHash(4);
-
-    // fill hash with fields that should be used for labels
-    // first turn on all the fields that are in defaultLabelFields
-    struct slPair *defaultLabelList = buildFieldList(track->tdb, "defaultLabelFields",  as);
-    if (defaultLabelList != NULL)
-        {
-        for(; defaultLabelList; defaultLabelList = defaultLabelList->next)
-            hashStore(onHash, defaultLabelList->name);
-        }
-    else
-        // no default list, use first entry in labelFields as default
-        hashStore(onHash, labelList->name);
-
-    // use cart variables to tweak the default-on hash
-    for(; labelEl; labelEl = labelEl->next)
-        {
-        /* the field name is after the <trackName>.label string */
-        char *fieldName = &labelEl->name[strlen(cartVar) + 1];
-
-        if (sameString((char *)labelEl->val, "1"))
-            hashStore(onHash, fieldName);
-        else if (sameString((char *)labelEl->val, "0"))
-            hashRemove(onHash, fieldName);
-        }
-
-    struct slPair *thisLabel = labelList;
-    for(; thisLabel; thisLabel = thisLabel->next)
-        {
-        if (hashLookup(onHash, thisLabel->name))
-            {
-            // put this column number in the list of columns to use to make label
-            slAddHead(&track->labelColumns, slIntNew(ptToInt(thisLabel->val)));
-            }
-        }
-    slReverse(&track->labelColumns);
-    }
-}
 
 char *bedName(struct track *tg, void *item);
 
 void loadSimpleBedWithLoader(struct track *tg, bedItemLoader loader)
 /* Load the items in one track using specified loader - just move beds in window... */
 {
 struct bed *bed, *list = NULL;
 char **row;
 int rowOffset;
 char *words[3];
 int wordCt;
 char query[128];
 bool doScoreCtFilter = FALSE;
 int scoreFilterCt = 0;
 char *setting;
@@ -139,41 +80,41 @@
     list = bedTabixReadBeds(btf, chromName, winStart, winEnd, loader);
     bedTabixFileClose(&btf);
     }
 else if (tg->isBigBed)
     { // avoid opening an unneeded db connection for bigBed; required not to use mysql for parallel fetch tracks
     struct lm *lm = lmInit(0);
     struct bigBedInterval *bb, *bbList = bigBedSelectRange(tg, chromName, winStart, winEnd, lm);
     char *bedRow[32];
     char startBuf[16], endBuf[16];
     struct bbiFile *bbi = fetchBbiForTrack(tg);
     struct bigBedFilter *filters = bigBedBuildFilters(cart, bbi, tg->tdb);
 
      if (tg->itemName == bedName && !trackDbSettingClosestToHomeOn(tg->tdb, "linkIdInName"))
         tg->itemName = bigBedItemName;
 
-    calculateLabelFields(tg);
+    bigBedLabelCalculateFields(cart, tg->tdb, bbi,  &tg->labelColumns);
     for (bb = bbList; bb != NULL; bb = bb->next)
         {
         bigBedIntervalToRow(bb, chromName, startBuf, endBuf, bedRow, ArraySize(bedRow));
         if (!bigBedFilterInterval(bedRow, filters))
             continue;
         bed = loader(bedRow);
         // FIXME BRANEY: either disable for all tracks with NUM_FIELDS > label field or better,
         // fix how label is stored so it doesn't trash custom bed field
         if (differentString(tg->tdb->type, "bigInteract"))
-            bed->label = makeLabel(tg, bb);
+            bed->label = bigBedMakeLabel(tg->tdb, tg->labelColumns, bb, chromName);
 
         slAddHead(&list, bed);
         }
     lmCleanup(&lm);
     }
 else
     {
     char *table = tg->table;
     struct customTrack *ct = tg->customPt;
     struct sqlConnection *conn = NULL;
     if (ct == NULL)
         conn = hAllocConnTrack(database, tg->tdb);
     else
         {
         conn = hAllocConn(CUSTOM_TRASH);
@@ -281,31 +222,32 @@
 
 void loadBed9(struct track *tg)
 /* Convert bed 9 info in window to linked feature.  (to handle itemRgb)*/
 {
 struct trackDb *tdb = tg->tdb;
 struct bed *bed;
 struct linkedFeatures *lfList = NULL, *lf;
 int scoreMin = atoi(trackDbSettingClosestToHomeOrDefault(tdb, "scoreMin", "0"));
 int scoreMax = atoi(trackDbSettingClosestToHomeOrDefault(tdb, "scoreMax", "1000"));
 boolean useItemRgb = FALSE;
 
 useItemRgb = bedItemRgb(tdb);
 
 if (tg->isBigBed)
     { // avoid opening an unneeded db connection for bigBed; required not to use mysql for parallel fetch tracks
-    calculateLabelFields(tg);
+    struct bbiFile *bbi = fetchBbiForTrack(tg);
+    bigBedLabelCalculateFields(cart, tg->tdb, bbi,  &tg->labelColumns);
     bigBedAddLinkedFeaturesFrom(tg, chromName, winStart, winEnd,
           scoreMin, scoreMax, useItemRgb, 9, &lfList);
     }
 else
     {
     struct sqlConnection *conn = hAllocConnTrack(database, tdb);
     struct sqlResult *sr;
     char **row;
     int rowOffset;
     char *scoreFilterClause = getScoreFilterClause(cart, tg->tdb,NULL);
     if (scoreFilterClause != NULL)
 	{
 	sr = hRangeQuery(conn, tg->table, chromName, winStart, winEnd,scoreFilterClause, &rowOffset);
 	freeMem(scoreFilterClause);
 	}
@@ -332,31 +274,32 @@
 
 void loadBed8(struct track *tg)
 /* Convert bed 8 info in window to linked feature. */
 {
 struct bed *bed;
 struct linkedFeatures *lfList = NULL, *lf;
 struct trackDb *tdb = tg->tdb;
 int scoreMin = atoi(trackDbSettingClosestToHomeOrDefault(tdb, "scoreMin", "0"));
 int scoreMax = atoi(trackDbSettingClosestToHomeOrDefault(tdb, "scoreMax", "1000"));
 boolean useItemRgb = FALSE;
 
 useItemRgb = bedItemRgb(tdb);
 
 if (tg->isBigBed)
     { // avoid opening an unneeded db connection for bigBed; required not to use mysql for parallel fetch tracks
-    calculateLabelFields(tg);
+    struct bbiFile *bbi = fetchBbiForTrack(tg);
+    bigBedLabelCalculateFields(cart, tg->tdb, bbi,  &tg->labelColumns);
     bigBedAddLinkedFeaturesFrom(tg, chromName, winStart, winEnd,
           scoreMin, scoreMax, useItemRgb, 8, &lfList);
     }
 else
     {
     struct sqlConnection *conn = hAllocConn(database);
     struct sqlResult *sr;
     char **row;
     int rowOffset;
     char *scoreFilterClause = getScoreFilterClause(cart, tg->tdb,NULL);
     if (scoreFilterClause != NULL)
 	{
 	sr = hRangeQuery(conn, tg->table, chromName, winStart, winEnd,scoreFilterClause, &rowOffset);
 	freeMem(scoreFilterClause);
 	}
@@ -531,31 +474,32 @@
 {
 struct sqlResult *sr;
 char **row;
 int rowOffset;
 struct bed *bed;
 struct linkedFeatures *lfList = NULL, *lf;
 struct trackDb *tdb = tg->tdb;
 int scoreMin = atoi(trackDbSettingClosestToHomeOrDefault(tdb, "scoreMin", "0"));
 int scoreMax = atoi(trackDbSettingClosestToHomeOrDefault(tdb, "scoreMax", "1000"));
 boolean useItemRgb = FALSE;
 
 useItemRgb = bedItemRgb(tdb);
 
 if (tg->isBigBed)
     { // avoid opening an unneeded db connection for bigBed; required not to use mysql for parallel fetch tracks
-    calculateLabelFields(tg);
+    struct bbiFile *bbi = fetchBbiForTrack(tg);
+    bigBedLabelCalculateFields(cart, tg->tdb, bbi,  &tg->labelColumns);
     bigBedAddLinkedFeaturesFrom(tg, chromName, winStart, winEnd,
           scoreMin, scoreMax, useItemRgb, 12, &lfList);
     }
 else
     {
     /* Use tg->tdb->track because subtracks inherit composite track's tdb
      * by default, and the variable is named after the composite track. */
     struct sqlConnection *conn = hAllocConn(database);
     char *scoreFilterClause = getScoreFilterClause(cart, tg->tdb,NULL);
     if (scoreFilterClause != NULL)
 	{
 	sr = hRangeQuery(conn, tg->table, chromName, winStart, winEnd,scoreFilterClause, &rowOffset);
 	freeMem(scoreFilterClause);
 	}
     else