3bbad1670f2e44ca41d06c657b8f8636abfce4fb
hiram
  Wed Mar 27 14:47:11 2019 -0700
provide list chrom function for hubs refs #18869

diff --git src/hg/hubApi/list.c src/hg/hubApi/list.c
index 8b0358d..24b75db 100644
--- src/hg/hubApi/list.c
+++ src/hg/hubApi/list.c
@@ -125,41 +125,178 @@
     {
     }
 // jsonWriteListStart(jw, "ucscGenomes");
 jsonWriteObjectStart(jw, "ucscGenomes");
 for ( el=dbList; el != NULL; el = el->next )
     {
     dbDbJsonData(jw, el, columnCount, columnNames);
     }
 // jsonWriteListEnd(jw);
 jsonWriteObjectEnd(jw);
 jsonWriteObjectEnd(jw);
 fputs(jw->dy->string,stdout);
 hDisconnectCentral(&conn);
 }
 
+static void hubChromInfoJsonOutput(FILE *f, char *hubUrl, char *genome)
+/* for given hubUrl list the chromosomes in the sequence for specified genome
+ */
+{
+struct trackHub *hub = errCatchTrackHubOpen(hubUrl);
+struct trackHubGenome *ge = NULL;
+char *track = cgiOptionalString("track");
+
+if (isEmpty(genome))
+    apiErrAbort("must specify a 'genome=name' with hubUrl for endpoint: /list/chromosomes?hubUrl=%s&genome=<empty>", hubUrl);
+
+struct trackHubGenome *foundGenome = NULL;
+
+for (ge = hub->genomeList; ge; ge = ge->next)
+    {
+    if (sameOk(genome, ge->name))
+	{
+	foundGenome = ge;
+	continue;	/* found genome */
+	}
+    }
+if (NULL == foundGenome)
+    apiErrAbort("can not find specified 'genome=%s' for endpoint: /list/chromosomes?hubUrl=%s&genome=%s", genome, hubUrl, genome);
+
+struct jsonWrite *jw = apiStartOutput();
+jsonWriteString(jw, "hubUrl", hubUrl);
+jsonWriteString(jw, "genome", genome);
+if (isNotEmpty(track))
+    {
+    jsonWriteString(jw, "track", track);
+    struct trackDb *tdb = obtainTdb(foundGenome, NULL);
+    if (NULL == tdb)
+	apiErrAbort("failed to find a track hub definition in genome=%s for endpoint '/list/chromosomes' give hubUrl=%s'", genome, hubUrl);
+
+    struct trackDb *thisTrack = findTrackDb(track, tdb);
+    if (NULL == thisTrack)
+	apiErrAbort("failed to find specified track=%s in genome=%s for endpoint '/getdata/track'  given hubUrl='%s'", track, genome, hubUrl);
+
+    char *bigDataUrl = trackDbSetting(thisTrack, "bigDataUrl");
+    struct bbiFile *bbi = bigFileOpen(thisTrack->type, bigDataUrl);
+    struct bbiChromInfo *chrList = bbiChromList(bbi);
+    slSort(chrList, chromInfoCmp);
+    struct bbiChromInfo *el = chrList;
+    jsonWriteNumber(jw, "chromCount", (long long)slCount(chrList));
+    jsonWriteObjectStart(jw, "chromosomes");
+    for ( ; el; el = el->next )
+	{
+	jsonWriteNumber(jw, el->name, (long long)el->size);
+	}
+    jsonWriteObjectEnd(jw);	/* chromosomes */
+    }
+else
+    {
+    struct chromInfo *ci = trackHubAllChromInfo(foundGenome->name);
+    slSort(ci, chromInfoCmp);
+    jsonWriteNumber(jw, "chromCount", (long long)slCount(ci));
+    jsonWriteObjectStart(jw, "chromosomes");
+    struct chromInfo *el = ci;
+    for ( ; el != NULL; el = el->next )
+	{
+	jsonWriteNumber(jw, el->chrom, (long long)el->size);
+	}
+    jsonWriteObjectEnd(jw);	/* chromosomes */
+    }
+jsonWriteObjectEnd(jw);	/* top level */
+fputs(jw->dy->string,stdout);
+
+#ifdef NOT
+char *table = cgiOptionalString("track");
+struct sqlConnection *conn = hAllocConn(db);
+/* in trackDb language: track == table */
+if (table)
+    {
+    if (! sqlTableExists(conn, table))
+	apiErrAbort("can not find specified 'track=%s' for endpoint: /list/chromosomes?db=%s&track=%s", table, db, table);
+    if (sqlColumnExists(conn, table, "chrom"))
+	{
+	char *dataTime = sqlTableUpdate(conn, table);
+	time_t dataTimeStamp = sqlDateToUnixTime(dataTime);
+	replaceChar(dataTime, ' ', 'T');	/* ISO 8601 */
+        struct jsonWrite *jw = apiStartOutput();
+	jsonWriteString(jw, "genome", db);
+	jsonWriteString(jw, "track", table);
+	jsonWriteString(jw, "dataTime", dataTime);
+	jsonWriteNumber(jw, "dataTimeStamp", (long long)dataTimeStamp);
+	freeMem(dataTime);
+        struct slPair *list = NULL;
+	char query[2048];
+        sqlSafef(query, sizeof(query), "select distinct chrom from %s", table);
+	struct sqlResult *sr = sqlGetResult(conn, query);
+	char **row;
+	while ((row = sqlNextRow(sr)) != NULL)
+    	{
+            int size = hChromSize(db, row[0]);
+	    slAddHead(&list, slPairNew(row[0], intToPt(size)));
+    	}
+	sqlFreeResult(&sr);
+        slPairIntSort(&list);
+        slReverse(&list);
+        jsonWriteNumber(jw, "chromCount", (long long)slCount(list));
+	jsonWriteObjectStart(jw, "chromosomes");
+        struct slPair *el = list;
+        for ( ; el != NULL; el = el->next )
+            jsonWriteNumber(jw, el->name, (long long)ptToInt(el->val));
+	jsonWriteObjectEnd(jw);	/* chromosomes */
+        jsonWriteObjectEnd(jw);	/* top level */
+        fputs(jw->dy->string,stdout);
+	}
+    else
+	apiErrAbort("track '%s' is not a position track, request table without chrom specification, genome: '%s'", table, db);
+    }
+else
+    {
+    char *dataTime = sqlTableUpdate(conn, "chromInfo");
+    time_t dataTimeStamp = sqlDateToUnixTime(dataTime);
+    replaceChar(dataTime, ' ', 'T');	/* ISO 8601 */
+    struct chromInfo *ciList = createChromInfoList(NULL, db);
+    slSort(ciList, chromInfoCmp);
+    struct chromInfo *el = ciList;
+    struct jsonWrite *jw = apiStartOutput();
+    jsonWriteString(jw, "genome", db);
+    jsonWriteString(jw, "dataTime", dataTime);
+    jsonWriteNumber(jw, "dataTimeStamp", (long long)dataTimeStamp);
+    freeMem(dataTime);
+    jsonWriteNumber(jw, "chromCount", (long long)slCount(ciList));
+    jsonWriteObjectStart(jw, "chromosomes");
+    for ( ; el != NULL; el = el->next )
+	{
+        jsonWriteNumber(jw, el->chrom, (long long)el->size);
+	}
+    jsonWriteObjectEnd(jw);	/* chromosomes */
+    jsonWriteObjectEnd(jw);	/* top level */
+    fputs(jw->dy->string,stdout);
+    }
+hFreeConn(&conn);
+#endif
+}
+
 static void chromInfoJsonOutput(FILE *f, char *db)
 /* for given db, if there is a track, list the chromosomes in that track,
  * for no track, simply list the chromosomes in the sequence
  */
 {
 char *table = cgiOptionalString("track");
 struct sqlConnection *conn = hAllocConn(db);
 /* in trackDb language: track == table */
 if (table)
     {
-    /* XXX TBD - expand this to a hub to get chromosomes from hub big* file */
     if (! sqlTableExists(conn, table))
 	apiErrAbort("can not find specified 'track=%s' for endpoint: /list/chromosomes?db=%s&track=%s", table, db, table);
     if (sqlColumnExists(conn, table, "chrom"))
 	{
 	char *dataTime = sqlTableUpdate(conn, table);
 	time_t dataTimeStamp = sqlDateToUnixTime(dataTime);
 	replaceChar(dataTime, ' ', 'T');	/* ISO 8601 */
         struct jsonWrite *jw = apiStartOutput();
 	jsonWriteString(jw, "genome", db);
 	jsonWriteString(jw, "track", table);
 	jsonWriteString(jw, "dataTime", dataTime);
 	jsonWriteNumber(jw, "dataTimeStamp", (long long)dataTimeStamp);
 	freeMem(dataTime);
         struct slPair *list = NULL;
 	char query[2048];
@@ -176,35 +313,35 @@
         slReverse(&list);
         jsonWriteNumber(jw, "chromCount", (long long)slCount(list));
 	jsonWriteObjectStart(jw, "chromosomes");
         struct slPair *el = list;
         for ( ; el != NULL; el = el->next )
             jsonWriteNumber(jw, el->name, (long long)ptToInt(el->val));
 	jsonWriteObjectEnd(jw);	/* chromosomes */
         jsonWriteObjectEnd(jw);	/* top level */
         fputs(jw->dy->string,stdout);
 	}
     else
 	apiErrAbort("track '%s' is not a position track, request table without chrom specification, genome: '%s'", table, db);
     }
 else
     {
-    /* XXX TBD - expand this to a hub to get chromosomes from hub 2bit file */
     char *dataTime = sqlTableUpdate(conn, "chromInfo");
     time_t dataTimeStamp = sqlDateToUnixTime(dataTime);
     replaceChar(dataTime, ' ', 'T');	/* ISO 8601 */
     struct chromInfo *ciList = createChromInfoList(NULL, db);
+    slSort(ciList, chromInfoCmp);
     struct chromInfo *el = ciList;
     struct jsonWrite *jw = apiStartOutput();
     jsonWriteString(jw, "genome", db);
     jsonWriteString(jw, "dataTime", dataTime);
     jsonWriteNumber(jw, "dataTimeStamp", (long long)dataTimeStamp);
     freeMem(dataTime);
     jsonWriteNumber(jw, "chromCount", (long long)slCount(ciList));
     jsonWriteObjectStart(jw, "chromosomes");
     for ( ; el != NULL; el = el->next )
 	{
         jsonWriteNumber(jw, el->chrom, (long long)el->size);
 	}
     jsonWriteObjectEnd(jw);	/* chromosomes */
     jsonWriteObjectEnd(jw);	/* top level */
     fputs(jw->dy->string,stdout);
@@ -215,31 +352,30 @@
 static void recursiveTrackList(struct jsonWrite *jw, struct trackDb *tdb)
 /* output trackDb tags only for real tracks, not containers,
  * recursive when subtracks exist
  */
 {
 if (! ( tdbIsComposite(tdb) || tdbIsCompositeView(tdb) ) )
     {
     jsonWriteObjectStart(jw, tdb->track);
     jsonWriteString(jw, "shortLabel", tdb->shortLabel);
     jsonWriteString(jw, "type", tdb->type);
     jsonWriteString(jw, "longLabel", tdb->longLabel);
     if (tdb->parent)
 	jsonWriteString(jw, "parent", tdb->parent->track);
     if (tdb->settingsHash)
 	{
-	jsonWriteString(jw, "hasSettingsHash", "TRUE");
 	struct hashEl *hel;
 	struct hashCookie hc = hashFirst(tdb->settingsHash);
 	while ((hel = hashNext(&hc)) != NULL)
 	    {
 	    if (sameWord("track", hel->name))
 		continue;	// already output in header
 	    if (isEmpty((char *)hel->val))
 		jsonWriteString(jw, hel->name, "empty");
 	    else
 		jsonWriteString(jw, hel->name, (char *)hel->val);
 	    }
 	}
     jsonWriteObjectEnd(jw);
     }
 
@@ -357,29 +493,34 @@
 	jsonWriteString(jw, "hubUrl", hubUrl);
 	jsonWriteObjectStart(jw, genome);
 	struct trackDb *el = NULL;
 	for (el = tdbList; el != NULL; el = el->next )
 	    {
 	    recursiveTrackList(jw, el);
 	    }
 	jsonWriteObjectEnd(jw);
 	jsonWriteObjectEnd(jw);
         fputs(jw->dy->string,stdout);
 	}
     }
 else if (sameWord("chromosomes", words[1]))
     {
     char *hubUrl = cgiOptionalString("hubUrl");
-//    char *genome = cgiOptionalString("genome");
+    char *genome = cgiOptionalString("genome");
     char *db = cgiOptionalString("db");
     if (isEmpty(hubUrl) && isEmpty(db))
-        apiErrAbort("ERROR: must supply hubUrl or db name to return chromosome list");
+        apiErrAbort("ERROR: must '%s' '%s' supply hubUrl or db name to return chromosome list", hubUrl, db);
 
     if (isEmpty(hubUrl))	// missing hubUrl implies UCSC database
 	{
         chromInfoJsonOutput(stdout, db);
 	return;
 	}
+    else
+	{
+        hubChromInfoJsonOutput(stdout, hubUrl, genome);
+	return;
+	}
     }
 else
     apiErrAbort("do not recognize endpoint function: '/%s/%s'", words[0], words[1]);
 }	/*	void apiList(char *words[MAX_PATH_INFO])        */