d24f68e60112fbd009085ec5f7a7d59b05160cec
tdreszer
  Tue Nov 1 10:10:40 2011 -0700
Added extraFields support for bigBeds in hgc.
diff --git src/hg/lib/hui.c src/hg/lib/hui.c
index 0a07852..b0f2ce6 100644
--- src/hg/lib/hui.c
+++ src/hg/lib/hui.c
@@ -4745,69 +4745,66 @@
 return FALSE;
 }
 
 
 #ifdef ALL_SCORE_FILTERS_LOGIC
 static int numericFiltersShowAll(struct cart *cart, struct trackDb *tdb, boolean *opened, boolean boxed,
                                boolean compositeLevel,char *name, char *title)
 // Shows all *Filter style filters.  Note that these are in random order and have no graceful title
 {
 int count = 0;
 struct slName *filterSettings = trackDbSettingsWildMatch(tdb, "*Filter");
 if (filterSettings)
     {
     puts("<BR>");
     struct slName *filter = NULL;
-    struct slPair *extras = NULL;
-    char *extraFields = trackDbSetting(tdb, "extraFields");  // TODo: seems like there should be a cleaner way
-    if (extraFields != NULL)
-        extras = slPairListFromString(extraFields,TRUE); // Quoted strings may be okay
+    struct extraField *extras = extraFieldsGet(tdb);
 
     while ((filter = slPopHead(&filterSettings)) != NULL)
         {
         if (differentString(filter->name,"noScoreFilter") && differentString(filter->name,"scoreFilter")) // TODO: scoreFilter could be included
             {
-            char *field = cloneString(filter->name);
+            // Determine floating point or integer
+            char *setting = trackDbSetting(tdb, filter->name);
+            boolean isFloat = (strchr(setting,'.') != NULL);
+
+            char *scoreName = cloneString(filter->name);
+            char *field = filter->name;   // No need to clone: will be thrown away at end of cycle
             int ix = strlen(field) - strlen("Filter");
             assert(ix > 0);
             field[ix] = '\0';
-            // Could lookup extraFields  // TODO: Should we be using extra fields?  Could this be sorted by the order in extraFields?
+
             if (extras != NULL)
                 {
-                char *foundLabel = slPairFindVal(extras, field);
-                if (foundLabel != NULL)
+                struct extraField *extra = extraFieldsFind(extras, field);
+                if (extra != NULL)
                     { // Found label so replace field
-                    freeMem(field);
-                    field = strchr(foundLabel,']');
-                    if (field == NULL)
-                        field = cloneString(foundLabel);
-                    else
-                        field = cloneString(field + 1);
-                    strSwapChar(field,'_',' ');
+                    field = extra->label;
+                    if (!isFloat)
+                        isFloat = (extra->type == ftFloat);
                     }
                 }
             char label[128];
             safef(label,sizeof(label),"Minimum %s",field);
-            freeMem(field);
-            // Determine floating point or integer
-            char *setting = trackDbSetting(tdb, filter->name);
-            boolean isFloat = (strchr(setting,'.') != NULL);
-            showScoreFilter(cart,tdb,opened,boxed,compositeLevel,name,title,label,filter->name,isFloat);
+            showScoreFilter(cart,tdb,opened,boxed,compositeLevel,name,title,label,scoreName,isFloat);
+            freeMem(scoreName);
             count++;
             }
         slNameFree(&filter);
         }
+    if (extras != NULL)
+        extraFieldsFree(&extras);
     }
 if (count > 0)
     puts("</TABLE>");
 return count;
 }
 #endif///def ALL_SCORE_FILTERS_LOGIC
 
 
 void scoreCfgUi(char *db, struct cart *cart, struct trackDb *tdb, char *name, char *title,  int maxScore, boolean boxed)
 /* Put up UI for filtering bed track based on a score */
 {
 char option[256];
 boolean compositeLevel = isNameAtCompositeLevel(tdb,name);
 boolean skipScoreFilter = FALSE;
 boolean bigBed = startsWith("bigBed",tdb->type);
@@ -7243,15 +7240,87 @@
 if (tableName)
     {
     char *date = firstWordInLine(sqlTableUpdate(conn, tableName));
     if (date != NULL)
 	printf("<B>Data last updated:&nbsp;</B>%s<BR>\n", date);
     }
 hFreeConn(&conn);
 }
 
 void printBbiUpdateTime(time_t *timep)
 /* for bbi files, print out the timep value */
 {
     printf ("<B>Data last updated:&nbsp;</B>%s<BR>\n",
 	sqlUnixTimeToDate(timep, FALSE));
 }
+
+struct extraField *extraFieldsGet(struct trackDb *tdb)
+// returns any extraFields defined in trackDb
+{
+char *fields = trackDbSetting(tdb, "extraFields"); // showFileds pValue=P_Value qValue=qValue
+if (fields == NULL)
+    return NULL;
+
+char *field = NULL;
+struct extraField *extras = NULL;
+struct extraField *extra = NULL;
+while(NULL != (field  = cloneNextWord(&fields)))
+    {
+    AllocVar(extra);
+    extra->name = field;
+    extra->label = field; // defaults to name
+    char *equal = strchr(field,'=');
+    if (equal != NULL)
+        {
+        *equal = '\0';
+        extra->label = equal + 1;
+        assert(*(extra->label)!='\0');
+        }
+
+    extra->type = ftString;
+    if (*(extra->label) == '[')
+        {
+        if (startsWith("[i",extra->label))
+            extra->type = ftInteger;
+        else if (startsWith("[f",extra->label))
+            extra->type = ftFloat;
+        extra->label = strchr(extra->label,']');
+        assert(extra->label != NULL);
+        extra->label += 1;
+        }
+    // clone independently of 'field' and swap in blanks
+    extra->label = cloneString(strSwapChar(extra->label,'_',' '));
+    slAddHead(&extras,extra);
+    }
+
+if (extras != NULL)
+    slReverse(&extras);
+return extras;
+}
+
+struct extraField *extraFieldsFind(struct extraField *extras, char *name)
+// returns the extraField matching the name (case insensitive).  Note: slNameFind does NOT work.
+{
+struct extraField *extra = extras;
+for (; extra != NULL; extra = extra->next)
+    {
+    if (sameWord(name, extra->name))
+        break;
+    }
+return extra;
+}
+
+void extraFieldsFree(struct extraField **pExtras)
+// frees all mem for extraFields list
+{
+if (pExtras != NULL)
+    {
+    struct extraField *extra = NULL;
+    while(NULL != (extra  = slPopHead(pExtras)))
+        {
+        freeMem(extra->name);
+        freeMem(extra->label);
+        freeMem(extra);
+        }
+    *pExtras = NULL;
+    }
+}