c791c339c5a9110259039a77b45b0965c17cfcbb
larrym
  Thu Jul 28 21:28:13 2011 -0700
add JSON Element code to represent JSON in memory and print out to html (redmine #4550)
diff --git src/hg/lib/jsHelper.c src/hg/lib/jsHelper.c
index afa079e..a70a7de 100644
--- src/hg/lib/jsHelper.c
+++ src/hg/lib/jsHelper.c
@@ -475,80 +475,209 @@
        "onclick=\"return setTableRowVisibility(this, '%s', '%s.section', 'section', true);\" "
        "id='%s_button' src='%s' alt='%s' title='%s this section' class='bigBlue'"
        " style='cursor:pointer;'>\n",
        section, track,
        section, buttonImage, (isOpen ? "-" : "+"), (isOpen ? "Collapse": "Expand"));
 printf("<B style='font-size:larger;'>&nbsp;%s</B></TD></TR>\n", sectionTitle);
 printf("<TR %sid='%s-%d'><TD colspan=2>", isOpen ? "" : "style='display: none' ", section, 1);
 }
 
 void jsEndCollapsibleSection()
 /* End the collapsible <TR id=...>. */
 {
 puts("</TD></TR>");
 }
 
-void jsAddString(struct hash *h, char *name, char *val)
+struct jsonStringElement *newJsonString(char *str)
+{
+struct jsonStringElement *ele;
+AllocVar(ele);
+ele->str = cloneString(str);
+ele->type = jsonString;
+return ele;
+}
+
+struct jsonHashElement *newJsonHash(struct hash *h)
+{
+struct jsonHashElement *ele;
+AllocVar(ele);
+ele->type = jsonHash;
+ele->hash = h;
+return ele;
+}
+
+struct jsonListElement *newJsonList(struct slRef *list)
+{
+struct jsonListElement *ele;
+AllocVar(ele);
+ele->type = jsonList;
+ele->list = list;
+return ele;
+}
+
+void jsonHashAdd(struct jsonHashElement *h, char *name, struct jsonElement *ele)
+{
+hashReplace(h->hash, name, ele);
+}
+
+void jsonHashAddString(struct jsonHashElement *h, char *name, char *val)
 {
 // Add a string to a hash which will be used to print a javascript object;
 // existing values are replaced.
-char *str = needMem(strlen(val) + 3);
 val = javaScriptLiteralEncode(val);
+char *str = needMem(strlen(val) + 3);
 sprintf(str, "'%s'", val);
 freez(&val);
-hashReplace(h, name, str);
+jsonHashAdd(h, name, (struct jsonElement *) newJsonString(str));
 }
 
-void jsAddNumber(struct hash *h, char *name, long val)
+void jsonHashAddNumber(struct jsonHashElement *h, char *name, long val)
 {
 // Add a number to a hash which will be used to print a javascript object;
 // existing values are replaced.
 char buf[256];
 safef(buf, sizeof(buf), "%ld", val);
-hashReplace(h, name, cloneString(buf));
+jsonHashAdd(h, name, (struct jsonElement *) newJsonString(buf));
+}
+
+void jsonHashAddDouble(struct jsonHashElement *h, char *name, double val)
+{
+// Add a number to a hash which will be used to print a javascript object;
+// existing values are replaced.
+char buf[256];
+safef(buf, sizeof(buf), "%.10f", val);
+jsonHashAdd(h, name, (struct jsonElement *) newJsonString(buf));
 }
 
-void jsAddBoolean(struct hash *h, char *name, boolean val)
+void jsonHashAddBoolean(struct jsonHashElement *h, char *name, boolean val)
 {
 // Add a boolean to a hash which will be used to print a javascript object;
 // existing values are replaced.
-hashReplace(h, name, cloneString(val ? "true" : "false"));
+jsonHashAdd(h, name, (struct jsonElement *) newJsonString(val ? "true" : "false"));
 }
 
-void jsPrintHash(struct hash *hash, char *name, int indentLevel)
+void jsonListAdd(struct slRef **list, struct jsonElement *ele)
 {
-// prints a hash as a javascript variable
+struct slRef *e;
+AllocVar(e);
+e->val = ele;
+slAddHead(list, e);
+}
 
-int i;
+void jsonListAddString(struct slRef **list, char *val)
+{
+val = javaScriptLiteralEncode(val);
+char *str = needMem(strlen(val) + 3);
+sprintf(str, "'%s'", val);
+freez(&val);
+jsonListAdd(list, (struct jsonElement *) newJsonString(str));
+}
+
+void jsonListAddNumber(struct slRef **list, long val)
+{
+char buf[256];
+safef(buf, sizeof(buf), "%ld", val);
+jsonListAdd(list, (struct jsonElement *) newJsonString(buf));
+}
+
+void jsonListAddDouble(struct slRef **list, double val)
+{
+char buf[256];
+safef(buf, sizeof(buf), "%.10f", val);
+jsonListAdd(list, (struct jsonElement *) newJsonString(buf));
+}
+
+void jsonListAddBoolean(struct slRef **list, boolean val)
+{
+jsonListAdd(list, (struct jsonElement *) newJsonString(val ? "true" : "false"));
+}
+
+static char *makeIndentBuf(int indentLevel)
+{
 char *indentBuf;
 indentBuf = needMem(indentLevel + 1);
-for (i = 0; i < indentLevel; i++)
-    indentBuf[i] = '\t';
-indentBuf[i] = 0;
-if(hashNumEntries(hash))
+memset(indentBuf, '\t', indentLevel);
+indentBuf[indentLevel] = 0;
+return indentBuf;
+}
+
+static void jsonPrintRecurse(struct jsonElement *json, int indentLevel)
     {
-    struct hashEl *el, *list = hashElListHash(hash);
+char *indentBuf = makeIndentBuf(indentLevel);
+switch (json->type)
+    {
+    case jsonHash:
+        {
+        struct jsonHashElement *ele = (struct jsonHashElement *) json;
+        hPrintf("{\n");
+        if(hashNumEntries(ele->hash))
+            {
+            struct hashEl *el, *list = hashElListHash(ele->hash);
     slSort(&list, hashElCmp);
-    // We add START and END comments to facilitate scraping out this variable by javascript.
-    hPrintf("// START %s\n%svar %s = {\n", name, indentBuf, name);
     for (el = list; el != NULL; el = el->next)
         {
-        hPrintf("%s\t\"%s\": %s%s\n", indentBuf, el->name, (char *) el->val, el->next == NULL ? "" : ",");
+                struct jsonElement *val = (struct jsonElement *) el->val;
+                hPrintf("%s\t\"%s\": ", indentBuf, el->name);
+                jsonPrintRecurse(val, indentLevel + 1);
+                hPrintf("%s\n", el->next == NULL ? "" : ",");
         }
-    hPrintf("%s};\n// END %s\n", indentBuf, name);
     hashElFreeList(&list);
     }
+        hPrintf("%s}", indentBuf);
+        break;
+        }
+    case jsonList:
+        {
+        struct jsonListElement *rec = (struct jsonListElement *) json;
+        struct slRef *el;
+        hPrintf("[\n");
+        if(rec->list)
+            {
+            for (el = rec->list; el != NULL; el = el->next)
+                {
+                struct jsonElement *val = (struct jsonElement *) el->val;
+                hPrintf("%s\t", indentBuf);
+                jsonPrintRecurse(val, indentLevel + 1);
+                hPrintf("%s\n", el->next == NULL ? "" : ",");
+                }
+            }
+        hPrintf("%s]", indentBuf);
+        break;
+        }
+    case jsonString:
+        {
+        hPrintf("%s", ((struct jsonStringElement *) json)->str);
+        break;
+        }
+    default:
+        {
+        errAbort("jsonPrintRecurse; invalid type: %d", json->type);
+        break;
+        }
+    }
+freez(&indentBuf);
+}
+
+void jsonPrint(struct jsonElement *json, char *name, int indentLevel)
+{
+// print out a jsonElement
+
+char *indentBuf = makeIndentBuf(indentLevel);
+hPrintf("// START %s\n%svar %s = ", name, indentBuf, name);
+jsonPrintRecurse(json, indentLevel);
+hPrintf("%s;\n// END %s\n", indentBuf, name);
+freez(&indentBuf);
 }
 
 void jsonErrPrintf(struct dyString *ds, char *format, ...)
 //  Printf a json error to a dyString for communicating with ajax code; format is:
 //  {"error": error message here}
 {
 va_list args;
 va_start(args, format);
 dyStringPrintf(ds, "{\"error\": \"");
 struct dyString *buf = newDyString(1000);
 dyStringVaPrintf(buf, format, args);
 dyStringAppend(ds, javaScriptLiteralEncode(dyStringCannibalize(&buf)));
 dyStringPrintf(ds, "\"}");
 va_end(args);
 }