f08f66f3653ea11d306641ad089ad7dc085b8ba1
tdreszer
  Tue Nov 23 14:02:10 2010 -0800
Added format type drop down to advanced search tab.  Whitelist is in code and all code is wrapped with ifdefs when feature becomes more of a hassle than it is worth at this time.
diff --git src/hg/hgTracks/searchTracks.c src/hg/hgTracks/searchTracks.c
index a50001b..7448d2b 100644
--- src/hg/hgTracks/searchTracks.c
+++ src/hg/hgTracks/searchTracks.c
@@ -16,30 +16,31 @@
 #include "jksql.h"
 #include "hdb.h"
 #include "mdb.h"
 #include "trix.h"
 #include "jsHelper.h"
 #include "imageV2.h"
 
 #define ANYLABEL                 "Any"
 #define TRACK_SEARCH_FORM        "trackSearch"
 #define SEARCH_RESULTS_FORM      "searchResults"
 #define METADATA_NAME_PREFIX     "hgt_mdbVar"
 #define METADATA_VALUE_PREFIX    "hgt_mdbVal"
 #define TRACK_SEARCH_CURRENT_TAB "tsCurTab"
 #define TRACK_SEARCH_SIMPLE      "tsSimple"
 #define TRACK_SEARCH_ON_NAME     "tsName"
+#define TRACK_SEARCH_ON_TYPE     "tsType"
 #define TRACK_SEARCH_ON_GROUP    "tsGroup"
 #define TRACK_SEARCH_ON_DESCR    "tsDescr"
 #define TRACK_SEARCH_SORT        "tsSort"
 
 static int gCmpGroup(const void *va, const void *vb)
 /* Compare groups based on label. */
 {
 const struct group *a = *((struct group **)va);
 const struct group *b = *((struct group **)vb);
 return strcmp(a->label, b->label);
 }
 
 // Would like to do a radio button choice ofsorts
 enum sortBy
     {
@@ -157,30 +158,108 @@
 labels[ix] = cloneString(ANYLABEL);
 values[ix] = cloneString(ANYLABEL);
 struct slPair *pair = NULL;
 while((pair = slPopHead(&pairs)) != NULL)
     {
     ix++;
     labels[ix] = pair->name;
     values[ix] = pair->val;
     freeMem(pair);
     }
 *pLabels = labels;
 *pTerms = values;
 return count;
 }
 
+#ifdef TRACK_SEARCH_ON_TYPE
+static int getFormatTypes(char ***pLabels, char ***pTypes)
+{
+char *crudeTypes[] = {
+    ANYLABEL,
+    //"altGraphX",
+    "bam",
+    "psl",
+    "chain",
+    "netAlign",
+    "maf",
+    "bed",
+    "bigBed",
+    "ctgPos",
+    "expRatio",
+    "genePred",
+    "broadPeak",
+    "narrowPeak",
+    "rmsk",
+    "bedGraph",
+    "bigWig",
+    "wig",
+    "wigMaf",
+};
+// Non-standard:
+// type altGraphX
+// type axt
+// type bed5FloatScore
+// type bed5FloatScoreWithFdr
+// type chromGraph
+// type clonePos
+// type coloredExon
+// type encodeFiveC
+// type factorSource
+// type ld2
+// type logo
+// type maf
+// type sample
+// type wigMafProt 0.0 1.0
+
+char *nicerTypes[] = {
+    ANYLABEL,
+    //"altGraphX",
+    "Alignment binary (bam) - binary SAM",
+    "Alignment Blast (psl) - Blast output",
+    "Alignment Chains (chain) - Pairwise alignment",
+    "Alignment Nets (netAlign) - Net alignments",
+    "Alignments (maf) - multiple alignment format",
+    "bed - browser extensible data",
+    "bigBed - self index, often remote bed format",
+    "ctgPos - Contigs",
+    "expRatio - Expression ratios",
+    "Genes (genePred) - Gene prediction and annotation",
+    "Peaks Broad (broadPeak) - ENCODE large region peak format",
+    "Peaks Narrow (narrowPeak) - ENCODE small region peak format",
+    "Repeats (rmsk) - Repeat masking",
+    "Signal (bedGraph) - graphically represented bed data",
+    "Signal (bigWig) - self index, often remote wiggle format",
+    "Signal (wig) - wiggle format"
+    "Signal (wigMaf) - multiple alignment wiggle",
+};
+#endif///def TRACK_SEARCH_ON_TYPE
+
+int ix = 0, count = sizeof(crudeTypes)/sizeof(char *);
+char **labels;
+char **values;
+AllocArray(labels, count);
+AllocArray(values, count);
+for(ix=0;ix<count;ix++)
+    {
+    labels[ix] = cloneString(nicerTypes[ix]);
+    values[ix] = cloneString(crudeTypes[ix]);
+    }
+*pLabels = labels;
+*pTypes = values;
+return count;
+}
+
 static int metaDbVars(struct sqlConnection *conn, char *** metaVars, char *** metaLabels)
 // Search the assemblies metaDb table; If name == NULL, we search every metadata field.
 {
 char query[256];
 struct slPair *oneTerm,*whiteList = mdbCvWhiteList(TRUE,FALSE);
 int count =0, whiteCount = slCount(whiteList);
 char **retVar = needMem(sizeof(char *) * whiteCount);
 char **retLab = needMem(sizeof(char *) * whiteCount);
 
 for(oneTerm=whiteList;oneTerm!=NULL;oneTerm=oneTerm->next)
     {
     safef(query, sizeof(query), "select count(*) from metaDb where var = '%s'",oneTerm->name);
     if(sqlQuickNum(conn,query) > 0)
         {
         retVar[count] = oneTerm->name;
@@ -358,38 +437,38 @@
 {
 struct slRef *tracks = NULL;
 
 struct trixSearchResult *tsList;
 for(tsList = trixSearch(trix, descWordCount, descWords, TRUE); tsList != NULL; tsList = tsList->next)
     {
     struct track *track = (struct track *) hashFindVal(trackHash, tsList->itemId);
     if (track != NULL)  // It is expected that this is NULL (e.g. when the trix references trackDb tracks which have no tables)
         {
         refAdd(&tracks, track);
         }
     }
 return tracks;
 }
 
-static struct slRef *advancedSearchForTracks(struct sqlConnection *conn,struct group *groupList, char **descWords,int descWordCount, char *nameSearch, char *descSearch, char *groupSearch,
+static struct slRef *advancedSearchForTracks(struct sqlConnection *conn,struct group *groupList, char **descWords,int descWordCount, char *nameSearch, char *typeSearch, char *descSearch, char *groupSearch,
                                              int numMetadataNonEmpty,int numMetadataSelects,char **mdbVar,char **mdbVal)
 // Performs the advanced search and returns the found tracks.
 {
 int tracksFound = 0;
 struct slRef *tracks = NULL;
 
-    if(!isEmpty(nameSearch) || descSearch != NULL || groupSearch != NULL || numMetadataNonEmpty)
+    if(!isEmpty(nameSearch) || typeSearch != NULL || descSearch != NULL || groupSearch != NULL || numMetadataNonEmpty)
         {
         // First do the metaDb searches, which can be done quickly for all tracks with db queries.
         struct hash *matchingTracks = newHash(0);
         struct slName *el, *metaTracks = NULL;
         int i;
 
         for(i = 0; i < numMetadataSelects; i++)
             {
             if(!isEmpty(mdbVal[i]))
                 {
             #ifdef CV_SEARCH_SUPPORTS_FREETEXT
                 enum mdbCvSearchable searchBy = mdbCvSearchMethod(mdbVar[i]);
                 struct slName *tmp = NULL;
                 // If select is by free text then like
                 if (searchBy == cvsSearchByMultiSelect)
@@ -444,61 +523,80 @@
             }
         for (el = metaTracks; el != NULL; el = el->next)
             hashAddInt(matchingTracks, el->name, 1);
 
         struct group *group;
         for (group = groupList; group != NULL; group = group->next)
             {
             if(groupSearch == NULL || sameString(group->name, groupSearch))
                 {
                 if (group->trackList != NULL)
                     {
                     struct trackRef *tr;
                     for (tr = group->trackList; tr != NULL; tr = tr->next)
                         {
                         struct track *track = tr->track;
+                    #ifdef TRACK_SEARCH_ON_TYPE
+                        char *trackType = cloneFirstWord(track->tdb->type);
+                    #endif///def TRACK_SEARCH_ON_TYPE
                         if((isEmpty(nameSearch) || isNameMatch(track, nameSearch, "contains")) &&
+                    #ifdef TRACK_SEARCH_ON_TYPE
+                           (isEmpty(typeSearch) || (sameWord(typeSearch, trackType) && !tdbIsComposite(track->tdb))) &&
+                           //(isEmpty(typeSearch) || sameWord(typeSearch, trackType)) &&
+                    #endif///def TRACK_SEARCH_ON_TYPE
                            (isEmpty(descSearch) || isDescriptionMatch(track, descWords, descWordCount)) &&
                           (!numMetadataNonEmpty || hashLookup(matchingTracks, track->track) != NULL))
                             {
                             if (track != NULL)
                                 {
                                 tracksFound++;
                                 refAdd(&tracks, track);
                                 }
                             else
                                 warn("found group track is NULL.");
                             }
+                        #ifdef TRACK_SEARCH_ON_TYPE
+                            freeMem(trackType);
+                        #endif///def TRACK_SEARCH_ON_TYPE
                         if (track->subtracks != NULL)
                             {
                             struct track *subTrack;
                             for (subTrack = track->subtracks; subTrack != NULL; subTrack = subTrack->next)
                                 {
+                            #ifdef TRACK_SEARCH_ON_TYPE
+                                trackType = cloneFirstWord(subTrack->tdb->type);
+                            #endif///def TRACK_SEARCH_ON_TYPE
                                 if((isEmpty(nameSearch) || isNameMatch(subTrack, nameSearch, "contains")) &&
+                            #ifdef TRACK_SEARCH_ON_TYPE
+                                   (isEmpty(typeSearch) || sameWord(typeSearch, trackType)) &&
+                            #endif///def TRACK_SEARCH_ON_TYPE
                                    (isEmpty(descSearch) || isDescriptionMatch(subTrack, descWords, descWordCount)) &&
                                    (!numMetadataNonEmpty || hashLookup(matchingTracks, subTrack->track) != NULL))
                                     {
                                     // XXXX to parent hash. - use tdb->parent instead.
                                     //hashAdd(parents, subTrack->track, track);
                                     if (track != NULL)
                                         {
                                         tracksFound++;
                                         refAdd(&tracks, subTrack);
                                         }
                                     else
                                         warn("found subtrack is NULL.");
                                     }
+                            #ifdef TRACK_SEARCH_ON_TYPE
+                                freeMem(trackType);
+                            #endif///def TRACK_SEARCH_ON_TYPE
                                 }
                             }
                         }
                     }
                 }
             }
         }
 
 return tracks;
 }
 
 #define MAX_FOUND_TRACKS 100
 static void findTracksPageLinks(int tracksFound, int startFrom)
 {
 if (tracksFound <= MAX_FOUND_TRACKS)
@@ -738,56 +836,62 @@
 void doSearchTracks(struct group *groupList)
 {
 if (!advancedJavascriptFeaturesEnabled(cart))
     {
     warn("Requires advanced javascript features.");
     return;
     }
 struct group *group;
 char *groups[128];
 char *labels[128];
 int numGroups = 1;
 groups[0] = ANYLABEL;
 labels[0] = ANYLABEL;
 char *currentTab = cartUsualString(cart, TRACK_SEARCH_CURRENT_TAB, "simpleTab");
 char *nameSearch = cartOptionalString(cart, TRACK_SEARCH_ON_NAME);
+#ifdef TRACK_SEARCH_ON_TYPE
+char *typeSearch = cartOptionalString(cart, TRACK_SEARCH_ON_TYPE);
+#endif///def TRACK_SEARCH_ON_TYPE
 char *descSearch;
 char *groupSearch = cartOptionalString(cart, TRACK_SEARCH_ON_GROUP);
 boolean doSearch = sameString(cartOptionalString(cart, TRACK_SEARCH), "Search") || cartUsualInt(cart, TRACK_SEARCH_PAGER, -1) >= 0;
 struct sqlConnection *conn = hAllocConn(database);
 boolean metaDbExists = sqlTableExists(conn, "metaDb");
 int numMetadataSelects, tracksFound = 0;
 int numMetadataNonEmpty = 0;
 char **mdbVar = NULL;
 char **mdbVal = NULL;
 #ifdef ONE_FUNC
 struct hash *parents = newHash(4);
 #endif///def ONE_FUNC
 boolean simpleSearch;
 struct trix *trix;
 char trixFile[HDB_MAX_PATH_STRING];
 char **descWords = NULL;
 int descWordCount = 0;
 boolean searchTermsExist = FALSE;
 int cols;
 char buf[512];
 
 if(sameString(currentTab, "simpleTab"))
     {
     descSearch = cartOptionalString(cart, TRACK_SEARCH_SIMPLE);
     simpleSearch = TRUE;
     freez(&nameSearch);
+#ifdef TRACK_SEARCH_ON_TYPE
+    freez(&typeSearch);
+#endif///def TRACK_SEARCH_ON_TYPE
     freez(&groupSearch);
     }
 else
     {
     descSearch = cartOptionalString(cart, TRACK_SEARCH_ON_DESCR);
     simpleSearch = FALSE;
     }
 
 if(descSearch)
     stripChar(descSearch, '"');
 trackList = getTrackList(&groupList, -2); // global
 makeGlobalTrackHash(trackList);
 
 // NOTE: This is necessary when container cfg by '*' results in vis changes
 // This will handle composite/view override when subtrack specific vis exists, AND superTrack reshaping.
@@ -867,78 +971,99 @@
 hPrintf("<input type='text' name='%s' id='descSearch' value='%s' class='submitOnEnter' onkeyup='findTracksSearchButtonsEnable(true);' style='max-width:536px; width:536px; font-size:.9em;'>",
         TRACK_SEARCH_ON_DESCR, descSearch == NULL ? "" : descSearch);
 hPrintf("</td></tr>\n");
 if (!simpleSearch && descSearch)
     searchTermsExist = TRUE;
 
 hPrintf("<tr><td colspan=2></td><td align='right'>and&nbsp;</td>\n");
 hPrintf("<td><b style='max-width:100px;'>Group:</b></td>");
 hPrintf("<td align='right'>is</td>\n");
 hPrintf("<td colspan='%d'>", cols - 4);
 cgiMakeDropListFull(TRACK_SEARCH_ON_GROUP, labels, groups, numGroups, groupSearch, "class='groupSearch' style='min-width:40%; font-size:.9em;'");
 hPrintf("</td></tr>\n");
 if (!simpleSearch && groupSearch)
     searchTermsExist = TRUE;
 
+#ifdef TRACK_SEARCH_ON_TYPE
+// Track Type is (drop down)
+hPrintf("<tr><td colspan=2></td><td align='right'>and&nbsp;</td>\n");
+hPrintf("<td nowrap><b style='max-width:100px;'>Data Format:</b></td>");
+hPrintf("<td align='right'>is</td>\n");
+hPrintf("<td colspan='%d'>", cols - 4);
+char **formatTypes = NULL;
+char **formatLabels = NULL;
+int formatCount = getFormatTypes(&formatLabels, &formatTypes);
+cgiMakeDropListFull(TRACK_SEARCH_ON_TYPE, formatLabels, formatTypes, formatCount, typeSearch, "class='typeSearch' style='min-width:40%; font-size:.9em;'");
+hPrintf("</td></tr>\n");
+if (!simpleSearch && typeSearch)
+    searchTermsExist = TRUE;
+#endif///def TRACK_SEARCH_ON_TYPE
+
 // Metadata selects require careful accounting
 if(metaDbExists)
     numMetadataSelects = printMdbSelects(conn, cart, simpleSearch, &mdbVar, &mdbVal, &numMetadataNonEmpty, cols);
 else
     numMetadataSelects = 0;
 
 hPrintf("</table>\n");
 hPrintf("<input type='submit' name='%s' id='searchSubmit' value='search' style='font-size:.8em;'>\n", TRACK_SEARCH);
 hPrintf("<input type='button' name='clear' value='clear' class='clear' style='font-size:.8em;' onclick='findTracksClear();'>\n");
 hPrintf("<input type='submit' name='submit' value='cancel' class='cancel' style='font-size:.8em;'>\n");
 //hPrintf("<a target='_blank' href='../goldenPath/help/trackSearch.html'>help</a>\n");
 hPrintf("</div>\n</div>\n");
 
 hPrintf("</form>\n");
 hPrintf("</div>"); // Restricts to max-width:1000px;
 
 if(descSearch != NULL && !strlen(descSearch))
     descSearch = NULL;
 if(groupSearch != NULL && sameString(groupSearch, ANYLABEL))
     groupSearch = NULL;
+if(typeSearch != NULL && sameString(typeSearch, ANYLABEL))
+    typeSearch = NULL;
 
 if(!isEmpty(descSearch))
     {
     char *tmp = cloneString(descSearch);
     char *val = nextWord(&tmp);
     struct slName *el, *descList = NULL;
     int i;
     while (val != NULL)
         {
         slNameAddTail(&descList, val);
         descWordCount++;
         val = nextWord(&tmp);
         }
     descWords = needMem(sizeof(char *) * descWordCount);
     for(i = 0, el = descList; el != NULL; i++, el = el->next)
         descWords[i] = strLower(el->name);
     }
 if (doSearch && simpleSearch && descWordCount <= 0)
     doSearch = FALSE;
 
 if(doSearch)
     {
     // Now search
     struct slRef *tracks = NULL;
     if(simpleSearch)
         tracks = simpleSearchForTracksstruct(trix,descWords,descWordCount);
     else
-        tracks = advancedSearchForTracks(conn,groupList,descWords,descWordCount,nameSearch,descSearch,groupSearch,numMetadataNonEmpty,numMetadataSelects,mdbVar,mdbVal);
+#ifdef TRACK_SEARCH_ON_TYPE
+        tracks = advancedSearchForTracks(conn,groupList,descWords,descWordCount,nameSearch,typeSearch,descSearch,groupSearch,numMetadataNonEmpty,numMetadataSelects,mdbVar,mdbVal);
+#else///ifndef TRACK_SEARCH_ON_TYPE
+        tracks = advancedSearchForTracks(conn,groupList,descWords,descWordCount,nameSearch,NULL,descSearch,groupSearch,numMetadataNonEmpty,numMetadataSelects,mdbVar,mdbVal);
+#endif///ndef TRACK_SEARCH_ON_TYPE
 
     // Sort and Print results
     enum sortBy sortBy = cartUsualInt(cart,TRACK_SEARCH_SORT,sbRelevance);
     tracksFound = slCount(tracks);
     if(tracksFound > 1)
         findTracksSort(&tracks,simpleSearch,sortBy);
 
     displayFoundTracks(cart,tracks,tracksFound,sortBy);
     }
 
 hFreeConn(&conn);
 webNewSection("About Track Search");
 if(metaDbExists)
     hPrintf("<p>Search for terms in track names, descriptions, groups, and ENCODE "
             "metadata.  If multiple terms are entered, only tracks with all terms "