77f17523d1115eb2fb85eaf747a76db0c6328204
hiram
  Mon Jan 28 14:05:59 2019 -0800
ready to start listing other things refs #18869

diff --git src/hg/hubApi/hubApi.c src/hg/hubApi/hubApi.c
index ddec85b..1122600 100644
--- src/hg/hubApi/hubApi.c
+++ src/hg/hubApi/hubApi.c
@@ -44,45 +44,44 @@
 
 struct hubPublic
 /* Table of public track data hub connections. */
     {
     struct hubPublic *next;  /* Next in singly linked list. */
     char *hubUrl;	/* URL to hub.ra file */
     char *shortLabel;	/* Hub short label. */
     char *longLabel;	/* Hub long label. */
     char *registrationTime;	/* Time first registered */
     unsigned dbCount;	/* Number of databases hub has data for. */
     char *dbList;	/* Comma separated list of databases. */
     char *descriptionUrl;	/* URL to description HTML */
     };
 
 /* Global Variables */
-struct cart *cart;             /* CGI and other variables */
-struct hash *oldVars = NULL;
+static struct cart *cart;             /* CGI and other variables */
+static struct hash *oldVars = NULL;
 static struct hash *trackCounter = NULL;
 static long totalTracks = 0;
 static boolean measureTiming = FALSE;	/* set by CGI parameters */
 static boolean allTrackSettings = FALSE;	/* checkbox setting */
 static char **shortLabels = NULL;	/* public hub short labels in array */
 static int publicHubCount = 0;
 static struct hubPublic *publicHubList = NULL;
 static char *defaultHub = "Plants";
 static long enteredMainTime = 0;	/* will become = clock1000() on entry */
 		/* to allow calculation of when to bail out, taking too long */
 static long timeOutSeconds = 100;
 static boolean timedOut = FALSE;
-static boolean jsonOutput = FALSE;	/* turns on when pathInfo present */
 
 /* ######################################################################### */
 
 /* json output needs to encode special characters in strings:
   " - quotation mark
   / - forward slash
   \ - back slash
   \n - new line
   \r - carriage return
   \t - tab
 */
 
 static char* jsonEscape(char *jsonString)
 /* escape any of the special characters in the string for json output */
 {
@@ -495,97 +494,140 @@
 
 static char *urlFromShortLabel(char *shortLabel)
 {
 char hubUrl[1024];
 char query[1024];
 struct sqlConnection *conn = hConnectCentral();
 // Build a query to select the hubUrl for the given shortLabel
 sqlSafef(query, sizeof(query), "select hubUrl from %s where shortLabel='%s'",
       hubPublicTableName(), shortLabel);
 if (! sqlQuickQuery(conn, query, hubUrl, sizeof(hubUrl)))
     hubUrl[0] = 0;
 hDisconnectCentral(&conn);
 return cloneString(hubUrl);
 }
 
-void jsonPublicHubs()
+static void jsonPublicHubs()
 {
 struct hubPublic *el = publicHubList;
 hPrintf("{\"publicHubs\":[");
 for ( ; el != NULL; el = el->next )
     {
     hubPublicJsonOutput(el, stdout);
     if (el->next)
        hPrintf(",");
     }
 hPrintf("]}\n");
 }
 
-void doMiddle(struct cart *theCart)
+#define MAX_PATH_INFO 32
+static void apiList(char *words[MAX_PATH_INFO])
+/* 'list' function */
+{
+if (sameWord("publicHubs", words[1]))
+    jsonPublicHubs();
+else if (sameWord("genomes", words[1]))
+    {
+    char *hubUrl = cgiOptionalString("hubUrl");
+    if (isNotEmpty(hubUrl))
+	{
+        hPrintf("# list genomes for hubUrl: '%s'\n", hubUrl);
+	}
+    else
+	errAbort("# must supply hubUrl='http:...' some URL to a hub for /list/genomes\n");
+    }
+else
+    errAbort("# ERROR: do not recognize '%s' for 'list' function\n", words[1]);
+}
+
+static struct hash *apiFunctionHash = NULL;
+
+static void setupFunctionHash()
+{
+if (apiFunctionHash)
+    return;
+
+apiFunctionHash = hashNew(0);
+hashAdd(apiFunctionHash, "list", &apiList);
+}
+
+static void apiFunctionSwitch(char *pathInfo)
+/* given a pathInfo string: /command/subCommand/etc...
+ *  parse that and decide on which function to acll
+ */
+{
+/* the leading slash has been removed from the pathInfo, therefore, the
+ * chop will have the first word in words[0]
+ */
+char *words[MAX_PATH_INFO];/*expect no more than MAX_PATH_INFO number of words*/
+int wordCount = chopByChar(pathInfo, '/', words, ArraySize(words));
+if (wordCount < 2)
+    errAbort("ERROR: no commands found in path info\n");
+
+void (*apiFunction)(char **) = hashMustFindVal(apiFunctionHash, words[0]);
+
+(*apiFunction)(words);
+
+}
+
+static void doMiddle(struct cart *theCart)
 /* Set up globals and make web page */
 {
 // struct hubPublic *hubList = hubPublicLoadAll();
 publicHubList = hubPublicLoadAll();
 cart = theCart;
 measureTiming = hPrintStatus() && isNotEmpty(cartOptionalString(cart, "measureTiming"));
 measureTiming = TRUE;
 char *database = NULL;
 char *genome = NULL;
 
 getDbAndGenome(cart, &database, &genome, oldVars);
 initGenbankTableNames(database);
 
 char *docRoot = cfgOptionDefault("browser.documentRoot", DOCUMENT_ROOT);
 
 int timeout = cartUsualInt(cart, "udcTimeout", 300);
 if (udcCacheTimeout() < timeout)
     udcSetCacheTimeout(timeout);
 knetUdcInstall();
 
 char *pathInfo = getenv("PATH_INFO");
 
-if ((NULL == pathInfo) || strlen(pathInfo) < 1)
+if (isNotEmpty(pathInfo))
     {
-    pathInfo = cloneString("noPathInfo");
-    }
-else
-    {
-    jsonOutput = TRUE;
-    }
-
-if (jsonOutput)
-    {
-//    startHtml("json output example");
-//    hPrintf("<br><a href='http://hgwdev-hiram.gi.ucsc.edu/cgi-bin/hubApi'>return to hubApi</a><br><br>\n");
-    jsonPublicHubs();
-//    endHtml();
+    /* skip the first leading slash to simplify chopByChar parsing */
+    pathInfo += 1;
+    setupFunctionHash();
+    apiFunctionSwitch(pathInfo);
     return;
     }
+
 cartWebStart(cart, database, "access mechanism to hub data resources");
 
 char *goOtherHub = cartUsualString(cart, "goOtherHub", defaultHub);
 char *otherHubUrl = cartUsualString(cart, "urlHub", defaultHub);
 char *goPublicHub = cartUsualString(cart, "goPublicHub", defaultHub);
 char *hubDropDown = cartUsualString(cart, "publicHubs", defaultHub);
 char *urlDropDown = urlFromShortLabel(hubDropDown);
 char *urlInput = urlDropDown;	/* assume public hub */
 if (sameWord("go", goOtherHub))	/* requested other hub URL */
     urlInput = otherHubUrl;
 
 hPrintf("<h2>Example URLs to return json data structures:</h2>\n");
 hPrintf("<ul>\n");
 hPrintf("<li><a href='/cgi-bin/hubApi/list/publicHubs'>list public hubs</a> <em>/cgi-bin/hubApi/list/publicHubs</em></li>\n");
+hPrintf("<li><a href='/cgi-bin/hubApi/list/genomes?hubUrl=%s'>list genomes from specified hub</a> <em>/cgi-bin/hubApi/list/genomes?hubUrl='%s'</em></li>\n", urlInput, urlInput);
 hPrintf("</ul>\n");
 long lastTime = clock1000();
 struct trackHub *hub = trackHubOpen(urlInput, "");
 if (measureTiming)
     {
     long thisTime = clock1000();
     hPrintf("<em>hub open time: %ld millis</em><br>\n", thisTime - lastTime);
     }
 
 hPrintf("<h4>cart dump</h4>");
 hPrintf("<pre>\n");
 cartDump(cart);
 hPrintf("</pre>\n");
 
 hPrintf("<form action='%s' name='hubApiUrl' id='hubApiUrl' method='GET'>\n\n", "../cgi-bin/hubApi");
@@ -615,31 +657,31 @@
 hPrintf("<br>\n&nbsp;&nbsp;");
 hCheckBox("depthSearch", cartUsualBoolean(cart, "depthSearch", FALSE));
 hPrintf("&nbsp;perform full bbi file measurement : %s (will time out if taking longer than %ld seconds)<br>\n", depthSearch ? "TRUE" : "FALSE", timeOutSeconds);
 hPrintf("\n&nbsp;&nbsp;");
 allTrackSettings = cartUsualBoolean(cart, "allTrackSettings", FALSE);
 hCheckBox("allTrackSettings", allTrackSettings);
 hPrintf("&nbsp;display all track settings for each track : %s<br>\n", allTrackSettings ? "TRUE" : "FALSE");
 
 
 hPrintf("<br>\n</form>\n");
 
 hPrintf("<p>URL: %s - %s<br>\n", urlInput, sameWord("go",goPublicHub) ? "public hub" : "other hub");
 hPrintf("name: %s<br>\n", hub->shortLabel);
 hPrintf("description: %s<br>\n", hub->longLabel);
 hPrintf("default db: '%s'<br>\n", isEmpty(hub->defaultDb) ? "(none available)" : hub->defaultDb);
-printf("pathInfo:'%s'<br>\ndocRoot:'%s'<br>\n", pathInfo, docRoot);
+printf("docRoot:'%s'<br>\n", docRoot);
 
 if (hub->genomeList)
     genomeList(hub);
 
 hPrintf("</p>\n");
 
 if (timedOut)
     hPrintf("<h1>Reached time out %ld seconds</h1>", timeOutSeconds);
 if (measureTiming)
     hPrintf("<em>Overall total time: %ld millis</em><br>\n", clock1000() - enteredMainTime);
 
 cartWebEnd();
 }	/*	void doMiddle(struct cart *theCart)	*/
 
 /* Null terminated list of CGI Variables we don't want to save