a520a3e8703485e62c9bbabb43443f02a08c45ad
max
  Wed Aug 19 07:29:21 2020 -0700
committing code for the "related tracks" feature. This will have no effect on the RR, as the table does not exist there. The main point of the commit is to allow chris to start modifying the code without a manual copy. refs #25721

diff --git src/hg/hgc/hgc.c src/hg/hgc/hgc.c
index b59e42b..f82f4cc 100644
--- src/hg/hgc/hgc.c
+++ src/hg/hgc/hgc.c
@@ -3122,56 +3122,129 @@
 {
 trackDbPrintOrigAssembly(tdb, database);
 }
 
 static char *getHtmlFromSelfOrParent(struct trackDb *tdb)
 /* Get html from self or from parent if not in self. */
 {
 for (;tdb != NULL; tdb = tdb->parent)
     {
     if (tdb->html != NULL && tdb->html[0] != 0)
         return tdb->html;
     }
 return NULL;
 }
 
+void printHtmlAddRelated(struct trackDb *tdb, char *html)
+/* print the track description html and try to inject the "related track" section */
+{
+struct sqlConnection *conn = hAllocConn(database);
+if (!sqlTableExists(conn, "relatedTrack"))
+    {
+    puts(html);
+    hFreeConn(&conn);
+    return;
+    }
+
+char query[256];
+sqlSafef(query, sizeof(query),
+    "select track1, track2, why from relatedTrack where track1='%s' or track2='%s'",  tdb->track, tdb->track);
+
+char **row;
+struct sqlResult *sr;
+sr = sqlGetResult(conn, query);
+row = sqlNextRow(sr);
+if (row == NULL)
+    {
+    puts(html);
+    hFreeConn(&conn);
+    sqlFreeResult(&sr);
+    return;
+    }
+
+char *lines[10000];
+int lineCount = chopByChar(html, '\n', lines, ArraySize(lines));
+
+char* refLine1 = "<H2>References</H2>";
+char* refLine2 = "<h2>References</h2>";
+
+int lineIdx;
+for (lineIdx = 0; lineIdx < lineCount; lineIdx++)
+    {
+    char *line = lines[lineIdx];
+    if ( !sameWord(line, "<RELATED>") && !sameWord(line, refLine1) && !sameWord(line, refLine2))
+        {
+        puts(line);
+        continue;
+        } 
+
+    puts("<H2>Related tracks</H2>\n");
+    puts("<ul>\n");
+    do
+        {
+        char *track1 = row[0];
+        char *track2 = row[1];
+        char *why    = row[2];
+
+        char* otherTrack;
+        if (sameWord(track1, tdb->track))
+            otherTrack = track2;
+        else
+            otherTrack = track1;
+
+        struct trackDb *otherTdb = hashFindVal(trackHash, otherTrack);
+        puts("<li>");
+        puts(otherTdb->shortLabel);
+        puts(": ");
+        puts(why);
+        } while ((row = sqlNextRow(sr)) != NULL);
+    puts("</ul>\n");
+
+    if (sameWord(line, refLine1) || sameWord(line, refLine2))
+        puts(line);
+    }
+
+hFreeConn(&conn);
+sqlFreeResult(&sr);
+}
+
 void printTrackHtml(struct trackDb *tdb)
 /* If there's some html associated with track print it out. Also print
  * last update time for data table and make a link
  * to the TB table schema page for this table. */
 {
 if (!isCustomTrack(tdb->track))
     {
     extraUiLinks(database, tdb);
     printTrackUiLink(tdb);
     printOrigAssembly(tdb);
     printDataVersion(database, tdb);
     printUpdateTime(database, tdb, NULL);
     printDataRestrictionDate(tdb);
     }
 char *html = getHtmlFromSelfOrParent(tdb);
 if (html != NULL && html[0] != 0)
     {
     htmlHorizontalLine();
 
     // Add pennantIcon
     printPennantIconNote(tdb);
 
     // Wrap description html in div with limited width, so when the page is very wide
     // due to long details, the user doesn't have to scroll right to read the description.
     puts("<div class='readableWidth'>");
-    puts(html);
+    printHtmlAddRelated(tdb, html);
     puts("</div>");
     }
 hPrintf("<BR>\n");
 }
 
 void qChainRangePlusStrand(struct chain *chain, int *retQs, int *retQe)
 /* Return range of bases covered by chain on q side on the plus
  * strand. */
 {
 if (chain == NULL)
     errAbort("Can't find range in null query chain.");
 if (chain->qStrand == '-')
     {
     *retQs = chain->qSize - chain->qEnd+1;
     *retQe = chain->qSize - chain->qStart;