78623774789ddc510785fe261c9d8298538a9ad6
hiram
  Thu Aug 8 11:48:30 2013 -0700
fixup to eliminate globals, passing data in tg structure refs #9741 #11384
diff --git src/hg/hgTracks/joinedRmskTrack.c src/hg/hgTracks/joinedRmskTrack.c
index a31a033..16b11a7 100644
--- src/hg/hgTracks/joinedRmskTrack.c
+++ src/hg/hgTracks/joinedRmskTrack.c
@@ -10,43 +10,47 @@
 #include "jksql.h"
 #include "hdb.h"
 #include "hgTracks.h"
 #include "rmskJoined.h"
 
 /* winBaseCount size ( or below ) at which the detailed view
  * of repeats is turned on.
  */
 #define REPEAT_DETAIL_VIEW 100000
 
 /* The maximum size of unaligned sequence to draw before 
  * switching to the unscaled view: ie. "----//---"
  */
 #define MAX_UNALIGNED_LEN 200
 
-/* Hash of the repeatItems ( tg->items ) for this track.  
+/* classHash is the hash of the repeatItems ( tg->items ) for this track.  
  *   This is used to hold display names for the lines of
  *   the track, the line heights, and class colors.
- */
-struct hash *classHash = NULL;
-static struct repeatItem *otherRepeatItem = NULL;
-
-/* Hash of subtracks
+ *
+ * the subTracksHash is a hash of subtracks
  *   The joinedRmskTrack is designed to be used as a composite track.
  *   When jRepeatLoad is called this hash is populated with the 
  *   results of one or more table queries 
  */
-struct hash *subTracksHash = NULL;
+struct itemSpecifics
+/* extra information to go with each track */
+    {
+    struct hash *classHash;
+    struct repeatItem *otherRepeatItem;
+    struct hash *subTracksHash;
+    };
+
 struct subTrack
     {
     /* The number of display levels used in levels[] */
     int levelCount;
     /* The rmskJoined records from table query */
     struct rmskJoined *levels[30];
     };   
 
 // Display names
 static char *rptClassNames[] = {
   "SINE", "LINE", "LTR", "DNA", "Simple", "Low Complexity", "Satellite",
   "RNA", "Other", "Unknown",
 };
 
 // Data names
@@ -86,68 +90,71 @@
 static int
 cmpRepeatVisStart(const void *va, const void *vb)
 {
   const struct rmskJoined *a = *((struct rmskJoined **) va);
   const struct rmskJoined *b = *((struct rmskJoined **) vb);
   int aStart = a->chromStart;
   if (a->blockSizes[0] > MAX_UNALIGNED_LEN)
     aStart = a->chromStart + (a->blockSizes[0] - MAX_UNALIGNED_LEN);
   int bStart = b->chromStart;
   if (b->blockSizes[0] > MAX_UNALIGNED_LEN)
     bStart = b->chromStart + (b->blockSizes[0] - MAX_UNALIGNED_LEN);
   return (aStart - bStart);
 }
 
 /* Initialize the track */
-static struct repeatItem *
-makeJRepeatItems()
-{
+static void makeJRepeatItems(struct track *tg)
   /* Initialize the subtracks hash - This will eventually contain
    * all the repeat data for each displayed subtrack 
    */
-  subTracksHash = newHash(10);
+{
+  struct itemSpecifics *extraData;
+  AllocVar(extraData);
+
+  extraData->classHash = newHash(6);
+  extraData->otherRepeatItem = NULL;
+  extraData->subTracksHash = newHash(10);
+  tg->extraUiData = extraData;
 
-  classHash = newHash(6);
   struct repeatItem *ri, *riList = NULL;
   int i;
   int numClasses = ArraySize(rptClasses);
   for (i = 0; i < numClasses; ++i)
   {
     AllocVar(ri);
     ri->class = rptClasses[i];
     ri->className = rptClassNames[i];
     // New color attribute
     ri->color = jRepeatClassColors[i];
     slAddHead(&riList, ri);
     // Hash now prebuilt to hold color attributes
-    hashAdd(classHash, ri->class, ri);
+    hashAdd(extraData->classHash, ri->class, ri);
     if (sameString(rptClassNames[i], "Other"))
-      otherRepeatItem = ri;
+      extraData->otherRepeatItem = ri;
   }
   slReverse(&riList);
-  return riList;
+  tg->items = riList;
 }
 
-static void
-jRepeatLoad(struct track *tg)
+static void jRepeatLoad(struct track *tg)
 /* We do the query(ies) here so we can report how deep the track(s)
  * will be when jRepeatTotalHeight() is called later on 
  */ 
 {
-  tg->items = makeJRepeatItems();
+  makeJRepeatItems(tg);
+  struct itemSpecifics *extraData = tg->extraUiData;
 
-  fprintf(stderr, "Called jRepeatLoad: table = %s\n", tg->table );
   int baseWidth = winEnd - winStart;
   if ( tg->visibility == tvFull && baseWidth <= REPEAT_DETAIL_VIEW)
   {
     struct subTrack *st = NULL;
     AllocVar(st);
     if ( st )
     { 
       st->levels[0] = NULL;
       struct rmskJoined *rm = NULL;
       char **row;
       int rowOffset;
       struct sqlConnection *conn = hAllocConn(database);
       struct sqlResult *sr = hRangeQuery(conn, tg->table, chromName,
                                        winStart, winEnd, NULL,
                                        &rowOffset);
@@ -214,31 +221,31 @@
               crChromStart =
                 cr->chromStart + (cr->blockSizes[0] - MAX_UNALIGNED_LEN);
             crChromEnd = cr->chromEnd;
             if (cr->blockSizes[cr->blockCount - 1] > MAX_UNALIGNED_LEN)
               crChromEnd -=
                 (cr->blockSizes[cr->blockCount - 1] - MAX_UNALIGNED_LEN);
           }
           else
           {
             prev = rm;
             rm = rm->next;
           }
         } // while ( rm )
       } // while ( detailList )
       // Create Hash Entry
-      hashReplace(subTracksHash, tg->table, st);
+      hashReplace(extraData->subTracksHash, tg->table, st);
     } // if ( st )
   } // if ( tg->visibility == tvFull
 }
 
 static void
 jRepeatFree(struct track *tg)
 /* Free up jRepeatMasker items. */
 {
   slFreeList(&tg->items);
 }
 
 static char *
 jRepeatName(struct track *tg, void *item)
 /* Return name of jRepeat item track. */
 {
@@ -254,36 +261,37 @@
     if (strcmp(ri->className, "SINE") == 0)
     {
       return ("Repeats");
     }
     else
     {
       return &empty;
     }
   }
   return ri->className;
 }
 
 int
 jRepeatTotalHeight(struct track *tg, enum trackVisibility vis)
 {
+  struct itemSpecifics *extraData = tg->extraUiData;
   // Are we in full view mode and at the scale needed to display
   // the detail view?
   if (tg->limitedVis == tvFull && winBaseCount <= REPEAT_DETAIL_VIEW)
      {
         // Lookup the depth of this subTrack and report it
-        struct subTrack *st = hashFindVal(subTracksHash, tg->table );
+        struct subTrack *st = hashFindVal(extraData->subTracksHash, tg->table );
         if ( st )
           return ( (st->levelCount+1) * 24 );
         else
           // Just display one line
           return ( 24 );
      }
   else
     return tgFixedTotalHeightNoOverflow(tg, vis);
 }
 
 int
 jRepeatItemHeight(struct track *tg, void *item)
 {
   // Are we in full view mode and at the scale needed to display
   // the detail view?
@@ -563,31 +571,32 @@
  *
  *  Here is an example:
  *                ie. 
  *                A forward strand RM annotation from chr1:186-196
  *                which is aligned to a 100 bp repeat from 75-84
  *                in the consensus would be represented as:
  *
  *                chromStart: 111
  *                chromEnd: 212
  *                blockRelStarts: -1, 75, -1
  *                blockSizes: 75, 10, 16
  *
  */
 static void
 drawRMGlyph(struct hvGfx *hvg, int y, int heightPer,
-	    int width, int baseWidth, int xOff, struct rmskJoined *rm)
+   int width, int baseWidth, int xOff, struct rmskJoined *rm,
+      struct itemSpecifics *extraData)
 {
   int idx;
   int lx1, lx2;
   int cx1, cx2;
   int w;
   struct repeatItem *ri;
   /*
    * heightPer is the God given height of a single 
    * track item...respect your overlord.
    */
   int alignedBlockHeight = heightPer * 0.5;
   int alignedBlockOffset = heightPer - alignedBlockHeight;
   int unalignedBlockHeight = heightPer * 0.75;
   int unalignedBlockOffset = heightPer - unalignedBlockHeight;
 
@@ -607,33 +616,33 @@
     char *slashPtr = index(class, '/');
     if (slashPtr)
       *slashPtr = '\0';
   }
   else
   {
     safecpy(class, sizeof(class), "Unknown");
   }
   char *p = &(class[strlen(class) - 1]);
   if (*p == '?')
     *p = '\0';
   if (endsWith(class, "RNA"))
     safecpy(class, sizeof(class), "RNA");
 
   // Lookup the class to get the color scheme
-  ri = hashFindVal(classHash, class);
+  ri = hashFindVal(extraData->classHash, class);
   if (ri == NULL)
-    ri = otherRepeatItem;
+    ri = extraData->otherRepeatItem;
 
   // Pick the fill color based on the divergence
   int percId = 10000 - rm->score;
   int grayLevel = grayInRange(percId, 6000, 10000);
   fillColor = shadesOfGray[grayLevel];
   outlineColor = ri->color;
 
   // Draw from left to right
   for (idx = 0; idx < rm->blockCount; idx++)
   {
     int fragGStart = rm->blockRelStarts[idx];
 
     /*
      *  Assumptions about blockCount
      *   - first aligned block = 1, the block 0 is
@@ -918,30 +927,31 @@
 	}
       }
     }
   }
 
 }
 
 /* This is the original repeat drawing routine, modified
  * to handle the new rmskJoined table structure.  
  */
 static void
 origRepeatDraw(struct track *tg, int seqStart, int seqEnd,
 	       struct hvGfx *hvg, int xOff, int yOff, int width,
 	       MgFont * font, Color color, enum trackVisibility vis)
 {
+  struct itemSpecifics *extraData = tg->extraUiData;
   int baseWidth = seqEnd - seqStart;
   struct repeatItem *ri;
   int y = yOff;
   int heightPer = tg->heightPer;
   int lineHeight = tg->lineHeight;
   int x1, x2, w;
   boolean isFull = (vis == tvFull);
   Color col;
   struct sqlConnection *conn = hAllocConn(database);
   struct sqlResult *sr = NULL;
   char **row;
   int rowOffset;
 
   if (isFull)
   {
@@ -974,31 +984,31 @@
 	char *slashPtr = index(class, '/');
 	if (slashPtr)
 	  *slashPtr = '\0';
       }
       else
       {
 	safecpy(class, sizeof(class), "Unknown");
       }
       char *p = &(class[strlen(class) - 1]);
       if (*p == '?')
 	*p = '\0';
       if (endsWith(class, "RNA"))
 	safecpy(class, sizeof(class), "RNA");
       ri = hashFindVal(hash, class);
       if (ri == NULL)
-	ri = otherRepeatItem;
+	ri = extraData->otherRepeatItem;
       percId = 10000 - ro->score;
       grayLevel = grayInRange(percId, 6000, 10000);
       col = shadesOfGray[grayLevel];
 
       int idx = 0;
       for (idx = 0; idx < ro->blockCount; idx++)
       {
 	if (ro->blockRelStarts[idx] > 0)
 	{
 	  int blockStart = ro->chromStart + ro->blockRelStarts[idx];
 	  int blockEnd =
 	    ro->chromStart + ro->blockRelStarts[idx] + ro->blockSizes[idx];
 
 	  x1 = roundingScale(blockStart - winStart, width, baseWidth) + xOff;
 	  x1 = max(x1, 0);
@@ -1072,59 +1082,60 @@
     }
     dyStringFree(&query);
   }
   sqlFreeResult(&sr);
   hFreeConn(&conn);
 }
 
 /* Main callback for displaying this track in the viewport
  * of the browser.
  */
 static void
 jRepeatDraw(struct track *tg, int seqStart, int seqEnd,
 	    struct hvGfx *hvg, int xOff, int yOff, int width,
 	    MgFont * font, Color color, enum trackVisibility vis)
 {
+  struct itemSpecifics *extraData = tg->extraUiData;
   int baseWidth = seqEnd - seqStart;
   /*
    * Its unclear to me why heightPer is not updated to the
    * value set in jRepeatItemHeight() at the time this callback
    * is invoked.  Getting the correct value myself.
    * was:
    * int heightPer = tg->heightPer;
    */
   int heightPer = jRepeatItemHeight(tg, NULL);
   boolean isFull = (vis == tvFull);
   struct rmskJoined *rm;
 
   // If we are in full view mode and the scale is sufficient,
   // display the new visualization.
   if (isFull && baseWidth <= REPEAT_DETAIL_VIEW)
   {
     int level = yOff;
 
-    struct subTrack *st = hashFindVal(subTracksHash, tg->table );
+    struct subTrack *st = hashFindVal(extraData->subTracksHash, tg->table );
     if ( ! st )
       return;
     int lidx = st->levelCount;
     int currLevel = 0;
     for (currLevel = 0; currLevel < lidx; currLevel++)
     {
       rm = st->levels[currLevel];
       while (rm)
       {
-	drawRMGlyph(hvg, level, heightPer, width, baseWidth, xOff, rm);
+	drawRMGlyph(hvg, level, heightPer, width, baseWidth, xOff, rm, extraData);
 
 	char statusLine[128];
 	int ss1 = roundingScale(rm->alignStart - winStart,
 				width, baseWidth) + xOff;
         
 	safef(statusLine, sizeof(statusLine), "name: %s", rm->name );
 
 	int x1 =
 	  roundingScale(rm->alignStart - winStart, width, baseWidth) + xOff;
 	x1 = max(x1, 0);
 	int x2 =
 	  roundingScale(rm->alignEnd - winStart, width, baseWidth) + xOff;
 	int w = x2 - x1;
 	if (w <= 0)
 	  w = 1;