4b7050d8e3bce0273a6012e16587db4d8a75e127
braney
  Wed Aug 29 14:57:27 2018 -0700
add filtering in lists refs #20227

diff --git src/hg/hgTracks/bigBedTrack.c src/hg/hgTracks/bigBedTrack.c
index daf5482..c4a434b 100644
--- src/hg/hgTracks/bigBedTrack.c
+++ src/hg/hgTracks/bigBedTrack.c
@@ -136,62 +136,71 @@
 char *setting = trackDbSettingClosestToHome(tdb, filterName);
 char *value = cartUsualStringClosestToHome(cart, tdb, FALSE, filterName, setting);
 
 AllocVar(filter);
 filter->fieldNum =  bbExtraFieldIndex(bbi, field) + 3;
 filter->comparisonType = COMPARE_REGEXP;
 regcomp(&filter->regEx, value, REG_NOSUB);
 
 return filter;
 }
 
 struct bigBedFilter *bigBedMakeFilterBy(struct cart *cart, struct bbiFile *bbi, struct trackDb *tdb, char *field, struct slName *choices)
 /* Add a bigBed filter using a trackDb filterBy statement. */
 {
 struct bigBedFilter *filter;
+char filterType[4096];
+safef(filterType, sizeof filterType, "%s%s", field, FILTER_TYPE_NAME);
+char *setting = cartOrTdbString(cart, tdb, filterType, NULL);
 
 AllocVar(filter);
 filter->fieldNum =  bbExtraFieldIndex(bbi, field) + 3;
+if (setting && (sameString(setting, FILTERBY_SINGLE_LIST) || sameString(setting, FILTERBY_MULTIPLE_LIST_OR)))
+    filter->comparisonType = COMPARE_HASH_LIST_OR;
+else if (setting && sameString(setting, FILTERBY_MULTIPLE_LIST_AND))
+    filter->comparisonType = COMPARE_HASH_LIST_AND;
+else
     filter->comparisonType = COMPARE_HASH;
 filter->valueHash = newHash(5);
+filter->numValuesInHash = slCount(choices);
 
 for(; choices; choices = choices->next)
     hashStore(filter->valueHash, choices->name);
 
 return filter;
 }
 
 struct bigBedFilter *bigBedBuildFilters(struct cart *cart, struct bbiFile *bbi, struct trackDb *tdb)
 /* Build all the numeric and filterBy filters for a bigBed */
 {
 struct bigBedFilter *filters = NULL, *filter;
-struct slName *filterSettings = trackDbSettingsWildMatch(tdb, "*Filter");
+struct slName *filterSettings = trackDbSettingsWildMatch(tdb, FILTER_NUMBER_WILDCARD);
 
 for(; filterSettings; filterSettings = filterSettings->next)
     {
     char *fieldName = cloneString(filterSettings->name);
-    fieldName[strlen(fieldName) - sizeof "Filter" + 1] = 0;
+    fieldName[strlen(fieldName) - sizeof FILTER_NUMBER_NAME + 1] = 0;
     if ((filter = bigBedMakeNumberFilter(cart, bbi, tdb, filterSettings->name, NULL, fieldName)) != NULL)
         slAddHead(&filters, filter);
     }
 
-filterSettings = trackDbSettingsWildMatch(tdb, "*FilterText");
+filterSettings = trackDbSettingsWildMatch(tdb, FILTER_TEXT_WILDCARD);
 
 for(; filterSettings; filterSettings = filterSettings->next)
     {
     char *fieldName = cloneString(filterSettings->name);
-    fieldName[strlen(fieldName) - sizeof "FilterText" + 1] = 0;
+    fieldName[strlen(fieldName) - sizeof FILTER_TEXT_NAME + 1] = 0;
     if ((filter = bigBedMakeFilterText(cart, bbi, tdb, filterSettings->name,  fieldName)) != NULL)
         slAddHead(&filters, filter);
     }
 
 filterBy_t *filterBySet = filterBySetGet(tdb, cart,NULL);
 filterBy_t *filterBy = filterBySet;
 for (;filterBy != NULL; filterBy = filterBy->next)
     {
     if (filterBy->slChoices && differentString(filterBy->slChoices->name, "All")) 
         {
         if ((filter = bigBedMakeFilterBy(cart, bbi, tdb, filterBy->column, filterBy->slChoices)) != NULL)
             slAddHead(&filters, filter);
         }
     }
 
@@ -201,30 +210,54 @@
 
 boolean bigBedFilterInterval(char **bedRow, struct bigBedFilter *filters)
 /* Go through a row and filter based on filters.  Return TRUE if all filters are passed. */
 {
 struct bigBedFilter *filter;
 for(filter = filters; filter; filter = filter->next)
     {
     double val = atof(bedRow[filter->fieldNum]);
 
     switch(filter->comparisonType)
         {
         case COMPARE_REGEXP:
             if (regexec(&filter->regEx,bedRow[filter->fieldNum], 0, NULL,0 ) != 0)
                 return FALSE;
             break;
+        case COMPARE_HASH_LIST_AND:
+        case COMPARE_HASH_LIST_OR:
+            {
+            struct slName *values = commaSepToSlNames(bedRow[filter->fieldNum]);
+            unsigned found = 0;
+            for(; values; values = values->next)
+                {
+                if (hashLookup(filter->valueHash, values->name))
+                    {
+                    found++;
+                    if (filter->comparisonType == COMPARE_HASH_LIST_OR) 
+                        break;
+                    }
+                }
+            if (filter->comparisonType == COMPARE_HASH_LIST_AND) 
+                {
+                if (found < filter->numValuesInHash)
+                    return FALSE;
+                }
+            else if (!found)
+                return FALSE;
+            }
+            break;
+
         case COMPARE_HASH:
             if (!hashLookup(filter->valueHash, bedRow[filter->fieldNum]))
                 return FALSE;
             break;
         case COMPARE_LESS:
             if (!(val <= filter->value1))
                 return FALSE;
             break;
         case COMPARE_MORE:
             if (!(val >= filter->value1))
                 return FALSE;
             break;
         case COMPARE_BETWEEN:
             if (!((val >= filter->value1) && (val <= filter->value2)))
                 return FALSE;