6dcfa9d5af42d4b7968f39d8c1b4a53c62a481f9
braney
  Fri Sep 6 16:03:04 2013 -0700
added pack and squish modes to snake display, big clean up.  #10637
diff --git src/hg/hgTracks/snakeTrack.c src/hg/hgTracks/snakeTrack.c
index 29009da..d40f41d 100644
--- src/hg/hgTracks/snakeTrack.c
+++ src/hg/hgTracks/snakeTrack.c
@@ -1,102 +1,106 @@
+#ifdef USE_HAL
 /* snakeTrack - stuff to load and display snake type tracks in browser.  */
-/*       uses standard chains from the database or HAL files */
-/*       probably the chain and hal support should be in different files
- *       but they share drawing code
- */
 
 #include "common.h"
 #include "hash.h"
 #include "localmem.h"
 #include "linefile.h"
 #include "jksql.h"
 #include "hdb.h"
 #include "hgTracks.h"
 #include "chainBlock.h"
 #include "chainLink.h"
 #include "chainDb.h"
 #include "chainCart.h"
 #include "errCatch.h"
 #include "twoBit.h"
 #include "bigWarn.h"
 #include <pthread.h>
 #include "trackHub.h"
 #include "values.h"
 #include "snakeUi.h"
 
-#ifdef USE_HAL
-
-#ifdef USE_HAL
 #include "halBlockViz.h"
-#endif
 
 struct snakeFeature
     {
     struct snakeFeature *next;
     int start, end;			/* Start/end in browser coordinates. */
     int qStart, qEnd;			/* query start/end */
-    int level;				/* level in packed snake */
+    int level;				/* level in snake */
     int orientation;			/* strand... -1 is '-', 1 is '+' */
     boolean drawn;			/* did we draw this feature? */
     char *sequence;			/* may have sequence, or NULL */
     char *qName;			/* chrom name on other species */
     };
 
-// static machinery to calculate packed snake
-
-struct level
+static int snakeFeatureCmpTStart(const void *va, const void *vb)
+/* sort by start position on the target sequence */
 {
-boolean init;		/* has this level been initialized */
-int orientation;	/* strand.. see above */
-unsigned long edge;		/* the leading edge of this level */
-int adjustLevel;	/* used to compress out the unused levels */
-boolean hasBlock;	/* are there any blocks in this level */
-};
-
-static struct level Levels[1000000]; /* for packing the snake, not re-entrant! */
-static int maxLevel = 0;     	     /* deepest level */	
+const struct snakeFeature *a = *((struct snakeFeature **)va);
+const struct snakeFeature *b = *((struct snakeFeature **)vb);
+int diff = a->start - b->start;
 
-/* blocks that make it through the min size filter */
-static struct snakeFeature *newList = NULL;   
+return diff;
+}
 
 static int snakeFeatureCmpQStart(const void *va, const void *vb)
 /* sort by start position on the query sequence */
 {
 const struct snakeFeature *a = *((struct snakeFeature **)va);
 const struct snakeFeature *b = *((struct snakeFeature **)vb);
 int diff = a->qStart - b->qStart;
 
 if (diff == 0)
     {
     diff = a->start - b->start;
     }
 
 return diff;
 }
 
+
+// static machinery to calculate full and pack snake
+
+struct level
+{
+boolean init;		/* has this level been initialized */
+int orientation;	/* strand.. see above */
+unsigned long edge;	/* the leading edge of this level */
+int adjustLevel;	/* used to compress out the unused levels */
+boolean hasBlock;	/* are there any blocks in this level */
+};
+
+static struct level Levels[10000]; /* for packing the snake, not re-entrant! */
+static int maxLevel = 0;     	     /* deepest level */	
+
+/* blocks that make it through the min size filter */
+static struct snakeFeature *newList = NULL;   
+
 static void clearLevels()
-/* clear out the data structure that we use to pack the snake */
+/* clear out the data structure that we use to calculate full snakes */
 {
 int ii;
 
 for(ii=0; ii < sizeof(Levels) / sizeof(Levels[0]); ii++)
     Levels[ii].init = FALSE;
 maxLevel = 0;
 }
 
-static void calcSnake(struct snakeFeature *list, int level)
-// calculate the packed snake
+static void calcFullSnakeHelper(struct snakeFeature *list, int level)
+// calculate a full snake
 // updates global newList with unsorted blocks that pass the min
 // size filter.
 {
 struct snakeFeature *cb = list;
 struct snakeFeature *proposedList = NULL;
 
 if (level > maxLevel)
     maxLevel = level;
 if (level > ArraySize(Levels))
     errAbort("too many levels");
 
 if (Levels[level].init == FALSE)
     {
     // initialize the level if this is the first time we've seen it
     Levels[level].init = TRUE;
@@ -121,53 +125,53 @@
     if ((Levels[level].orientation != cb->orientation) ||
 	((cb->orientation == 1) && (Levels[level].edge > cb->start)) ||
 	((cb->orientation == -1) && (Levels[level].edge < cb->end)))
 	{
 	// add this to the list of an insert
 	slAddHead(&insertHead, cb);
 	continue;
 	}
 
     // the current block will fit on this level
     // go ahead and deal with the blocks that wouldn't 
     if (insertHead)
 	{
 	// we had an insert, go ahead and calculate where that goes
 	slReverse(&insertHead);
-	calcSnake(insertHead, level + 1);
+	calcFullSnakeHelper(insertHead, level + 1);
 	insertHead = NULL;
 	}
 
     // assign the current block to this level
     cb->level = level;
 
     if (cb->orientation == 1)
 	Levels[level].edge = cb->end;
     else
 	Levels[level].edge = cb->start;
 
     // add this block to the list of proposed blocks for this level
     slAddHead(&proposedList, cb);
     }
 
 // we're at the end of the list.  Deal with any blocks
 // that didn't fit on this level
 if (insertHead)
     {
     slReverse(&insertHead);
     int nextLevel = level + 1;
-    calcSnake(insertHead, nextLevel);
+    calcFullSnakeHelper(insertHead, nextLevel);
     insertHead = NULL;
     }
 
 // do we have any proposed blocks
 if (proposedList == NULL) 
     return;
 
 // we parsed all the blocks in the list to see if they fit in our level
 // now let's see if the list of blocks for this level is big enough
 // to actually add
 
 struct snakeFeature *temp;
 double scale = scaleForWindow(insideWidth, winStart, winEnd);
 int start, end;
 
@@ -187,139 +191,50 @@
     errAbort("size of a list of blocks should not be less than zero");
 
 // check to see if the apparent size is big enough
 if (apparentSize < 1)
     return;
 
 // transfer proposedList to new block list
 for(temp=proposedList; temp; temp = next)
     {
     next = temp->next;
     temp->next = NULL;
     slAddHead(&newList, temp);
     }
 }
 
-struct cartOptions
-    {
-    enum chainColorEnum chainColor; /*  ChromColors, ScoreColors, NoColors */
-    int scoreFilter ; /* filter chains by score if > 0 */
-    };
-
-static int snakeHeight(struct track *tg, enum trackVisibility vis)
-/* calculate height of all the snakes being displayed */
-{
-if (vis == tvDense)
-    return tg->lineHeight;
-
-int height = 0;
-struct slList *item = tg->items;
-
-item = tg->items;
-
-for (item=tg->items;item; item = item->next)
-    {
-    height += tg->itemHeight(tg, item);
-    }
-return height;
-}
-
-// mySQL code to read in chains
-
-static void doQuery(struct sqlConnection *conn, char *fullName, 
-			struct lm *lm, struct hash *hash, 
-			int start, int end,  boolean isSplit, int chainId)
-/* doQuery- check the database for chain elements between
- * 	start and end.  Use the passed hash to resolve chain
- * 	id's and place the elements into the right
- * 	linkedFeatures structure
- */
-{
-struct sqlResult *sr = NULL;
-char **row;
-struct linkedFeatures *lf;
-struct snakeFeature *sf;
-struct dyString *query = newDyString(1024);
-char *force = "";
-
-if (isSplit)
-    force = "force index (bin)";
-
-if (chainId == -1)
-    sqlDyStringPrintf(query, 
-	"select chainId,tStart,tEnd,qStart from %sLink %-s where ",
-	fullName, force);
-else
-    sqlDyStringPrintf(query, 
-	"select chainId, tStart,tEnd,qStart from %sLink where chainId=%d and ",
-	fullName, chainId);
-if (!isSplit)
-    sqlDyStringPrintf(query, "tName='%s' and ", chromName);
-hAddBinToQuery(start, end, query);
-dyStringPrintf(query, "tStart<%u and tEnd>%u", end, start);
-sr = sqlGetResult(conn, query->string);
-
-/* Loop through making up simple features and adding them
- * to the corresponding linkedFeature. */
-while ((row = sqlNextRow(sr)) != NULL)
-    {
-    lf = hashFindVal(hash, row[0]);
-    if (lf != NULL)
-	{
-	struct chain *pChain = lf->extra;
-	lmAllocVar(lm, sf);
-	sf->start = sqlUnsigned(row[1]);
-	sf->end = sqlUnsigned(row[2]);
-	sf->qStart = sqlUnsigned(row[3]); 
-
-	sf->qEnd = sf->qStart + (sf->end - sf->start);
-	if ((pChain) && pChain->qStrand == '-')
-	    {
-	    int temp;
-
-	    temp = sf->qStart;
-	    sf->qStart = pChain->qSize - sf->qEnd;
-	    sf->qEnd = pChain->qSize - temp;
-	    }
-	sf->orientation = lf->orientation;
-	slAddHead(&lf->components, sf);
-	}
-    }
-sqlFreeResult(&sr);
-dyStringFree(&query);
-}
-
 struct snakeInfo
 {
 int maxLevel;
 } snakeInfo;
 
-static void calcPackSnake(struct track *tg, void *item)
+static void calcFullSnake(struct track *tg, void *item)
 {
 struct linkedFeatures  *lf = (struct linkedFeatures *)item;
 if (lf->components == NULL)
     return;
 
 // we use the codons field to keep track of whether we already
 // calculated the height of this snake
 if (lf->codons == NULL)
     {
     clearLevels();
     struct snakeFeature *sf;
 
     // this will destroy lf->components, and add to newList
-    calcSnake((struct snakeFeature *)lf->components, 0);
+    calcFullSnakeHelper((struct snakeFeature *)lf->components, 0);
     lf->components = (struct simpleFeature *)newList;
     newList = NULL;
     slSort(&lf->components, snakeFeatureCmpQStart);
 
     // now we're going to compress the levels that aren't used
     // to do that, we need to see which blocks are on the screen,
     // or connected to something on the screen
     int oldMax = maxLevel;
     clearLevels();
     struct snakeFeature *prev = NULL;
     for(sf=(struct snakeFeature *)lf->components; sf; prev = sf, sf = sf->next)
 	{
 	if (Levels[sf->level].init == FALSE)
 	    {
 	    Levels[sf->level].init = TRUE;
@@ -362,118 +277,275 @@
 	    count++;
 	}
     maxLevel = count - 1;
 
     // remap blocks
     for(sf=(struct snakeFeature *)lf->components; sf; sf = sf->next)
 	sf->level = Levels[sf->level].adjustLevel;
 
     struct snakeInfo *si;
     AllocVar(si);
     si->maxLevel = maxLevel;
     lf->codons = (struct simpleFeature *)si;
     }
 }
 
-static int packSnakeItemHeight(struct track *tg, void *item)
+static void calcPackSnakeHelper(struct snakeFeature *list, int level)
+// calculate a packed snake
+// updates global newList with unsorted blocks that pass the min
+// size filter.
+{
+struct snakeFeature *cb = list;
+struct snakeFeature *proposedList = NULL;
+
+if (level > maxLevel)
+    maxLevel = level;
+if (level > ArraySize(Levels))
+    errAbort("too many levels");
+
+if (Levels[level].init == FALSE)
+    {
+    // initialize the level if this is the first time we've seen it
+    Levels[level].init = TRUE;
+    Levels[level].edge = 0;
+    }
+
+// now we step through the blocks and assign them to levels
+struct snakeFeature *next;
+struct snakeFeature *insertHead = NULL;
+for(; cb; cb = next)
+    {
+    // we're going to add this block to a different list 
+    // so keep track of the next pointer
+    next = cb->next;
+
+    // if this block can't fit on this level add to the insert
+    // list and move on to the next block
+    if ( Levels[level].edge > cb->start)
+	{
+	// add this to the list of an insert
+	slAddHead(&insertHead, cb);
+	continue;
+	}
+
+    // the current block will fit on this level
+    // go ahead and deal with the blocks that wouldn't 
+    if (insertHead)
+	{
+	// we had an insert, go ahead and calculate where that goes
+	slReverse(&insertHead);
+	calcPackSnakeHelper(insertHead, level + 1);
+	insertHead = NULL;
+	}
+
+    // assign the current block to this level
+    cb->level = level;
+
+    Levels[level].edge = cb->end;
+
+    // add this block to the list of proposed blocks for this level
+    slAddHead(&proposedList, cb);
+    }
+
+// we're at the end of the list.  Deal with any blocks
+// that didn't fit on this level
+if (insertHead)
+    {
+    slReverse(&insertHead);
+    calcPackSnakeHelper(insertHead,  level + 1);
+    insertHead = NULL;
+    }
+
+// do we have any proposed blocks
+if (proposedList == NULL) 
+    return;
+
+// we parsed all the blocks in the list to see if they fit in our level
+// now let's see if the list of blocks for this level is big enough
+// to actually add
+
+struct snakeFeature *temp;
+double scale = scaleForWindow(insideWidth, winStart, winEnd);
+int start, end;
+
+// order the blocks so lowest start position is first
+slReverse(&proposedList);
+
+start=proposedList->start;
+for(temp=proposedList; temp->next; temp = temp->next)
+    ;
+end=temp->end;
+
+// calculate how big the string of blocks is in screen coordinates
+double apparentSize = scale * (end - start);
+
+if (apparentSize < 0)
+    errAbort("size of a list of blocks should not be less than zero");
+
+// check to see if the apparent size is big enough
+if (apparentSize < 1)
+    return;
+
+// transfer proposedList to new block list
+for(temp=proposedList; temp; temp = next)
+    {
+    next = temp->next;
+    temp->next = NULL;
+    slAddHead(&newList, temp);
+    }
+}
+
+static void calcPackSnake(struct track *tg, void *item)
+{
+struct linkedFeatures  *lf = (struct linkedFeatures *)item;
+if (lf->components == NULL)
+    return;
+
+// we use the codons field to keep track of whether we already
+// calculated the height of this snake
+if (lf->codons == NULL)
+    {
+    clearLevels();
+
+    // this will destroy lf->components, and add to newList
+    calcPackSnakeHelper((struct snakeFeature *)lf->components, 0);
+    lf->components = (struct simpleFeature *)newList;
+    newList = NULL;
+    
+    //slSort(&lf->components, snakeFeatureCmpQStart);
+
+    struct snakeInfo *si;
+    AllocVar(si);
+    si->maxLevel = maxLevel;
+    lf->codons = (struct simpleFeature *)si;
+    }
+}
+
+static int snakeItemHeight(struct track *tg, void *item)
 // return height of a single packed snake 
 {
-if (item == NULL)
+if ((item == NULL) || (tg->visibility == tvSquish) || (tg->visibility == tvDense)) 
     return 0;
+
 struct linkedFeatures  *lf = (struct linkedFeatures *)item;
 if (lf->components == NULL)
     return 0;
+
+if (tg->visibility == tvFull) 
+    calcFullSnake(tg, item);
+else if (tg->visibility == tvPack) 
     calcPackSnake(tg, item);
+
 struct snakeInfo *si = (struct snakeInfo *)lf->codons;
 int lineHeight = tg->lineHeight ;
 return (si->maxLevel + 1) * (2 * lineHeight);
 }
 
-static int snakeItemHeight(struct track *tg, void *item)
-{
-return packSnakeItemHeight(tg, item);
-}
-
 static int linkedFeaturesCmpScore(const void *va, const void *vb)
 /* Help sort linkedFeatures by score */
 {
 const struct linkedFeatures *a = *((struct linkedFeatures **)va);
 const struct linkedFeatures *b = *((struct linkedFeatures **)vb);
 if (a->score > b->score)
     return -1;
 else if (a->score < b->score)
     return 1;
 return 0;
 }
 
+static int snakeHeight(struct track *tg, enum trackVisibility vis)
+/* calculate height of all the snakes being displayed */
+{
+if (vis == tvDense)
+    return tg->lineHeight;
+
+if (vis == tvSquish)
+    return tg->lineHeight/2;
+
+int height = 0;
+struct slList *item = tg->items;
+
+item = tg->items;
+
+for (item=tg->items;item; item = item->next)
+    {
+    height += tg->itemHeight(tg, item);
+    }
+return height;
+}
+
 static void snakeDraw(struct track *tg, int seqStart, int seqEnd,
         struct hvGfx *hvg, int xOff, int yOff, int width, 
         MgFont *font, Color color, enum trackVisibility vis)
 /* Draw linked features items. */
 {
 struct slList *item;
 int y;
 struct linkedFeatures  *lf;
 double scale = scaleForWindow(width, seqStart, seqEnd);
 int height = snakeHeight(tg, vis);
 
 hvGfxSetClip(hvg, xOff, yOff, width, height);
 
+if ((tg->visibility == tvFull) || (tg->visibility == tvPack))
+    {
     // score snakes by how many bases they cover
     for (item = tg->items; item != NULL; item = item->next)
 	{
 	lf = (struct linkedFeatures *)item;
 	struct snakeFeature  *sf;
 
 	lf->score = 0;
 	for (sf =  (struct snakeFeature *)lf->components; sf != NULL;  sf = sf->next)
 	    {
 	    lf->score += sf->end - sf->start;
 	    }
 	}
 
     slSort(&tg->items, linkedFeaturesCmpScore);
+    }
 
 y = yOff;
 for (item = tg->items; item != NULL; item = item->next)
     {
     if(tg->itemColor != NULL) 
 	color = tg->itemColor(tg, item, hvg);
     tg->drawItemAt(tg, item, hvg, xOff, y, scale, font, color, vis);
     if (vis == tvFull)
 	y += tg->itemHeight(tg, item);
     } 
 }
 
-static void packSnakeDrawAt(struct track *tg, void *item,
+static void snakeDrawAt(struct track *tg, void *item,
 	struct hvGfx *hvg, int xOff, int y, double scale, 
 	MgFont *font, Color color, enum trackVisibility vis)
 /* Draw a single simple bed item at position. */
 {
 unsigned showSnpWidth = cartOrTdbInt(cart, tg->tdb, 
     SNAKE_SHOW_SNP_WIDTH, SNAKE_DEFAULT_SHOW_SNP_WIDTH);
 struct linkedFeatures  *lf = (struct linkedFeatures *)item;
+
+
+if (tg->visibility == tvFull) 
+    calcFullSnake(tg, item);
+else if (tg->visibility == tvPack)
     calcPackSnake(tg, item);
 
 if (lf->components == NULL)
     return;
 
-#ifdef USE_HAL
 boolean isHalSnake = lf->isHalSnake;
-#else
-boolean isHalSnake = FALSE;
-#endif
 
 struct snakeFeature  *sf = (struct snakeFeature *)lf->components, *prevSf = NULL;
 int s = tg->itemStart(tg, item);
 int sClp = (s < winStart) ? winStart : s;
 int x1 = round((sClp - winStart)*scale) + xOff;
 int textX = x1;
 int yOff = y;
 boolean withLabels = (withLeftLabels && (vis == tvFull) && !tg->drawName);
 unsigned   labelColor = MG_BLACK;
 
 // draw the labels
 if (withLabels)
     {
     char *name = tg->itemName(tg, item);
     int nameWidth = mgFontStringWidth(font, name);
@@ -508,50 +580,48 @@
         hvGfxUnclip(hvgSide);
         hvGfxSetClip(hvgSide, insideX, yOff, insideWidth, tg->height);
         }
     else
         {
         if(drawNameInverted)
             {
             hvGfxBox(hvg, textX - 1, y, nameWidth+1, tg->heightPer-1, color);
             hvGfxTextRight(hvg, textX, y, nameWidth, tg->heightPer, MG_WHITE, font, name);
             }
         else
             hvGfxTextRight(hvg, textX, y, nameWidth, tg->heightPer, labelColor, font, name);
         }
     }
 
-#ifdef USE_HAL
 // let's draw some blue bars for the duplications
 struct hal_target_dupe_list_t* dupeList = lf->dupeList;
 
 for(; dupeList ; dupeList = dupeList->next)
     {
     struct hal_target_range_t *range = dupeList->tRange;
     for(; range; range = range->next)
 	{
 	int s = range->tStart;
 	int e = range->tStart + range->size;
 	int sClp = (s < winStart) ? winStart : s;
 	int eClp = (e > winEnd) ? winEnd : e;
 	int x1 = round((sClp - winStart)*scale) + xOff;
 	int x2 = round((eClp - winStart)*scale) + xOff;
 	hvGfxLine(hvg, x1, y , x2, y , MG_BLUE);
 	}
     }
 y+=2;
-#endif
 
 // now we're going to draw the boxes
 
 s = sf->start;
 int lastE = -1;
 int lastS = -1;
 int offY = y;
 int lineHeight = tg->lineHeight ;
 int tStart, tEnd, qStart;
 int  qs, qe;
 int heightPer = tg->heightPer;
 int lastX = -1,lastY = y;
 int lastQEnd = 0;
 int lastLevel = -1;
 int e;
@@ -597,40 +667,40 @@
 	color =  darkBlueColor;
 
     int w = ex - sx;
     if (w == 0) 
 	w = 1;
     assert(w > 0);
     char buffer[1024];
     safef(buffer, sizeof buffer, "%d %d",sf->qStart,sf->qEnd);
     if (sx < insideX)
 	{
 	int olap = insideX - sx;
 	sx = insideX;
 	w -= olap;
 	}
     char qAddress[4096];
-    if (vis == tvFull)
+    if ((vis == tvFull) || (vis == tvPack) )
 	{
-	safef(qAddress, sizeof qAddress, "qName=%s&qs=%d&qe=%d&qWidth=%d",tg->itemName(tg, item),  qs, qe,  winEnd - winStart);
+	safef(qAddress, sizeof qAddress, "qName=%s&qs=%d&qe=%d&qWidth=%d",sf->qName,  qs, qe,  winEnd - winStart);
 	mapBoxHgcOrHgGene(hvg, s, e, sx+1, y, w-2, heightPer, tg->track,
 		    buffer, buffer, NULL, TRUE, qAddress);
 	}
     hvGfxBox(hvg, sx, y, w, heightPer, color);
 
     // now draw the mismatches if we're at high enough resolution 
-    if ((winBaseCount < showSnpWidth) && (vis == tvFull))
+    if ((winBaseCount < showSnpWidth) && ((vis == tvFull) || (vis == tvPack)))
     {
 	char *twoBitString = trackDbSetting(tg->tdb, "twoBit");
 	static struct twoBitFile *tbf = NULL;
 	static char *lastTwoBitString = NULL;
 	static struct dnaSeq *seq = NULL;
 	static char *lastQName = NULL;
 
 	// sequence for chain snakes is in 2bit files which we cache
 	if (!isHalSnake)
 	    {
 	    if (twoBitString == NULL)
 		twoBitString = "/gbdb/hg19/hg19.2bit";
 
 	    if ((lastTwoBitString == NULL) ||
 		differentString(lastTwoBitString, twoBitString))
@@ -689,31 +759,31 @@
 	    int myw = myex - mysx;
 	    spreadAlignString(hvg, mysx, y, myw, heightPer, MG_WHITE, font, ourDna,
 		extraSeq->dna, seqLen, TRUE, FALSE);
 	    }
 
     }
     sf->drawn = TRUE;
     tEnd = e;
     tStart = s;
     qStart = sf->qStart;
     lastY = y;
     lastLevel = sf->level;
     //lastX = x;
     }
 
-if (vis == tvDense)
+if (vis != tvFull)
     return;
 
 // now we're going to draw the lines between the blocks
 
 lastX = -1,lastY = y;
 lastQEnd = 0;
 lastLevel = 0;
 qe = lastQEnd = 0;
 prevSf = NULL;
 for (sf =  (struct snakeFeature *)lf->components; sf != NULL; lastQEnd = qe, prevSf = sf, sf = sf->next)
     {
     int y1, y2;
     int sx, ex;
     qs = sf->qStart;
     qe = sf->qEnd;
@@ -791,76 +861,307 @@
 			hvGfxLine(hvg, lastX, y1, sx, y2, color);
 			mapBoxHgcOrHgGene(hvg, s, e, lastX, y1, sx-lastX, 1, tg->track,
 				"", buffer, NULL, TRUE, NULL);
 			}
 		    }
 		}
 	    else if (lastLevel > sf->level)
 		{
 		hvGfxLine(hvg, lastX, y1, sx, y2, color);
 		hvGfxLine(hvg, sx, y2, sx, y2 - lineHeight - lineHeight/3, color);
 		char buffer[1024];
 		safef(buffer, sizeof buffer, "%d-%d %dbp gap",prevSf->qStart,prevSf->qEnd, qs - lastQEnd);
 		mapBoxHgcOrHgGene(hvg, s, e, sx, y2 - lineHeight - lineHeight/3, 2, lineHeight + lineHeight/3, tg->track,
 	                    "", buffer, NULL, TRUE, NULL);
 
-		}
-	    else
+		}
+	    else
+		{
+		char buffer[1024];
+		safef(buffer, sizeof buffer, "%d-%d %dbp gap",prevSf->qStart,prevSf->qEnd, qs - lastQEnd);
+		if (sf->orientation == -1)
+		    {
+		    hvGfxLine(hvg, lastX-1, y1, ex, y2, color);
+		    hvGfxLine(hvg, ex, y2, ex, y2 + lineHeight , color);
+		    mapBoxHgcOrHgGene(hvg, s, e, ex-1, y2, 2, lineHeight , tg->track,
+				"", buffer, NULL, TRUE, NULL);
+		    }
+		else
+		    {
+		    hvGfxLine(hvg, lastX-1, y1, sx, y2, color);
+		    hvGfxLine(hvg, sx, y2, sx, y2 + lineHeight , color);
+		    mapBoxHgcOrHgGene(hvg, s, e, sx-1, y2, 2, lineHeight , tg->track,
+				"", buffer, NULL, TRUE, NULL);
+
+		    }
+		}
+	    }
+	}
+    tEnd = e;
+    tStart = s;
+    qStart = sf->qStart;
+    if (sf->orientation == -1)
+	lastX = sx;
+    else
+	lastX = ex;
+    lastS = s;
+    lastE = e;
+    lastLevel = sf->level;
+    lastQEnd = qe;
+    }
+}
+
+void halSnakeLoadItems(struct track *tg)
+// load up a snake from a HAL file.   This code is called in threads
+// so *no* use of globals please. All but full snakes are read into a single
+// linked feature.
+{
+unsigned showSnpWidth = cartOrTdbInt(cart, tg->tdb, 
+    SNAKE_SHOW_SNP_WIDTH, SNAKE_DEFAULT_SHOW_SNP_WIDTH);
+
+// if we have a network error we want to put out a message about it
+struct errCatch *errCatch = errCatchNew();
+if (errCatchStart(errCatch))
+    {
+    char *fileName = trackDbSetting(tg->tdb, "bigDataUrl");
+    char *otherSpecies = trackDbSetting(tg->tdb, "otherSpecies");
+    int handle = halOpenLOD(fileName);
+    int needSeq = (winBaseCount < showSnpWidth) ? 1 : 0;
+    struct hal_block_results_t *head = halGetBlocksInTargetRange(handle, otherSpecies, trackHubSkipHubName(database), chromName, winStart, winEnd, needSeq, 1);
+
+    // did we get any blocks from HAL
+    if (head == NULL)
+	{
+	errCatchEnd(errCatch);
+	return;
+	}
+    struct hal_block_t* cur = head->mappedBlocks;
+    struct linkedFeatures *lf;
+    struct hash *qChromHash = newHash(5);
+    struct linkedFeatures *lfList = NULL;
+    char buffer[4096];
+
+#ifdef NOTNOW
+    struct hal_target_dupe_list_t* targetDupeBlocks = head->targetDupeBlocks;
+
+    for(;targetDupeBlocks; targetDupeBlocks = targetDupeBlocks->next)
+	{
+	printf("<br>id: %d qChrom %s\n", targetDupeBlocks->id, targetDupeBlocks->qChrom);
+	struct hal_target_range_t *range = targetDupeBlocks->tRange;
+	for(; range; range = range->next)
+	    {
+	    printf("<br>   %ld : %ld\n", range->tStart, range->size);
+	    }
+	}
+#endif
+
+    while (cur)
+    {
+	struct hashEl* hel;
+
+	//safef(buffer, sizeof buffer, "%s.%c", cur->qChrom,cur->strand);
+	if (tg->visibility == tvFull)
+	    safef(buffer, sizeof buffer, "%s", cur->qChrom);
+	else
+	    {
+	    // make sure the block is on the screen 
+	    if (!positiveRangeIntersection(winStart, winEnd, cur->tStart,  cur->tStart + cur->size))
+		{
+		cur = cur->next;
+		continue;
+		}
+	    safef(buffer, sizeof buffer, "allInOne");
+	    }
+
+	if ((hel = hashLookup(qChromHash, buffer)) == NULL)
+	    {
+	    AllocVar(lf);
+	    lf->isHalSnake = TRUE;
+	    slAddHead(&lfList, lf);
+	    lf->start = 0;
+	    lf->end = 1000000000;
+	    lf->grayIx = maxShade;
+	    lf->name = cloneString(buffer);
+	    lf->extra = cloneString(buffer);
+	    lf->orientation = (cur->strand == '+') ? 1 : -1;
+	    hashAdd(qChromHash, lf->name, lf);
+
+	    // now figure out where the blue bars go
+	    struct hal_target_dupe_list_t* targetDupeBlocks = head->targetDupeBlocks;
+
+	    if ((tg->visibility == tvPack) || (tg->visibility == tvFull))
+		for(;targetDupeBlocks; targetDupeBlocks = targetDupeBlocks->next)
+		    {
+		    if ((tg->visibility == tvPack) ||
+			((tg->visibility == tvFull) &&
+			 (sameString(targetDupeBlocks->qChrom, cur->qChrom))))
+			{
+			struct hal_target_dupe_list_t* dupeList;
+			AllocVar(dupeList);
+			*dupeList = *targetDupeBlocks;
+			slAddHead(&lf->dupeList, dupeList);
+			// TODO: should clone the target_range structures
+			// rather than copying them
+			}
+		    }
+	    }
+	else
+	    {
+	    lf = hel->val;
+	    }
+
+	struct snakeFeature  *sf;
+	AllocVar(sf);
+	slAddHead(&lf->components, sf);
+	
+	sf->start = cur->tStart;
+	sf->end = cur->tStart + cur->size;
+	sf->qStart = cur->qStart;
+	sf->qEnd = cur->qStart + cur->size;
+	sf->orientation = (cur->strand == '+') ? 1 : -1;
+	sf->sequence = cloneString(cur->sequence);
+	sf->qName = cur->qChrom;
+
+	cur = cur->next;
+    }
+    if (tg->visibility == tvFull)
+	{
+	for(lf=lfList; lf ; lf = lf->next)
+	    {
+	    slSort(&lf->components, snakeFeatureCmpQStart);
+	    }
+	}
+    else if (tg->visibility == tvPack)
+	{
+	assert(lf->next == NULL);
+	slSort(&lf->components, snakeFeatureCmpTStart);
+	}
+    
+    //halFreeBlocks(head);
+    //halClose(handle, myThread);
+
+    tg->items = lfList;
+    }
+errCatchEnd(errCatch);
+if (errCatch->gotError)
+    {
+    tg->networkErrMsg = cloneString(errCatch->message->string);
+    tg->drawItems = bigDrawWarning;
+    tg->totalHeight = bigWarnTotalHeight;
+    }
+errCatchFree(&errCatch);
+}
+
+void halSnakeDrawLeftLabels(struct track *tg, int seqStart, int seqEnd,
+        struct hvGfx *hvg, int xOff, int yOff, int width, int height,
+        boolean withCenterLabels, MgFont *font,
+        Color color, enum trackVisibility vis)
+{
+}
+
+void halSnakeMethods(struct track *tg, struct trackDb *tdb, 
+	int wordCount, char *words[])
+{
+linkedFeaturesMethods(tg);
+tg->canPack = tdb->canPack = TRUE;
+tg->loadItems = halSnakeLoadItems;
+tg->drawItems = snakeDraw;
+tg->mapItemName = lfMapNameFromExtra;
+tg->subType = lfSubChain;
+//tg->extraUiData = (void *) chainCart;
+tg->totalHeight = snakeHeight; 
+tg->drawLeftLabels = halSnakeDrawLeftLabels;
+
+tg->drawItemAt = snakeDrawAt;
+tg->itemHeight = snakeItemHeight;
+}
+#endif  // USE_HAL
+
+#ifdef NOTNOW
+
+// from here down are routines to support the visualization of chains as snakes
+// this code is currently BROKEN, and may be removed completely in the future
+
+struct cartOptions
+    {
+    enum chainColorEnum chainColor; /*  ChromColors, ScoreColors, NoColors */
+    int scoreFilter ; /* filter chains by score if > 0 */
+    };
+
+// mySQL code to read in chains
+
+static void doQuery(struct sqlConnection *conn, char *fullName, 
+			struct lm *lm, struct hash *hash, 
+			int start, int end,  boolean isSplit, int chainId)
+/* doQuery- check the database for chain elements between
+ * 	start and end.  Use the passed hash to resolve chain
+ * 	id's and place the elements into the right
+ * 	linkedFeatures structure
+ */
+{
+struct sqlResult *sr = NULL;
+char **row;
+struct linkedFeatures *lf;
+struct snakeFeature *sf;
+struct dyString *query = newDyString(1024);
+char *force = "";
+
+if (isSplit)
+    force = "force index (bin)";
+
+if (chainId == -1)
+    sqlDyStringPrintf(query, 
+	"select chainId,tStart,tEnd,qStart from %sLink %-s where ",
+	fullName, force);
+else
+    sqlDyStringPrintf(query, 
+	"select chainId, tStart,tEnd,qStart from %sLink where chainId=%d and ",
+	fullName, chainId);
+if (!isSplit)
+    sqlDyStringPrintf(query, "tName='%s' and ", chromName);
+hAddBinToQuery(start, end, query);
+dyStringPrintf(query, "tStart<%u and tEnd>%u", end, start);
+sr = sqlGetResult(conn, query->string);
+
+/* Loop through making up simple features and adding them
+ * to the corresponding linkedFeature. */
+while ((row = sqlNextRow(sr)) != NULL)
     {
-		char buffer[1024];
-		safef(buffer, sizeof buffer, "%d-%d %dbp gap",prevSf->qStart,prevSf->qEnd, qs - lastQEnd);
-		if (sf->orientation == -1)
+    lf = hashFindVal(hash, row[0]);
+    if (lf != NULL)
 	{
-		    hvGfxLine(hvg, lastX-1, y1, ex, y2, color);
-		    hvGfxLine(hvg, ex, y2, ex, y2 + lineHeight , color);
-		    mapBoxHgcOrHgGene(hvg, s, e, ex-1, y2, 2, lineHeight , tg->track,
-				"", buffer, NULL, TRUE, NULL);
-		    }
-		else
+	struct chain *pChain = lf->extra;
+	lmAllocVar(lm, sf);
+	sf->start = sqlUnsigned(row[1]);
+	sf->end = sqlUnsigned(row[2]);
+	sf->qStart = sqlUnsigned(row[3]); 
+
+	sf->qEnd = sf->qStart + (sf->end - sf->start);
+	if ((pChain) && pChain->qStrand == '-')
 	    {
-		    hvGfxLine(hvg, lastX-1, y1, sx, y2, color);
-		    hvGfxLine(hvg, sx, y2, sx, y2 + lineHeight , color);
-		    mapBoxHgcOrHgGene(hvg, s, e, sx-1, y2, 2, lineHeight , tg->track,
-				"", buffer, NULL, TRUE, NULL);
+	    int temp;
 
+	    temp = sf->qStart;
+	    sf->qStart = pChain->qSize - sf->qEnd;
+	    sf->qEnd = pChain->qSize - temp;
 	    }
+	sf->orientation = lf->orientation;
+	slAddHead(&lf->components, sf);
 	}
     }
-	}
-    tEnd = e;
-    tStart = s;
-    qStart = sf->qStart;
-    if (sf->orientation == -1)
-	lastX = sx;
-    else
-	lastX = ex;
-    lastS = s;
-    lastE = e;
-    lastLevel = sf->level;
-    lastQEnd = qe;
-    }
-}
-
-
-static void snakeDrawAt(struct track *tg, void *item,
-	struct hvGfx *hvg, int xOff, int y, double scale, 
-	MgFont *font, Color color, enum trackVisibility vis)
-/* Draw a single simple bed item at position. */
-{
-if ((tg->visibility == tvFull) || (tg->visibility == tvDense))
-    packSnakeDrawAt(tg, item, hvg, xOff, y, scale, 
-	font, color, vis);
+sqlFreeResult(&sr);
+dyStringFree(&query);
 }
 
 static void fixItems(struct linkedFeatures *lf)
 // put all chain blocks from a single query chromosome into one
 // linkedFeatures structure
 {
 struct linkedFeatures *firstLf, *next;
 struct snakeFeature  *sf,  *nextSf;
 
 firstLf = lf;
 for (;lf; lf = next)
     {
     next = lf->next;
     if (!sameString(firstLf->name, lf->name) && (lf->components != NULL))
 	{
@@ -944,144 +1245,30 @@
 	 * one or two lines to the edge of the screen.
 	 */
 #define STARTSLOP	0
 #define MULTIPLIER	10
 #define MAXLOOK		100000
 	extra = (STARTSLOP < maxOverLeft) ? STARTSLOP : maxOverLeft;
 	start = seqStart - extra;
 	extra = (STARTSLOP < maxOverRight) ? STARTSLOP : maxOverRight;
 	end = seqEnd + extra;
 	doQuery(conn, fullName, lm,  hash, start, end,  isSplit, -1);
 	}
     }
 hFreeConn(&conn);
 }
 
-#ifdef USE_HAL
-void halSnakeLoadItems(struct track *tg)
-{
-unsigned showSnpWidth = cartOrTdbInt(cart, tg->tdb, 
-    SNAKE_SHOW_SNP_WIDTH, SNAKE_DEFAULT_SHOW_SNP_WIDTH);
-struct errCatch *errCatch = errCatchNew();
-if (errCatchStart(errCatch))
-    {
-    char *fileName = trackDbSetting(tg->tdb, "bigDataUrl");
-    char *otherSpecies = trackDbSetting(tg->tdb, "otherSpecies");
-    int handle = halOpenLOD(fileName);
-    int needSeq = (winBaseCount < showSnpWidth) ? 1 : 0;
-    struct hal_block_results_t *head = halGetBlocksInTargetRange(handle, otherSpecies, trackHubSkipHubName(database), chromName, winStart, winEnd, needSeq, 1);
-
-    // did we get any blocks from HAL
-    if (head == NULL)
-	{
-	errCatchEnd(errCatch);
-	return;
-	}
-    struct hal_block_t* cur = head->mappedBlocks;
-    struct linkedFeatures *lf;
-    struct hash *qChromHash = newHash(5);
-    struct linkedFeatures *lfList = NULL;
-    char buffer[4096];
-
-#ifdef NOTNOW
-    struct hal_target_dupe_list_t* targetDupeBlocks = head->targetDupeBlocks;
-
-    for(;targetDupeBlocks; targetDupeBlocks = targetDupeBlocks->next)
-	{
-	printf("<br>id: %d qChrom %s\n", targetDupeBlocks->id, targetDupeBlocks->qChrom);
-	struct hal_target_range_t *range = targetDupeBlocks->tRange;
-	for(; range; range = range->next)
-	    {
-	    printf("<br>   %ld : %ld\n", range->tStart, range->size);
-	    }
-	}
-#endif
-
-    while (cur)
-    {
-	struct hashEl* hel;
-
-	//safef(buffer, sizeof buffer, "%s.%c", cur->qChrom,cur->strand);
-	safef(buffer, sizeof buffer, "%s", cur->qChrom);
-	if ((hel = hashLookup(qChromHash, buffer)) == NULL)
-	    {
-	    AllocVar(lf);
-	    lf->isHalSnake = TRUE;
-	    slAddHead(&lfList, lf);
-	    lf->start = 0;
-	    lf->end = 1000000000;
-	    lf->grayIx = maxShade;
-	    lf->name = cloneString(buffer);
-	    lf->extra = cloneString(buffer);
-	    lf->orientation = (cur->strand == '+') ? 1 : -1;
-	    hashAdd(qChromHash, lf->name, lf);
-
-	    // now figure out where the blue bars go
-	    struct hal_target_dupe_list_t* targetDupeBlocks = head->targetDupeBlocks;
-
-	    for(;targetDupeBlocks; targetDupeBlocks = targetDupeBlocks->next)
-		{
-		if (sameString(targetDupeBlocks->qChrom, cur->qChrom))
-		    {
-		    struct hal_target_dupe_list_t* dupeList;
-		    AllocVar(dupeList);
-		    *dupeList = *targetDupeBlocks;
-		    slAddHead(&lf->dupeList, dupeList);
-		    // TODO: should clone the target_range structures
-		    }
-		}
-	    }
-	else
-	    {
-	    lf = hel->val;
-	    }
-
-	struct snakeFeature  *sf;
-	AllocVar(sf);
-	slAddHead(&lf->components, sf);
-	
-	sf->start = cur->tStart;
-	sf->end = cur->tStart + cur->size;
-	sf->qStart = cur->qStart;
-	sf->qEnd = cur->qStart + cur->size;
-	sf->orientation = (cur->strand == '+') ? 1 : -1;
-	sf->sequence = cloneString(cur->sequence);
-
-    //  printBlock(stdout, cur);
-      cur = cur->next;
-    }
-    for(lf=lfList; lf ; lf = lf->next)
-	{
-	slSort(&lf->components, snakeFeatureCmpQStart);
-	}
-    //halFreeBlocks(head);
-    //halClose(handle, myThread);
-
-    tg->items = lfList;
-    }
-errCatchEnd(errCatch);
-if (errCatch->gotError)
-    {
-    tg->networkErrMsg = cloneString(errCatch->message->string);
-    tg->drawItems = bigDrawWarning;
-    tg->totalHeight = bigWarnTotalHeight;
-    }
-errCatchFree(&errCatch);
-}
-#endif // USE_HAL
-
-
 void snakeLoadItems(struct track *tg)
 // Load chains from a mySQL database
 {
 char *track = tg->table;
 struct chain chain;
 int rowOffset;
 char **row;
 struct sqlConnection *conn = hAllocConn(database);
 struct sqlResult *sr = NULL;
 struct linkedFeatures *list = NULL, *lf;
 int qs;
 char optionChr[128]; /* Option -  chromosome filter */
 char *optionChrStr;
 char extraWhere[128] ;
 struct cartOptions *chainCart;
@@ -1172,87 +1359,30 @@
 else
     slReverse(&list);
 tg->items = list;
 
 
 /* Clean up. */
 sqlFreeResult(&sr);
 hFreeConn(&conn);
 
 /* now load the items */
 loadLinks(tg, ourStart, ourEnd, tg->visibility);
 lf=tg->items;
 fixItems(lf);
 }	/*	chainLoadItems()	*/
 
-#ifdef NOTNOW
-static Color chainScoreColor(struct track *tg, void *item, struct hvGfx *hvg)
-{
-struct linkedFeatures *lf = (struct linkedFeatures *)item;
-
-return(tg->colorShades[lf->grayIx]);
-}
-
-static Color chainNoColor(struct track *tg, void *item, struct hvGfx *hvg)
-{
-return(tg->ixColor);
-}
-
-static void setNoColor(struct track *tg)
-{
-tg->itemColor = chainNoColor;
-tg->color.r = 0;
-tg->color.g = 0;
-tg->color.b = 0;
-tg->altColor.r = 127;
-tg->altColor.g = 127;
-tg->altColor.b = 127;
-tg->ixColor = MG_BLACK;
-tg->ixAltColor = MG_GRAY;
-}
-#endif
-
-#ifdef USE_HAL
-void halSnakeDrawLeftLabels(struct track *tg, int seqStart, int seqEnd,
-        struct hvGfx *hvg, int xOff, int yOff, int width, int height,
-        boolean withCenterLabels, MgFont *font,
-        Color color, enum trackVisibility vis)
-{
-}
-
-
-void halSnakeMethods(struct track *tg, struct trackDb *tdb, 
-	int wordCount, char *words[])
-{
-//errAbort("halSnakeMethds\n");
-linkedFeaturesMethods(tg);
-tg->canPack = FALSE;
-tdb->canPack = FALSE;
-tg->loadItems = halSnakeLoadItems;
-tg->drawItems = snakeDraw;
-tg->mapItemName = lfMapNameFromExtra;
-tg->subType = lfSubChain;
-//tg->extraUiData = (void *) chainCart;
-tg->totalHeight = snakeHeight; 
-tg->drawLeftLabels = halSnakeDrawLeftLabels;
-
-tg->drawItemAt = snakeDrawAt;
-tg->itemHeight = snakeItemHeight;
-}
-#endif
-
-#ifdef NOTNOW
 void snakeMethods(struct track *tg, struct trackDb *tdb, 
 	int wordCount, char *words[])
 /* Fill in custom parts of alignment chains. */
 {
 
 struct cartOptions *chainCart;
 
 AllocVar(chainCart);
 
 boolean normScoreAvailable = chainDbNormScoreAvailable(tdb);
 
 /*	what does the cart say about coloring option	*/
 chainCart->chainColor = chainFetchColorOption(cart, tdb, FALSE);
 
 chainCart->scoreFilter = cartUsualIntClosestToHome(cart, tdb,
@@ -1294,17 +1424,41 @@
     else
 	chainCart->chainColor = chainColorChromColors;
     }
 
 tg->canPack = FALSE;
 tg->loadItems = snakeLoadItems;
 tg->drawItems = snakeDraw;
 tg->mapItemName = lfMapNameFromExtra;
 tg->subType = lfSubChain;
 tg->extraUiData = (void *) chainCart;
 tg->totalHeight = snakeHeight; 
 
 tg->drawItemAt = snakeDrawAt;
 tg->itemHeight = snakeItemHeight;
 }
-#endif
+
+static Color chainScoreColor(struct track *tg, void *item, struct hvGfx *hvg)
+{
+struct linkedFeatures *lf = (struct linkedFeatures *)item;
+
+return(tg->colorShades[lf->grayIx]);
+}
+
+static Color chainNoColor(struct track *tg, void *item, struct hvGfx *hvg)
+{
+return(tg->ixColor);
+}
+
+static void setNoColor(struct track *tg)
+{
+tg->itemColor = chainNoColor;
+tg->color.r = 0;
+tg->color.g = 0;
+tg->color.b = 0;
+tg->altColor.r = 127;
+tg->altColor.g = 127;
+tg->altColor.b = 127;
+tg->ixColor = MG_BLACK;
+tg->ixAltColor = MG_GRAY;
+}
 #endif