2d30d99f5f6d3d6532166a0c70c89d38e6053fb1
braney
  Fri Apr 5 16:57:02 2024 -0700
ongoing work on quickLift

diff --git src/hg/lib/trackHub.c src/hg/lib/trackHub.c
index 7753734..1cd8bbf 100644
--- src/hg/lib/trackHub.c
+++ src/hg/lib/trackHub.c
@@ -42,30 +42,31 @@
 #include "bbiFile.h"
 #include "bPlusTree.h"
 #include "hgFind.h"
 #include "hubConnect.h"
 #include "trix.h"
 #include "vcf.h"
 #include "vcfUi.h"
 #include "htmshell.h"
 #include "bigBedFind.h"
 #include "customComposite.h"
 #include "interactUi.h"
 #include "bedTabix.h"
 #include "hic.h"
 #include "hui.h"
 #include "chromAlias.h"
+#include "trashDir.h"
 
 #ifdef USE_HAL
 #include "halBlockViz.h"
 #endif
 
 static struct hash *hubCladeHash;  // mapping of clade name to hub pointer
 static struct hash *hubAssemblyHash; // mapping of assembly name to genome struct
 static struct hash *hubAssemblyUndecoratedHash; // mapping of undecorated assembly name to genome struct
 static struct hash *hubOrgHash;   // mapping from organism name to hub pointer
 static struct trackHub *globalAssemblyHubList; // list of trackHubs in the user's cart
 static struct hash *trackHubHash;
 
 char *trackHubRelativeUrl(char *hubUrl, char *path)
 /* Return full path (in URL form if it's a remote hub) given
  * path possibly relative to hubUrl. Do a freeMem of result
@@ -1402,15 +1403,218 @@
             errAbort("HAL close error: %s", errString);
         }
 #endif
     else if (startsWithWord("hic", type))
         {
         struct hicMeta *header;
         char *errString = hicLoadHeader(bigDataUrl, &header, genome->name);
         if (errString != NULL)
             errAbort("hic file error: %s", errString);
         }
     else
         errAbort("unrecognized type %s in genome %s track %s", type, genome->name, tdb->track);
     freez(&bigDataUrl);
     }
 }
+
+static void outHubHeader(FILE *f, char *db)
+// output a track hub header
+{
+fprintf(f,"hub quickLiftHub%s\n\
+shortLabel Quicklift from %s\n\
+longLabel Quicklift from %s\n\
+useOneFile on\n\
+email genome-www@soe.ucsc.edu\n\n", db, db, db);
+fprintf(f,"genome %s\n\n", db);
+}
+
+static char *getHubName(struct cart *cart, char *db)
+// get the name of the hub to use for quickLifted tracks
+{
+struct tempName hubTn;
+char buffer[4096];
+#define quickLiftCartName     "hubQuickLift"
+safef(buffer, sizeof buffer, "%s-%s", quickLiftCartName, db);
+char *hubName = cartOptionalString(cart, buffer);
+int fd = -1;
+
+if ((hubName == NULL) || ((fd = open(hubName, 0)) < 0))
+    {
+    trashDirDateFile(&hubTn, "quickLift", "hub", ".txt");
+    hubName = cloneString(hubTn.forCgi);
+    cartSetString(cart, buffer, hubName);
+    FILE *f = mustOpen(hubName, "a");
+    outHubHeader(f, db);
+    fclose(f);
+    }
+
+if (fd >= 0)
+    close(fd);
+
+cartSetString(cart, "hubUrl", hubName);
+cartSetString(cart, hgHubConnectRemakeTrackHub, hubName);
+return hubName;
+}
+
+static void dumpTdbAndParents(struct dyString *dy, struct trackDb *tdb, struct hash *existHash, struct hash *wantHash)
+/* Put a trackDb entry into a dyString, stepping up the tree for some variables. */
+{
+struct hashCookie cookie = hashFirst(tdb->settingsHash);
+struct hashEl *hel;
+while ((hel = hashNext(&cookie)) != NULL)
+    {   
+    if (!hashLookup(existHash, hel->name) && ((wantHash == NULL) || hashLookup(wantHash, hel->name)))    
+        {
+        dyStringPrintf(dy, "%s %s\n", hel->name, (char *)hel->val);
+        hashStore(existHash, hel->name);
+        }
+    }
+
+if (tdb->parent)
+    {
+    struct hash *newWantHash = newHash(4);
+    hashStore(newWantHash, "type"); // right now we only want type from parents
+    dumpTdbAndParents(dy, tdb->parent, existHash, newWantHash);
+    }
+}
+
+static bool subtrackEnabledInTdb(struct trackDb *subTdb)
+/* Return TRUE unless the subtrack was declared with "subTrack ... off". */
+{
+bool enabled = TRUE;
+char *words[2];
+char *setting;
+if ((setting = trackDbLocalSetting(subTdb, "parent")) != NULL)
+    {
+    if (chopLine(cloneString(setting), words) >= 2)
+        if (sameString(words[1], "off"))
+            enabled = FALSE;
+    }
+else
+    return subTdb->visibility != tvHide;
+
+return enabled;
+}
+
+static bool isSubtrackVisible(struct cart *cart, struct trackDb *tdb)
+/* Has this subtrack not been deselected in hgTrackUi or declared with
+ *  * "subTrack ... off"?  -- assumes composite track is visible. */
+{
+boolean overrideComposite = (NULL != cartOptionalString(cart, tdb->track));
+bool enabledInTdb = subtrackEnabledInTdb(tdb);
+char option[1024];
+safef(option, sizeof(option), "%s_sel", tdb->track);
+boolean enabled = cartUsualBoolean(cart, option, enabledInTdb);
+if (overrideComposite)
+    enabled = TRUE;
+return enabled;
+}       
+            
+        
+static bool isParentVisible(struct cart *cart, struct trackDb *tdb)
+// Are this track's parents visible?
+{
+if (tdb->parent == NULL)
+    return TRUE;
+        
+if (!isParentVisible(cart, tdb->parent))
+    return FALSE;
+        
+char *cartVis = cartOptionalString(cart, tdb->parent->track);
+boolean vis;
+if (cartVis != NULL)
+    vis =  differentString(cartVis, "hide");
+else if (tdbIsSuperTrack(tdb->parent))
+    vis = tdb->parent->isShow;
+else
+    vis = tdb->parent->visibility != tvHide;
+
+return vis;
+}
+
+struct dyString *trackDbString(struct trackDb *tdb)
+/* Convert a trackDb entry into a dyString. */
+{
+struct dyString *dy;
+struct hash *existHash = newHash(5);
+struct hashEl *hel;
+
+hel = hashLookup(tdb->settingsHash, "track");
+if (hel == NULL)
+    errAbort("can't find track variable in tdb");
+
+dy = dyStringNew(200);
+dyStringPrintf(dy, "track %s\n", trackHubSkipHubName((char *)hel->val));
+hashStore(existHash, "track");
+    
+dumpTdbAndParents(dy, tdb, existHash, NULL);
+
+return dy;
+}
+
+static void walkTree(FILE *f, struct cart *cart,  struct trackDb *tdb, struct dyString *visDy)
+/* walk tree looking for visible tracks. */
+{
+for(; tdb; tdb = tdb->next)
+    {
+    if (tdb->subtracks)
+        walkTree(f, cart, tdb->subtracks, visDy);
+    else 
+        {
+        if (!startsWith("big", tdb->type))
+            continue;
+        boolean isVisible = FALSE;
+        if (tdb->parent == NULL)
+            {
+            char *cartVis = cartOptionalString(cart, tdb->track);
+            if (cartVis != NULL)
+                {
+                tdb->visibility = hTvFromString(cartVis);
+                }
+            isVisible =  tdb->visibility != tvHide;
+            }
+        else if (isParentVisible(cart, tdb) &&  isSubtrackVisible(cart, tdb))
+            {
+            char *cartVis = cartOptionalString(cart, tdb->parent->track);
+            tdb->visibility = hTvFromString(cartVis);
+            isVisible = TRUE;
+            }
+
+        if (isVisible)
+            {
+            dyStringPrintf(visDy, "&%s=%s", tdb->track,hStringFromTv(tdb->visibility));
+            //if (hashLookup(tdb->settingsHash, "customized") == NULL)
+                {
+                hashRemove(tdb->settingsHash, "maxHeightPixels");
+                hashRemove(tdb->settingsHash, "superTrack");
+                hashRemove(tdb->settingsHash, "subGroups");
+                hashRemove(tdb->settingsHash, "polished");
+                hashRemove(tdb->settingsHash, "noInherit");
+                hashRemove(tdb->settingsHash, "group");
+                hashRemove(tdb->settingsHash, "parent");
+                }
+
+            //hashReplace(tdb->settingsHash, "customized", "on");
+
+            struct dyString *dy = trackDbString(tdb);
+
+            fprintf(f, "%s\n", dy->string);
+            }
+        }
+    }
+}
+
+char *trackHubBuild(char *db, struct cart *cart, struct dyString *visDy)
+/* Build a track hub using trackDb and the cart. */
+{
+struct trackDb *tdb = hTrackDb(db);
+slSort(&tdb,trackDbCmp);
+char *filename = getHubName(cart, db);
+
+FILE *f = mustOpen(filename, "a");
+chmod(filename, 0666);
+
+walkTree(f, cart, tdb, visDy);
+fclose(f);
+
+return cloneString(filename);
+}