485724bcdce8810dcf1b65755c97dbb3c39fa02a
braney
  Mon Aug 25 15:37:25 2025 -0700
give quickLiftChains there own methods in hgTracks and a special hgc
page

diff --git src/hg/hgc/hgc.c src/hg/hgc/hgc.c
index 1ca4317a322..25374b41a83 100644
--- src/hg/hgc/hgc.c
+++ src/hg/hgc/hgc.c
@@ -4738,30 +4738,224 @@
 printf("<BR>Statistics on the scores of all items in window (go to track controls to set minimum score to display):\n");
 
 printf("<TABLE BORDER=1>\n");
 printf("<TR><TD><B>Q1</B></TD><TD>%f</TD></TR>\n", as->q1);
 printf("<TR><TD><B>median</B></TD><TD>%f</TD></TR>\n", as->median);
 printf("<TR><TD><B>Q3</B></TD><TD>%f</TD></TR>\n", as->q3);
 printf("<TR><TD><B>average</B></TD><TD>%f</TD></TR>\n", as->average);
 printf("<TR><TD><B>min</B></TD><TD>%f</TD></TR>\n", as->minVal);
 printf("<TR><TD><B>max</B></TD><TD>%f</TD></TR>\n", as->maxVal);
 printf("<TR><TD><B>count</B></TD><TD>%d</TD></TR>\n", as->count);
 printf("<TR><TD><B>total</B></TD><TD>%f</TD></TR>\n", as->total);
 printf("<TR><TD><B>standard deviation</B></TD><TD>%f</TD></TR>\n", as->stdDev);
 printf("</TABLE>\n");
 }
 
+void quickLiftChainClick(struct sqlConnection *conn, struct trackDb *tdb,
+                       char *item, int start, char *otherDb)
+/* Handle a click on the quickChain track */
+{
+struct twoBitFile *otherTbf = getOtherTwoBitUrl(tdb);
+char *otherOrg = NULL;
+struct chain *chain = NULL, *subChain = NULL, *toFree = NULL;
+int chainWinSize;
+boolean otherIsActive = FALSE;
+
+if (hDbIsActive(otherDb))
+    otherIsActive = TRUE;
+
+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));
+    }
+
+chain = chainLoadItemInRange(tdb, item);
+if (startsWith("big", tdb->type))
+    {
+    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;
+            }
+        }
+    }
+
+chainSubsetOnT(chain, winStart, winEnd, &subChain, &toFree);
+
+char position[128];
+char *ourPos, *otherPos;
+int seqStart = cartInt(cart, "l");
+int seqEnd =   cartInt(cart, "r");
+char *chromName = cartString(cart, "c");
+safef(position, 128, "%s:%d-%d", chromName, seqStart, seqEnd);
+ourPos = cloneString(addCommasToPos(database, position));
+printf("<B>%s position:</B> %s<BR>", trackHubSkipHubName(database), ourPos);
+
+int qs,qe;
+qChainRangePlusStrand(subChain, &qs, &qe);
+safef(position, 128, "%s:%d-%d", subChain->qName, qs-1, qe);
+otherPos = cloneString(addCommasToPos(otherDb, position));
+printf("<B>%s position: </B>", trackHubSkipHubName(otherDb));
+linkToOtherBrowser(otherDb, subChain->qName, qs-1, qe);
+printf("%s</A><BR><BR>",  otherPos);
+chainWinSize = min(winEnd-winStart, chain->tEnd - chain->tStart);
+
+if (otherTbf != NULL || 
+    (!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 of whole window.</A><BR><BR>");
+        }
+    else
+        {
+        printf("Zoom so that browser window covers 1,000,000 bases or less "
+           "and return here to see alignment details.<BR>\n");
+        }
+    }
+
+char *liftDb = cloneString(trackDbSetting(tdb, "quickLiftDb"));
+char *quickLiftFile = cloneString(trackDbSetting(tdb, "quickLiftUrl"));
+struct quickLiftRegions *hr, *regions = quickLiftGetRegions(database, liftDb, quickLiftFile, chromName, seqStart, seqEnd);
+
+unsigned deletions = 0;
+unsigned insertions = 0;
+unsigned mismatches = 0;
+unsigned doubles = 0;
+
+for(hr = regions; hr; hr = hr->next)
+    {
+    switch(hr->type)
+        {
+        case QUICKTYPE_INSERT:
+            insertions++;
+            break;
+        case QUICKTYPE_DEL:
+            deletions++;
+            break;
+        case QUICKTYPE_DOUBLE:
+            doubles++;
+            break;
+        case QUICKTYPE_MISMATCH:
+            mismatches++;
+            break;
+        }
+    }
+
+if (deletions)
+    {
+    printf("<BR><B>Deletions in Window:</B><BR>");
+    printf("<TABLE border=\"1\"> <TR>\n");
+    printf("<TR><TD>%s Position</TD><TD>%s Position</TD><TD>Bases</TD><TD>Alignment</TD><TR>", trackHubSkipHubName(database), trackHubSkipHubName(otherDb));
+    for(hr = regions; hr; hr = hr->next)
+        {
+        if (hr->type != QUICKTYPE_DEL)
+            continue;
+
+        char *ourPos, *otherPos;
+        snprintf(position, 128, "%s:%ld-%ld", hr->chrom, hr->chromStart, hr->chromEnd);
+        ourPos = cloneString(addCommasToPos(database, position));
+        snprintf(position, 128, "%s:%ld-%ld", hr->oChrom, hr->oChromStart, hr->oChromEnd);
+        otherPos = cloneString(addCommasToPos(database, position));
+        printf("<TR><TD>%s</TD><TD>%s</TD><TD>%.*s</TD><TD>",   ourPos, otherPos, hr->otherBaseCount, hr->otherBases);
+        hgcAnchorSomewhereExt("htcChainAli", item, tdb->track, chain->tName, hr->chromStart - 10, hr->chromEnd + 10, tdb->track);
+            printf("alignment</A></TD></TR>");
+
+        }
+    printf("</TABLE>");
+    }
+
+if (insertions)
+    {
+    printf("<BR><B>Insertions in Window:</B><BR>");
+    printf("<TABLE border=\"1\"> <TR>\n");
+    printf("<TR><TD>%s Position</TD><TD>%s Position</TD><TD>Bases</TD><TD>Alignment</TD><TR>", trackHubSkipHubName(database), trackHubSkipHubName(otherDb));
+    for(hr = regions; hr; hr = hr->next)
+        {
+        if (hr->type != QUICKTYPE_INSERT)
+            continue;
+
+        char *ourPos, *otherPos;
+        snprintf(position, 128, "%s:%ld-%ld", hr->chrom, hr->chromStart, hr->chromEnd);
+        ourPos = cloneString(addCommasToPos(database, position));
+        snprintf(position, 128, "%s:%ld-%ld", hr->oChrom, hr->oChromStart, hr->oChromEnd);
+        otherPos = cloneString(addCommasToPos(database, position));
+        printf("<TR><TD>%s</TD><TD>%s</TD><TD>%.*s</TD><TD>",   ourPos, otherPos, hr->baseCount, hr->bases);
+        hgcAnchorSomewhereExt("htcChainAli", item, tdb->track, chain->tName, hr->chromStart - 10, hr->chromEnd + 10, tdb->track);
+            printf("alignment</A></TD></TR>");
+
+        }
+    printf("</TABLE>");
+    }
+
+if (doubles)
+    {
+    printf("<BR><B>Double Gaps in Window:</B><BR>");
+    printf("<TABLE border=\"1\"> <TR>\n");
+    printf("<TR><TD>%s Position</TD><TD>%s Position</TD><TD># Bases in %s</TD><TD>#Bases in %s</TD><TD>Alignment</TD><TR>", trackHubSkipHubName(database), trackHubSkipHubName(otherDb), trackHubSkipHubName(database), trackHubSkipHubName(otherDb));
+    for(hr = regions; hr; hr = hr->next)
+        {
+        if (hr->type != QUICKTYPE_DOUBLE)
+            continue;
+
+        char *ourPos, *otherPos;
+        snprintf(position, 128, "%s:%ld-%ld", hr->chrom, hr->chromStart, hr->chromEnd);
+        ourPos = cloneString(addCommasToPos(database, position));
+        snprintf(position, 128, "%s:%ld-%ld", hr->oChrom, hr->oChromStart, hr->oChromEnd);
+        otherPos = cloneString(addCommasToPos(database, position));
+        printf("<TR><TD>%s</TD><TD>%s</TD><TD>%d</TD><TD>%d</TD><TD>",   ourPos, otherPos, hr->baseCount, hr->otherBaseCount);
+        hgcAnchorSomewhereExt("htcChainAli", item, tdb->track, chain->tName, hr->chromStart - 10, hr->chromEnd + 10, tdb->track);
+            printf("alignment</A></TD></TR>");
+
+        }
+    printf("</TABLE>");
+    }
+
+if (mismatches)
+    {
+    printf("<BR><B>Mismatches in Window:</B><BR>");
+    printf("<TABLE border=\"1\"> <TR>\n");
+    printf("<TR><TD>%s Position</TD><TD>%s Position</TD><TD>Change</TD><TD>Alignment</TD><TR>", trackHubSkipHubName(database), trackHubSkipHubName(otherDb));
+    for(hr = regions; hr; hr = hr->next)
+        {
+        if (hr->type != QUICKTYPE_MISMATCH)
+            continue;
+
+        char *ourPos, *otherPos;
+        snprintf(position, 128, "%s:%ld-%ld", hr->chrom, hr->chromStart, hr->chromEnd);
+        ourPos = cloneString(addCommasToPos(database, position));
+        snprintf(position, 128, "%s:%ld-%ld", hr->oChrom, hr->oChromStart, hr->oChromEnd);
+        otherPos = cloneString(addCommasToPos(database, position));
+        printf("<TR><TD>%s</TD><TD>%s</TD><TD>%.*s -> %.*s</TD><TD>",   ourPos, otherPos, hr->otherBaseCount, hr->otherBases, hr->baseCount, hr->bases);
+        hgcAnchorSomewhereExt("htcChainAli", item, tdb->track, chain->tName, hr->chromStart - 10, hr->chromEnd + 10, tdb->track);
+            printf("alignment</A></TD></TR>");
+
+        }
+    printf("</TABLE>");
+    }
+}
 void genericClickHandlerPlus(
         struct trackDb *tdb, char *item, char *itemForUrl, char *plus)
 /* Put up generic track info, with additional text appended after item. */
 {
 char *dupe, *type, *words[16], *headerItem;
 int wordCount;
 int start = cartInt(cart, "o");
 int end = cartInt(cart, "t");
 struct sqlConnection *conn = NULL;
 char *imagePath = trackDbSetting(tdb, ITEM_IMAGE_PATH);
 char *container = trackDbSetting(tdb, "container");
 
 char *liftDb = cloneString(trackDbSetting(tdb, "quickLiftDb"));
 
 if (liftDb)
@@ -4864,30 +5058,34 @@
 	genericBigPslClick(conn, tdb, item, start, end);
 	}
     else if (sameString(type, "psl"))
         {
 	char *subType = ".";
 	if (wordCount > 1)
 	    subType = words[1];
 	genericPslClick(conn, tdb, item, start, subType);
 	}
     else if (sameString(type, "netAlign"))
         {
 	if (wordCount < 3)
 	    errAbort("Missing field in netAlign track type field");
 	genericNetClick(conn, tdb, item, start, words[1], words[2]);
 	}
+    else if (sameString(type, "bigQuickLiftChain")) 
+        {
+	quickLiftChainClick(conn, tdb, item, start, words[1]);
+	}
     else if (sameString(type, "chain") || sameString(type, "bigChain") )
         {
 	if (wordCount < 2)
 	    errAbort("Missing field in chain track type field");
 	genericChainClick(conn, tdb, item, start, words[1]);
 	}
     else if (sameString(type, "maf"))
         {
 	genericMafClick(conn, tdb, item, start);
 	}
     else if (sameString(type, "wigMaf") ||  sameString(type, "bigMaf"))
         {
 	genericMafClick(conn, tdb, item, start);
         }
     else if (startsWith("wigMafProt", type))