482973fd8be9571348f698bd70ac28cd62494440
tdreszer
  Tue Jan 11 13:47:28 2011 -0800
Checked in file search tab but ifdef'd out
diff --git src/hg/hgTracks/searchTracks.c src/hg/hgTracks/searchTracks.c
index 732c0e0..b931bd2 100644
--- src/hg/hgTracks/searchTracks.c
+++ src/hg/hgTracks/searchTracks.c
@@ -4,47 +4,60 @@
 #include "searchTracks.h"
 #include "hCommon.h"
 #include "memalloc.h"
 #include "obscure.h"
 #include "dystring.h"
 #include "hash.h"
 #include "cheapcgi.h"
 #include "hPrint.h"
 #include "htmshell.h"
 #include "cart.h"
 #include "hgTracks.h"
 #include "web.h"
 #include "jksql.h"
 #include "hdb.h"
 #include "mdb.h"
+#include "fileUi.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"
 
+//#define FILES_SEARCH
+#ifdef FILES_SEARCH
+    #define TRACK_SEARCH_ON_FILETYPE "tsFileType"
+#endif///def FILES_SEARCH
+
+// Currently selected tab
+enum searchTab {
+    simpleTab   = 0,
+    advancedTab = 1,
+    filesTab    = 2,
+};
+
 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
     {
     sbRelevance=0,
     sbAbc      =1,
     sbHierarchy=2,
     };
@@ -68,31 +81,31 @@
 else if ( tdbIsContainerChild(a->tdb) && !tdbIsContainerChild(b->tdb))
         return 1;
 return strcasecmp(a->longLabel, b->longLabel);
 }
 
 static int gCmpTrack(const void *va, const void *vb)
 /* Compare tracks based on longLabel. */
 {
 const struct slRef *aa = *((struct slRef **)va);
 const struct slRef *bb = *((struct slRef **)vb);
 const struct track *a = ((struct track *) aa->val);
 const struct track *b = ((struct track *) bb->val);
 return strcasecmp(a->longLabel, b->longLabel);
 }
 
-static void findTracksSort(struct slRef **pTrack, boolean simpleSearch, enum sortBy sortBy)
+static void findTracksSort(struct slRef **pTrack, enum sortBy sortBy)
 {
 if (sortBy == sbHierarchy)
     slSort(pTrack, gCmpTrackHierarchy);
 else if (sortBy == sbAbc)
     slSort(pTrack, gCmpTrack);
 else
     slReverse(pTrack);
 }
 
 
 // XXXX make a matchString function to support "contains", "is" etc. and wildcards in contains
 
 //    ((sameString(op, "is") && !strcasecmp(track->shortLabel, str)) ||
 
 static boolean isNameMatch(struct track *track, char *str, char *op)
@@ -158,31 +171,30 @@
 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,
     "bam",
     "psl",
     "chain",
     "netAlign",
     "maf",
     "bed",
     "bigBed",
     "ctgPos",
     "expRatio",
     "genePred",
     "broadPeak",
@@ -217,74 +229,119 @@
     "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;
 }
 
+#ifdef FILES_SEARCH
+static int getFileFormatTypes(char ***pLabels, char ***pTypes)
+{
+char *crudeTypes[] = {
+    ANYLABEL,
+    "bam",
+    "bam.bai",
+    "tagAlign",
+    "bed.gz",
+    "bigBed",
+    "broadPeak",
+    "narrowPeak",
+    "fastq",
+    "bigWig",
+    "wig"
+};
+char *nicerTypes[] = {
+    ANYLABEL,
+    "Alignment binary (bam) - binary SAM",
+    "Alignment binary index (bai) - binary SAM index",
+    "Alignment tags (tagAlign)",
+    "bed - browser extensible data",
+    "bigBed - self index, often remote bed format",
+    "Peaks Broad (broadPeak) - ENCODE large region peak format",
+    "Peaks Narrow (narrowPeak) - ENCODE small region peak format",
+    "Raw Sequence (fastq) - High throughput sequence format",
+    "Signal (bigWig) - self index, often remote wiggle format",
+    "Signal (wig) - wiggle format"
+};
+
+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;
+}
+#endif///def FILES_SEARCH
+
 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;
         retLab[count] = oneTerm->val;
         count++;
         }
     }
 // Don't do it, unless you clone strings above:  slPairFreeValsAndList(&whileList);
 
 *metaVars = retVar;
 *metaLabels = retLab;
 return count;
 }
 
-static int printMdbSelects(struct sqlConnection *conn,struct cart *cart,boolean simpleSearch,char ***pMdbVar,char ***pMdbVal,int *numMetadataNonEmpty,int cols)
+static int printMdbSelects(struct sqlConnection *conn,struct cart *cart,enum searchTab selectedTab,char ***pMdbVar,char ***pMdbVal,int *numMetadataNonEmpty,int cols)
 // Prints a table of mdb selects if appropriate and returns number of them
 {
 // figure out how many metadata selects are visible.
 int delSearchSelect = cartUsualInt(cart, TRACK_SEARCH_DEL_ROW, 0);   // 1-based row to delete
 int addSearchSelect = cartUsualInt(cart, TRACK_SEARCH_ADD_ROW, 0);   // 1-based row to insert after
 int numMetadataSelects = 0;
 char **mdbVar = NULL;
 char **mdbVal = NULL;
 char **mdbVars = NULL;
 char **mdbVarLabels = NULL;
 int i, count = metaDbVars(conn, &mdbVars, &mdbVarLabels);
 
 for(;;)
     {
     char buf[256];
@@ -308,31 +365,31 @@
     *pMdbVar = mdbVar;
     *pMdbVal = mdbVal;
     int i;
     for(i = 0; i < numMetadataSelects; i++)
         {
         char buf[256];
         int offset;   // used to handle additions/deletions
         if(addSearchSelect > 0 && i >= addSearchSelect)
             offset = 0; // do nothing to offset (i.e. copy data from previous row)
         else if(delSearchSelect > 0 && i + 1 >= delSearchSelect)
             offset = 2;
         else
             offset = 1;
         safef(buf, sizeof(buf), "%s%d", METADATA_NAME_PREFIX, i + offset);
         mdbVar[i] = cloneString(cartOptionalString(cart, buf));
-        if(!simpleSearch)
+        if(selectedTab!=simpleTab)
             {
             int j;
             boolean found = FALSE;
             // We need to make sure mdbVar[i] is valid in this assembly; if it isn't, reset it to "cell".
             for(j = 0; j < count && !found; j++)
                 if(sameString(mdbVars[j], mdbVar[i]))
                     found = TRUE;
             if(found)
                 {
             safef(buf, sizeof(buf), "%s%d", METADATA_VALUE_PREFIX, i + offset);
             mdbVal[i] = cloneString(cartOptionalString(cart, buf));
             if(sameString(mdbVal[i], ANYLABEL))
                 mdbVal[i] = NULL;
                 }
             else
@@ -435,148 +492,88 @@
 {
 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 *typeSearch, char *descSearch, char *groupSearch,
-                                             int numMetadataNonEmpty,int numMetadataSelects,char **mdbVar,char **mdbVal)
+static struct slRef *advancedSearchForTracks(struct sqlConnection *conn,struct group *groupList, char **descWords,int descWordCount,
+                                             char *nameSearch, char *typeSearch, char *descSearch, char *groupSearch, struct slPair *mdbPairs)
 // Performs the advanced search and returns the found tracks.
 {
 int tracksFound = 0;
 struct slRef *tracks = NULL;
+int numMetadataNonEmpty = slCount(mdbPairs);
 
     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)
-                    {
-                    // TO BE IMPLEMENTED
-                    // The mdbVal[1] will hve to be filled cartOptionalSlNameList(cart,???)
-                    struct slName *choices = (struct slName *)mdbVal[i];
-                    if (slCount(choices) == 1)
-                        {
-                        tmp = mdbObjSearch(conn, mdbVar[i], choices->name, "is", MDB_VAL_STD_TRUNCATION, TRUE, FALSE);
-                        }
-                    else if(choices != NULL)
-                        {
-                        // Then slNames will need to be assembled into a string in the form of 'a','b','c'
-                        struct dyString *dyList = dyStringNew(256);
-                        dyStringPrintf(dyList,"'%s'",choices->name);
-                        struct slName *choice = choices->next;
-                        for(;choice!=NULL;choice=choice->next)
-                            dyStringPrintf(dyList,",'%s'",choice->name);
-                        tmp = mdbObjSearch(conn, mdbVar[i], dyStringContents(dyList), "in", MDB_VAL_STD_TRUNCATION, TRUE, FALSE);
-                        dyStringFree(&dyList);
-                        }
-                    }
-                else if (searchBy == cvsSearchBySingleSelect)
-                    {
-                    tmp = mdbObjSearch(conn, mdbVar[i], mdbVal[i], "is", MDB_VAL_STD_TRUNCATION, TRUE, FALSE);
-                    }
-                else if (searchBy == cvsSearchByFreeText)
-                    {
-                    tmp = mdbObjSearch(conn, mdbVar[i], mdbVal[i], "like", MDB_VAL_STD_TRUNCATION, TRUE, FALSE);
-                    }
-                else if (searchBy == cvsSearchByDateRange || searchBy == cvsSearchByIntegerRange)
+        if (numMetadataNonEmpty)
                     {
-                    // TO BE IMPLEMENTED
-                    // Requires new mdbObjSearch API and more than one mdbVal[i]
-                    }
-                if (tmp != NULL)
+
+            struct mdbObj *mdbObj, *mdbObjs = mdbObjRepeatedSearch(conn,mdbPairs,TRUE,FALSE);
+            if (mdbObjs)
                     {
-                    if(metaTracks == NULL)
-                        metaTracks = tmp;
-                    else
-                        metaTracks = slNameIntersection(metaTracks, tmp);
-                    }
-            #else///ifndif CV_SEARCH_SUPPORTS_FREETEXT
-                struct slName *tmp = mdbObjSearch(conn, mdbVar[i], mdbVal[i], "is", MDB_VAL_STD_TRUNCATION, TRUE, FALSE);
-                if(metaTracks == NULL)
-                    metaTracks = tmp;
-                else
-                    metaTracks = slNameIntersection(metaTracks, tmp);
-            #endif///ndef CV_SEARCH_SUPPORTS_FREETEXT
-                if (metaTracks == NULL)
-                    break; // If there are no results in a round, then successive intersections will be empty too
+                for (mdbObj = mdbObjs; mdbObj != NULL; mdbObj = mdbObj->next)
+                    hashAddInt(matchingTracks, mdbObj->obj, 1);
+                mdbObjsFree(&mdbObjs);
                 }
             }
-        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); // will be spilled
-                    #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))) &&
-                    #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.");
                             }
                         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); // will be spilled
-                            #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.");
                                     }
                                 }
                             }
@@ -827,73 +824,75 @@
 }
 
 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);
-#else///ifndef TRACK_SEARCH_ON_TYPE
-char *typeSearch = NULL;
-#endif///def TRACK_SEARCH_ON_TYPE
-char *descSearch;
+#ifdef FILES_SEARCH
+char *fileTypeSearch = cartOptionalString(cart, TRACK_SEARCH_ON_FILETYPE);
+#endif///def FILES_SEARCH
+char *descSearch=FALSE;
 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];
 
+enum searchTab selectedTab = simpleTab;
+char *currentTab = cartUsualString(cart, TRACK_SEARCH_CURRENT_TAB, "simpleTab");
 if(sameString(currentTab, "simpleTab"))
     {
+    selectedTab = 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
+else if(sameString(currentTab, "advancedTab"))
     {
+    selectedTab = advancedTab;
     descSearch = cartOptionalString(cart, TRACK_SEARCH_ON_DESCR);
-    simpleSearch = FALSE;
     }
+#ifdef FILES_SEARCH
+else if(sameString(currentTab, "filesTab"))
+    {
+    selectedTab = filesTab;
+    descSearch = cartOptionalString(cart, TRACK_SEARCH_ON_DESCR);
+    }
+#endif///def FILES_SEARCH
 
 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.
 parentChildCartCleanup(trackList,cart,oldVars); // Subtrack settings must be removed when composite/view settings are updated
 
 getSearchTrixFile(database, trixFile, sizeof(trixFile));
 trix = trixOpen(trixFile);
 slSort(&groupList, gCmpGroup);
 for (group = groupList; group != NULL; group = group->next)
     {
@@ -916,37 +915,40 @@
 cartSaveSession(cart);  // Creates hidden var of hgsid to avoid bad voodoo
 safef(buf, sizeof(buf), "%lu", clock1());
 cgiMakeHiddenVar("hgt_", buf);  // timestamps page to avoid browser cache
 
 
 hPrintf("<input type='hidden' name='db' value='%s'>\n", database);
 hPrintf("<input type='hidden' name='%s' id='currentTab' value='%s'>\n", TRACK_SEARCH_CURRENT_TAB, currentTab);
 hPrintf("<input type='hidden' name='%s' value=''>\n",TRACK_SEARCH_DEL_ROW);
 hPrintf("<input type='hidden' name='%s' value=''>\n",TRACK_SEARCH_ADD_ROW);
 hPrintf("<input type='hidden' name='%s' value=''>\n",TRACK_SEARCH_PAGER);
 
 hPrintf("<div id='tabs' style='display:none; %s'>\n"
         "<ul>\n"
         "<li><a href='#simpleTab'><B style='font-size:.9em;font-family: arial, Geneva, Helvetica, san-serif;'>Search</B></a></li>\n"
         "<li><a href='#advancedTab'><B style='font-size:.9em;font-family: arial, Geneva, Helvetica, san-serif;'>Advanced</B></a></li>\n"
+#ifdef FILES_SEARCH
+        "<li><a href='#filesTab'><B style='font-size:.9em;font-family: arial, Geneva, Helvetica, san-serif;'>Files</B></a></li>\n"
+#endif///def FILES_SEARCH
         "</ul>\n"
         "<div id='simpleTab' style='max-width:inherit;'>\n",cgiBrowser()==btIE?"width:1060px;":"max-width:inherit;");
 
 hPrintf("<table style='width:100%%; font-size:.9em;'><tr><td colspan='2'>");
 hPrintf("<input type='text' name='%s' id='simpleSearch' class='submitOnEnter' value='%s' style='max-width:1000px; width:100%%;' onkeyup='findTracksSearchButtonsEnable(true);'>\n",
         TRACK_SEARCH_SIMPLE,descSearch == NULL ? "" : descSearch);
-if (simpleSearch && descSearch)
+if (selectedTab==simpleTab && descSearch)
     searchTermsExist = TRUE;
 
 hPrintf("</td></tr><td style='max-height:4px;'></td></tr></table>");
 //hPrintf("</td></tr></table>");
 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("</div>\n");
 
 // Advanced tab
 hPrintf("<div id='advancedTab' style='width:inherit;'>\n"
         "<table cellSpacing=0 style='width:inherit; font-size:.9em;'>\n");
 cols = 8;
 
 // Track Name contains
@@ -954,116 +956,205 @@
 hPrintf("<td nowrap><b style='max-width:100px;'>Track&nbsp;Name:</b></td>");
 hPrintf("<td align='right'>contains</td>\n");
 hPrintf("<td colspan='%d'>", cols - 4);
 hPrintf("<input type='text' name='%s' id='nameSearch' class='submitOnEnter' value='%s' onkeyup='findTracksSearchButtonsEnable(true);' style='min-width:326px; font-size:.9em;'>",
         TRACK_SEARCH_ON_NAME, nameSearch == NULL ? "" : nameSearch);
 hPrintf("</td></tr>\n");
 
 // Description contains
 hPrintf("<tr><td colspan=2></td><td align='right'>and&nbsp;</td>");
 hPrintf("<td><b style='max-width:100px;'>Description:</b></td>");
 hPrintf("<td align='right'>contains</td>\n");
 hPrintf("<td colspan='%d'>", cols - 4);
 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)
+if (selectedTab==advancedTab && 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)
+if (selectedTab==advancedTab && 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)
+if (selectedTab==advancedTab && 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);
+    numMetadataSelects = printMdbSelects(conn, cart, selectedTab, &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("</div>\n");
+
+#ifdef FILES_SEARCH
+// Files tab
+hPrintf("<div id='filesTab' style='width:inherit;'>\n"
+        "<table cellSpacing=0 style='width:inherit; font-size:.9em;'>\n");
+cols = 8;
+
+//// Track Name contains
+//hPrintf("<tr><td colspan=3></td>");
+//hPrintf("<td nowrap><b style='max-width:100px;'>Track&nbsp;Name:</b></td>");
+//hPrintf("<td align='right'>contains</td>\n");
+//hPrintf("<td colspan='%d'>", cols - 4);
+//hPrintf("<input type='text' name='%s' id='nameSearch' class='submitOnEnter' value='%s' onkeyup='findTracksSearchButtonsEnable(true);' style='min-width:326px; font-size:.9em;'>",
+//        TRACK_SEARCH_ON_NAME, nameSearch == NULL ? "" : nameSearch);
+//hPrintf("</td></tr>\n");
+//
+//// Description contains
+//hPrintf("<tr><td colspan=2></td><td align='right'>and&nbsp;</td>");
+//hPrintf("<td><b style='max-width:100px;'>Description:</b></td>");
+//hPrintf("<td align='right'>contains</td>\n");
+//hPrintf("<td colspan='%d'>", cols - 4);
+//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 (selectedTab==fileTab && 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 (selectedTab==fileTab && groupSearch)
+//    searchTermsExist = TRUE;
+
+// Track Type is (drop down)
+hPrintf("<tr><td colspan=2></td><td align='right'>&nbsp;</td>\n");
+//hPrintf("<tr><td colspan=2></td><td align='right'>and&nbsp;</td>\n"); // Bring back "and" if using "Track Name,Description or Group
+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);
+formatCount = getFileFormatTypes(&formatLabels, &formatTypes);
+cgiMakeDropListFull(TRACK_SEARCH_ON_FILETYPE, formatLabels, formatTypes, formatCount, fileTypeSearch, "class='fileTypeSearch' style='min-width:40%; font-size:.9em;'");
+hPrintf("</td></tr>\n");
+if (selectedTab==filesTab && fileTypeSearch)
+    searchTermsExist = TRUE;
+hPrintf("</div>\n");
+
+// Metadata selects require careful accounting
+if(metaDbExists)
+    numMetadataSelects = printMdbSelects(conn, cart, selectedTab, &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");
+
+#endif///def FILES_SEARCH
+hPrintf("</div>\n");
 
 hPrintf("</form>\n");
 hPrintf("</div>"); // Restricts to max-width:1000px;
 
+if (measureTiming)
+    uglyTime("Rendered tabs");
+
 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)
+if (doSearch && selectedTab==simpleTab && descWordCount <= 0)
     doSearch = FALSE;
 
 if(doSearch)
     {
+    // Convert to slPair list
+    int ix=0;
+    struct slPair *mdbPairs = NULL;
+    for(ix = 0; ix < numMetadataSelects; ix++)
+        {
+        if(!isEmpty(mdbVal[ix]))
+            slAddHead(&mdbPairs,slPairNew(mdbVar[ix],mdbVal[ix]));
+        }
+    slReverse(&mdbPairs);
+
     // Now search
     struct slRef *tracks = NULL;
-    if(simpleSearch)
+    if(selectedTab==simpleTab)
         tracks = simpleSearchForTracksstruct(trix,descWords,descWordCount);
-    else
-        tracks = advancedSearchForTracks(conn,groupList,descWords,descWordCount,nameSearch,typeSearch,descSearch,groupSearch,numMetadataNonEmpty,numMetadataSelects,mdbVar,mdbVal);
+    else if(selectedTab==advancedTab)
+        tracks = advancedSearchForTracks(conn,groupList,descWords,descWordCount,nameSearch,typeSearch,descSearch,groupSearch,mdbPairs);
+#ifdef FILES_SEARCH
+    else if(selectedTab==filesTab)
+        fileSearchResults(database, conn, mdbPairs, fileTypeSearch);
+#endif///def FILES_SEARCH
+
+    if (measureTiming)
+        uglyTime("Searched for tracks");
 
     // Sort and Print results
+    if(selectedTab!=filesTab)
+        {
     enum sortBy sortBy = cartUsualInt(cart,TRACK_SEARCH_SORT,sbRelevance);
     tracksFound = slCount(tracks);
     if(tracksFound > 1)
-        findTracksSort(&tracks,simpleSearch,sortBy);
+            findTracksSort(&tracks,sortBy);
 
     displayFoundTracks(cart,tracks,tracksFound,sortBy);
+
+        if (measureTiming)
+            uglyTime("Displayed found tracks");
     }
 
+    slPairFreeList(&mdbPairs);
+    }
 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 "
             "will be part of the results.");
 else
     hPrintf("<p>Search for terms in track descriptions, groups, and names. "
             "If multiple terms are entered, only tracks with all terms "
             "will be part of the results.");
 hPrintf("<BR><a target='_blank' href='../goldenPath/help/trackSearch.html'>more help</a></p>\n");
-
 webEndSectionTables();
 }