7e5840e03baf4a7b7c198016c393d0b86f7b72b6
braney
  Tue Nov 16 15:25:19 2021 -0800
allow hgc pages on chains to provide a link to the "other" browser if
the other assembly is an unattached genark assembly hub

diff --git src/hg/hgc/hgc.c src/hg/hgc/hgc.c
index 499b83e..851766f 100644
--- src/hg/hgc/hgc.c
+++ src/hg/hgc/hgc.c
@@ -252,30 +252,31 @@
 #include "bigPsl.h"
 #include "bedTabix.h"
 #include "longRange.h"
 #include "hmmstats.h"
 #include "aveStats.h"
 #include "trix.h"
 #include "bPlusTree.h"
 #include "customFactory.h"
 #include "iupac.h"
 #include "clinvarSubLolly.h"
 #include "jsHelper.h"
 #include "errCatch.h"
 #include "htslib/bgzf.h"
 #include "htslib/kstring.h"
 #include "pipeline.h"
+#include "genark.h"
 
 static char *rootDir = "hgcData";
 
 #define LINESIZE 70  /* size of lines in comp seq feature */
 
 struct cart *cart;	/* User's settings. */
 char *seqName;		/* Name of sequence we're working on. */
 int winStart, winEnd;   /* Bounds of sequence. */
 char *database;		/* Name of mySQL database. */
 char *organism;		/* Colloquial name of organism. */
 char *genome;		/* common name, e.g. Mouse, Human */
 char *scientificName;	/* Scientific name of organism. */
 
 /* for earlyBotCheck() function at the beginning of main() */
 #define delayFraction   0.5    /* standard penalty is 1.0 for most CGIs */
@@ -3530,119 +3531,139 @@
 
 if (!hFindSplitTable(db, seqName, track, table, sizeof table, &hasBin))
     errAbort("No %s track in database %s for %s", track, db, seqName);
 sqlSafef(query, sizeof(query),
 	 "select * from %s where id = %d", table, id);
 sr = sqlGetResult(conn, query);
 row = sqlNextRow(sr);
 if (row == NULL)
     errAbort("Can't find %d in %s", id, table);
 chain = chainHeadLoad(row + hasBin);
 sqlFreeResult(&sr);
 chainDbAddBlocks(chain, track, conn);
 return chain;
 }
 
+void linkToOtherBrowserHub(char *otherDb, char *chrom, int start, int end,  char *hubUrl)
+/* Make anchor tag to open another browser window. */
+{
+printf("<A TARGET=\"_blank\" HREF=\"%s?genome=%s&position=%s%%3A%d-%d&hubUrl=%s\">",
+       hgTracksName(), otherDb, chrom, start+1, end, hubUrl);
+}
+
 void linkToOtherBrowserExtra(char *otherDb, char *chrom, int start, int end, char *extra)
 /* Make anchor tag to open another browser window. */
 {
 printf("<A TARGET=\"_blank\" HREF=\"%s?db=%s&%s&position=%s%%3A%d-%d\">",
        hgTracksName(), otherDb, extra, chrom, start+1, end);
 }
 
 void linkToOtherBrowserSearch(char *otherDb, char *tag)
 /* Make anchor tag to open another browser window. */
 {
 printf("<A TARGET=\"_blank\" HREF=\"%s?db=%s&ct=&position=%s\">",
        hgTracksName(), otherDb, tag);
 }
 
 void linkToOtherBrowser(char *otherDb, char *chrom, int start, int end)
 /* Make anchor tag to open another browser window. */
 {
 printf("<A TARGET=\"_blank\" HREF=\"%s?db=%s&ct=&position=%s%%3A%d-%d\">",
        hgTracksName(), otherDb, chrom, start+1, end);
 }
 
 void linkToOtherBrowserTitle(char *otherDb, char *chrom, int start, int end, char *title)
 /* Make anchor tag to open another browser window. */
 {
 printf("<A TARGET=\"_blank\" TITLE=\"%s\" HREF=\"%s?db=%s&ct=&position=%s%%3A%d-%d\">",
        title, hgTracksName(), otherDb, chrom, start+1, end);
 }
 
-void chainToOtherBrowser(struct chain *chain, char *otherDb, char *otherOrg)
+void chainToOtherBrowser(struct chain *chain, char *otherDb, char *otherOrg, char *hubUrl)
 /* Put up link that lets us use chain to browser on
  * corresponding window of other species. */
 {
 struct chain *subChain = NULL, *toFree = NULL;
 int qs,qe;
 chainSubsetOnT(chain, winStart, winEnd, &subChain, &toFree);
 if (subChain != NULL && otherOrg != NULL)
     {
     qChainRangePlusStrand(subChain, &qs, &qe);
-    linkToOtherBrowserExtra(otherDb, subChain->qName, qs-1, qe, cartSidUrlString(cart));
+    if (hubUrl)
+        linkToOtherBrowserHub(otherDb, subChain->qName, qs-1, qe, hubUrl);
+    else
+        linkToOtherBrowser(otherDb, subChain->qName, qs-1, qe);
     printf("Open %s browser</A> at position corresponding to the part of chain that is in this window.<BR>\n", trackHubSkipHubName(otherOrg));
     }
 chainFree(&toFree);
 }
 
 void genericChainClick(struct sqlConnection *conn, struct trackDb *tdb,
                        char *item, int start, char *otherDb)
 /* Handle click in chain track, at least the basics. */
 {
 char *thisOrg = hOrganism(database);
 char *otherOrg = NULL;
 struct chain *chain = NULL, *subChain = NULL, *toFree = NULL;
 int chainWinSize;
 double subSetScore = 0.0;
 int qs, qe;
 boolean nullSubset = FALSE;
+boolean otherIsActive = FALSE;
+char *hubUrl = NULL;   // if otherDb is a genark browser
+
+if (hDbIsActive(otherDb))
+    otherIsActive = TRUE;
+else 
+    hubUrl = genarkUrl(otherDb); // may be NULL
 
 if (! sameWord(otherDb, "seq"))
     {
     otherOrg = hOrganism(otherDb);
     }
 if (otherOrg == NULL)
     {
     /* use first word of chain label (count on org name as first word) */
     otherOrg = firstWordInLine(cloneString(tdb->shortLabel));
     }
 
 if (startsWith("big", tdb->type))
     {
     char *fileName = bbiNameFromSettingOrTable(tdb, conn, tdb->table);
     char *linkFileName = trackDbSetting(tdb, "linkDataUrl");
     chain = chainLoadIdRangeHub(fileName, linkFileName, seqName, winStart, winEnd, atoi(item));
 
-    if (!hDbIsActive(otherDb)) // if this isn't a native database, check to see if it's a hub
+    if (!otherIsActive) // if this isn't a native database, check to see if it's a hub
         {
         struct trackHubGenome *genome = trackHubGetGenomeUndecorated(otherDb);
         if (genome)
+            {
+            otherIsActive = TRUE;
             otherDb = genome->name;
             }
         }
+    }
 else
     {
     chain = chainLoadIdRange(database, tdb->table, seqName, winStart, winEnd, atoi(item));
     }
 
 chainSubsetOnT(chain, winStart, winEnd, &subChain, &toFree);
 
 if (subChain == NULL)
     nullSubset = TRUE;
-else if (hDbIsActive(otherDb) && subChain != chain)
+else if (otherIsActive && subChain != chain)
     {
     char *linearGap = trackDbSettingOrDefault(tdb, "chainLinearGap", "loose");
     struct gapCalc *gapCalc = gapCalcFromFile(linearGap);
     struct axtScoreScheme *scoreScheme = axtScoreSchemeDefault();
     int qStart = subChain->qStart;
     int qEnd   = subChain->qEnd  ;
     struct dnaSeq *tSeq = hDnaFromSeq(database, subChain->tName, subChain->tStart, subChain->tEnd, dnaLower);
     struct dnaSeq *qSeq = NULL;
     char *matrix = trackDbSetting(tdb, "matrix");
     if (matrix != NULL)
         {
         char *words[64];
         int size = chopByWhite(matrix, words, 64) ;
         if (size == 2 && atoi(words[0]) == 16)
             {
@@ -3675,44 +3696,47 @@
        trackHubSkipHubName(thisOrg), hgTracksName(), cartSidUrlString(cart), database,
        chain->tName, chain->tStart+1, chain->tEnd, chain->tName, chain->tStart+1, chain->tEnd,
        chain->tEnd-chain->tStart);
 printf("<B>Strand:</B> %c<BR>\n", chain->qStrand);
 qChainRangePlusStrand(chain, &qs, &qe);
 if (sameWord(otherDb, "seq"))
     {
     printf("<B>%s position:</B> %s:%d-%d  size: %d<BR>\n",
 	otherOrg, chain->qName, qs, qe, chain->qEnd - chain->qStart);
     }
 else
     {
     /* prints link to other db browser only if db exists and is active */
     /* else just print position with no link for the other db */
     printf("<B>%s position: </B>", otherOrg);
-    if (hDbIsActive(otherDb))
+    if (otherIsActive)
         printf(" <A target=\"_blank\" href=\"%s?db=%s&position=%s%%3A%d-%d\">",
                hgTracksName(), otherDb, chain->qName, qs, qe);
+    else if (hubUrl != NULL)
+        printf(" <A target=\"_blank\" href=\"%s?genome=%s&hubUrl=%s&position=%s%%3A%d-%d\">",
+               hgTracksName(), otherDb, hubUrl, chain->qName, qs, qe);
     printf("%s:%d-%d", chain->qName, qs, qe);
-    if (hDbIsActive(otherDb))
+    if (otherIsActive || hubUrl)
         printf("</A>");
     printf(" size: %d<BR>\n", chain->qEnd - chain->qStart);
     }
 printf("<B>Chain ID:</B> %s<BR>\n", item);
 printf("<B>Score:</B> %1.0f\n", chain->score);
 
 if (nullSubset)
     printf("<B>Score within browser window:</B> N/A (no aligned bases)<BR>\n");
-else if (hDbIsActive(otherDb) && subChain != chain)
+else if (otherIsActive && subChain != chain)
     printf("<B>&nbsp;&nbsp;Approximate Score within browser window:</B> %1.0f<BR>\n",
 	   subSetScore);
 else
     printf("<BR>\n");
 
 boolean normScoreAvailable = chainDbNormScoreAvailable(tdb);
 
 if (normScoreAvailable)
     {
     char tableName[HDB_MAX_TABLE_STRING];
     if (!hFindSplitTable(database, chain->tName, tdb->table, tableName, sizeof tableName, NULL))
 	errAbort("genericChainClick track %s not found", tdb->table);
     char query[256];
     struct sqlResult *sr;
     char **row;
@@ -3742,33 +3766,34 @@
 if (!startsWith("big", tdb->type) && sqlDatabaseExists(otherDb) && chromSeqFileExists(otherDb, chain->qName))
     {
     if (chainWinSize < 1000000)
         {
         printf("View ");
         hgcAnchorSomewhere("htcChainAli", item, tdb->track, chain->tName);
         printf("DNA sequence alignment</A> details of parts of chain within browser "
            "window.<BR>\n");
         }
     else
         {
         printf("Zoom so that browser window covers 1,000,000 bases or less "
            "and return here to see alignment details.<BR>\n");
         }
     }
-if (!sameWord(otherDb, "seq") && (hDbIsActive(otherDb)))
+
+if (!sameWord(otherDb, "seq") && (otherIsActive || hubUrl))
     {
-    chainToOtherBrowser(chain, otherDb, otherOrg);
+    chainToOtherBrowser(chain, otherDb, otherOrg, hubUrl);
     }
 /*
 if (!sameWord(otherDb, "seq") && (hDbIsActive(otherDb)))
     {
     chainToOtherBrowser(chain, otherDb, otherOrg);
     }
 */
 chainFree(&chain);
 }
 
 char *trackTypeInfo(char *track)
 /* Return type info on track. You can freeMem result when done. */
 {
 struct slName *trackDbs = hTrackDbList(), *oneTrackDb;
 struct sqlConnection *conn = hAllocConn(database);
@@ -3900,31 +3925,31 @@
 	    else
 	        {
 	        printf("Odd, net not in window<BR>\n");
 	        }
 	    }
         else
 	    {
 	    printf("To see alignment details zoom so that the browser window covers 1,000,000 bases or less.<BR>\n");
 	    }
         }
     chain = chainDbLoad(conn, database, chainTrack, seqName, net->chainId);
     if (chain != NULL)
         {
          /* print link to browser for otherDb only if otherDb is active */
         if (hDbIsActive(otherDb))
-	    chainToOtherBrowser(chain, otherDb, otherOrgBrowser);
+	    chainToOtherBrowser(chain, otherDb, otherOrgBrowser, NULL);
 	chainFree(&chain);
 	}
     htmlHorizontalLine();
     }
 printf("<B>Type:</B> %s<BR>\n", net->type);
 printf("<B>Level:</B> %d<BR>\n", (net->level+1)/2);
 printf("<B>%s position:</B> %s:%d-%d<BR>\n",
        org, net->tName, net->tStart+1, net->tEnd);
 printf("<B>%s position:</B> %s:%d-%d<BR>\n",
        otherOrg, net->qName, net->qStart+1, net->qEnd);
 printf("<B>Strand:</B> %c<BR>\n", net->strand[0]);
 printLabeledNumber(NULL, "Score", net->score);
 if (net->chainId)
     {
     printf("<B>Chain ID:</B> %u<BR>\n", net->chainId);