77dc06c4bdc5e10f5d2705a51300ec028a7d785f
tdreszer
  Fri Oct 1 10:51:48 2010 -0700
FindTracks now finds superTracks (Advanced only) and hgTrackUi now does superTrack reshaping when children have vis changed
diff --git src/hg/hgTracks/wigMafTrack.c.old src/hg/hgTracks/wigMafTrack.c.old
new file mode 100644
index 0000000..890239d
--- /dev/null
+++ src/hg/hgTracks/wigMafTrack.c.old
@@ -0,0 +1,2530 @@
+/* wigMafTrack - display multiple alignment files with score wiggle
+ * and base-level alignment, or else density plot of pairwise alignments
+ * (zoomed out) */
+
+#include "common.h"
+#include "hash.h"
+#include "linefile.h"
+#include "jksql.h"
+#include "hdb.h"
+#include "hgTracks.h"
+#include "maf.h"
+#include "scoredRef.h"
+#include "wiggle.h"
+#include "hCommon.h"
+#include "hgMaf.h"
+#include "mafTrack.h"
+#include "customTrack.h"
+#include "mafSummary.h"
+#include "mafFrames.h"
+#include "phyloTree.h"
+
+static char const rcsid[] = "$Id: wigMafTrack.c,v 1.146 2010/05/11 01:43:28 kent Exp $";
+
+#define GAP_ITEM_LABEL  "Gaps"
+#define MAX_SP_SIZE 2000
+
+struct wigMafItem
+/* A maf track item --
+ * a line of bases (base level) or pairwise density gradient (zoomed out). */
+    {
+    struct wigMafItem *next;
+    char *name;		/* Common name */
+    char *db;		/* Database */
+    int group;          /* number of species group/clade */
+    int ix;		/* Position in list. */
+    int height;		/* Pixel height of item. */
+    int inserts[128];
+    int insertsSize;
+    int seqEnds[128];
+    int seqEndsSize;
+    int brackStarts[128];
+    int brackStartsSize;
+    int brackEnds[128];
+    int brackEndsSize;
+    };
+
+static void wigMafItemFree(struct wigMafItem **pEl)
+/* Free up a wigMafItem. */
+{
+struct wigMafItem *el = *pEl;
+if (el != NULL)
+    {
+    freeMem(el->name);
+    freeMem(el->db);
+    freez(pEl);
+    }
+}
+
+void wigMafItemFreeList(struct wigMafItem **pList)
+/* Free a list of dynamically allocated wigMafItem's */
+{
+struct wigMafItem *el, *next;
+
+for (el = *pList; el != NULL; el = next)
+    {
+    next = el->next;
+    wigMafItemFree(&el);
+    }
+*pList = NULL;
+}
+
+Color wigMafItemLabelColor(struct track *tg, void *item, struct hvGfx *hvg)
+/* Return color to draw a maf item based on the species group it is in */
+{
+struct wigMafItem *mi = (struct wigMafItem *)item;
+if (sameString(mi->name, GAP_ITEM_LABEL))
+    return getOrangeColor();
+return (((struct wigMafItem *)item)->group % 2 ?
+                        tg->ixAltColor : tg->ixColor);
+}
+
+static struct mafAli *wigMafLoadInRegion(struct sqlConnection *conn,
+    struct sqlConnection *conn2, char *table, char *chrom, int start, int end, char *file)
+/* Load mafs from region */
+{
+    return mafLoadInRegion2(conn, conn2, table, chrom, start, end, file);
+}
+
+static struct wigMafItem *newMafItem(char *s, int g, boolean lowerFirstChar)
+/* Allocate and initialize a maf item. Species param can be a db or name */
+{
+struct wigMafItem *mi;
+char *val;
+
+AllocVar(mi);
+if ((val = hGenome(s)) != NULL)
+    {
+    /* it's a database name */
+    mi->db = cloneString(s);
+    mi->name = val;
+    }
+else
+    {
+    mi->db = cloneString(s);
+    mi->name = cloneString(s);
+    }
+mi->name = hgDirForOrg(mi->name);
+if (lowerFirstChar)
+    *mi->name = tolower(*mi->name);
+mi->height = tl.fontHeight;
+mi->group = g;
+return mi;
+}
+
+struct wigMafItem *getSpeciesFromMaf(struct track *track, int height)
+{
+struct wigMafItem *mi = NULL, *miList = NULL;
+struct hash *hash = newHash(8);	/* keyed by database. */
+struct mafPriv *mp = getMafPriv(track);
+struct mafAli *maf;
+char buf[64];
+char *otherOrganism;
+
+if (mp->list == (struct mafAli *)-1)
+    return NULL;
+for (maf = mp->list; maf != NULL; maf = maf->next)
+    {
+    struct mafComp *mc;
+    for (mc = maf->components; mc != NULL; mc = mc->next)
+	{
+	mafSrcDb(mc->src, buf, sizeof(buf));
+	if (sameString(buf, database))
+	    continue;
+	if (hashLookup(hash, buf) == NULL)
+	    {
+	    AllocVar(mi);
+	    mi->db = cloneString(buf);
+	    otherOrganism = hOrganism(mi->db);
+	    mi->name =
+		(otherOrganism == NULL ? cloneString(buf) : otherOrganism);
+
+	    mi->height = tl.fontHeight;
+	    slAddHead(&miList, mi);
+	    hashAdd(hash, mi->db, mi);
+	    }
+	}
+    }
+hashFree(&hash);
+
+return miList;
+}
+
+struct wigMafItem *newSpeciesItems(struct track *track, int height)
+/* Make up item list for all species configured in track settings */
+{
+struct dyString *order = dyStringNew(256);
+char option[MAX_SP_SIZE];
+char *species[MAX_SP_SIZE];
+char *groups[20];
+char *defaultOff[MAX_SP_SIZE];
+char sGroup[24];
+struct wigMafItem *mi = NULL, *miList = NULL;
+int group;
+int i;
+int speciesCt = 0, groupCt = 1;
+int speciesOffCt = 0;
+struct hash *speciesOffHash = newHash(0);
+char buffer[128];
+char *speciesTarget = trackDbSetting(track->tdb, SPECIES_TARGET_VAR);
+char *speciesTree = trackDbSetting(track->tdb, SPECIES_TREE_VAR);
+bool useTarg;	/* use phyloTree to find shortest path */
+struct phyloTree *tree = NULL;
+char *speciesUseFile = trackDbSetting(track->tdb, SPECIES_USE_FILE);
+char *msaTable = NULL;
+
+/* either speciesOrder or speciesGroup is specified in trackDb */
+char *speciesOrder = trackDbSetting(track->tdb, SPECIES_ORDER_VAR);
+char *speciesGroup = trackDbSetting(track->tdb, SPECIES_GROUP_VAR);
+char *speciesOff = trackDbSetting(track->tdb, SPECIES_DEFAULT_OFF_VAR);
+
+bool lowerFirstChar = TRUE;
+char *firstCase;
+
+firstCase = trackDbSetting(track->tdb, ITEM_FIRST_CHAR_CASE);
+if (firstCase != NULL)
+    {
+    if (sameWord(firstCase, "noChange")) lowerFirstChar = FALSE;
+    }
+
+char *cfgPrefix = compositeViewControlNameFromTdb(track->tdb);
+safef(buffer, sizeof(buffer), "%s.vis",/*cfgPrefix*/track->track);
+if (!cartVarExists(cart, buffer) && (speciesTarget != NULL))
+    useTarg = TRUE;
+else
+    {
+    char *val;
+
+    val = cartUsualString(cart, buffer, "useCheck");
+    useTarg = sameString("useTarg",val);
+    }
+
+if (useTarg && (tree = phyloParseString(speciesTree)) == NULL)
+    useTarg = FALSE;
+
+if (speciesOrder == NULL && speciesGroup == NULL && speciesUseFile == NULL)
+    return getSpeciesFromMaf(track, height);
+
+if (speciesGroup)
+    groupCt = chopLine(cloneString(speciesGroup), groups);
+
+if (speciesUseFile)
+    {
+    if ((speciesGroup != NULL) || (speciesOrder != NULL))
+	errAbort("Can't specify speciesUseFile and speciesGroup or speciesOrder");
+    if (hIsGsidServer())
+	{
+	msaTable = trackDbSetting(track->tdb, "msaTable");
+    	if (msaTable != NULL)
+	    {
+	    speciesOrder = cartGetOrderFromFileAndMsaTable(database, cart, speciesUseFile, msaTable);
+    	    }
+	else
+	    {
+    	    speciesOrder = cartGetOrderFromFile(database, cart, speciesUseFile);
+	    }
+	}
+    else
+	{
+    	speciesOrder = cartGetOrderFromFile(database, cart, speciesUseFile);
+    	}
+    speciesOff = NULL;
+    }
+
+/* keep track of species configured off initially for track */
+if (speciesOff)
+    {
+    speciesOffCt = chopLine(cloneString(speciesOff), defaultOff);
+    for (i = 0; i < speciesOffCt; i++)
+        hashAdd(speciesOffHash, defaultOff[i], NULL);
+    }
+
+/* Make up items for other organisms by scanning through group & species
+   track settings */
+for (group = 0; group < groupCt; group++)
+    {
+    if (groupCt != 1 || !speciesOrder)
+        {
+        safef(sGroup, sizeof sGroup, "%s%s",
+                                SPECIES_GROUP_PREFIX, groups[group]);
+        speciesOrder = trackDbRequiredSetting(track->tdb, sGroup);
+        }
+    if (useTarg)
+	{
+	char *ptr, *path;
+	struct hash *orgHash = newHash(0);
+	int numNodes, ii;
+	char *nodeNames[512];
+	char *species = NULL;
+	char *lowerString;
+
+	path = phyloNodeNames(tree);
+	numNodes = chopLine(path, nodeNames);
+	for(ii=0; ii < numNodes; ii++)
+	    {
+	    if ((ptr = hOrganism(nodeNames[ii])) != NULL)
+		{
+		ptr[0] = tolower(ptr[0]);
+		hashAdd(orgHash, ptr, nodeNames[ii]);
+		}
+	    else
+		{
+		hashAdd(orgHash, nodeNames[ii], nodeNames[ii]);
+		}
+	    }
+
+	lowerString = cartUsualString(cart, SPECIES_HTML_TARGET,speciesTarget);
+	lowerString[0] = tolower(lowerString[0]);
+	species = hashFindVal(orgHash, lowerString);
+	if ((ptr = phyloFindPath(tree, database, species)) != NULL)
+	    speciesOrder = ptr;
+	}
+
+
+    safef(option, sizeof(option), "%s.speciesOrder", /*cfgPrefix*/track->track);
+    speciesCt = chopLine(cloneString(speciesOrder), species);
+
+    for (i = 0; i < speciesCt; i++)
+        {
+	if (!useTarg)
+	    {
+	    /* skip this species if UI checkbox was unchecked */
+	    safef(option, sizeof(option), "%s.%s", cfgPrefix, species[i]);
+	    if (!cartVarExists(cart, option))
+		if (hashLookup(speciesOffHash, species[i]))
+		    cartSetBoolean(cart, option, FALSE);
+	    if (!cartUsualBoolean(cart, option, TRUE))
+		continue;
+	    }
+        mi = newMafItem(species[i], group, lowerFirstChar);
+        slAddHead(&miList, mi);
+        }
+    }
+
+slReverse(&miList);
+for (mi = miList; mi != NULL; mi = mi->next)
+    {
+    mi->height = height;
+    dyStringPrintf(order, "%s ",mi->db);
+    }
+safef(option, sizeof(option), "%s.speciesOrder", /*cfgPrefix*/track->track);
+cartSetString(cart, option, order->string);
+compositeViewControlNameFree(&cfgPrefix);
+slReverse(&miList);
+
+return miList;
+}
+
+static struct wigMafItem *scoreItem(int scoreHeight, char *label)
+/* Make up item that will show the score */
+{
+struct wigMafItem *mi;
+
+AllocVar(mi);
+mi->name = cloneString(label);
+mi->height = scoreHeight;
+return mi;
+}
+
+struct mafPriv *getMafPriv(struct track *track)
+{
+struct mafPriv *mp = track->customPt;
+
+if (mp == NULL)
+    {
+    AllocVar(mp);
+    track->customPt = mp;
+    }
+
+return mp;
+}
+
+char *getTrackMafFile(struct track *track)
+/* look up MAF file name in track setting, return NULL if not found */
+{
+return hashFindVal(track->tdb->settingsHash, "mafFile");
+}
+
+char *getCustomMafFile(struct track *track)
+{
+char *fileName = getTrackMafFile(track);
+if (fileName == NULL)
+    errAbort("cannot find custom maf setting");
+return fileName;
+}
+
+static void loadMafsToTrack(struct track *track)
+/* load mafs in region to track custom pointer */
+{
+struct sqlConnection *conn;
+struct sqlConnection *conn2;
+struct mafPriv *mp = getMafPriv(track);
+
+if (winBaseCount > MAF_SUMMARY_VIEW)
+    return;
+
+/* we open two connections to the database
+ * that has the maf track in it.  One is
+ * for the scoredRefs, the other to access
+ * the extFile database.  We could get away
+ * with just one connection, but then we'd
+ * have to allocate more memory to hold
+ * the scoredRefs (whereas now we just use
+ * one statically loaded scoredRef).
+ */
+if (mp->ct)
+    {
+    char *fileName = getCustomMafFile(track);
+
+    conn = hAllocConn(CUSTOM_TRASH);
+    conn2 = hAllocConn(CUSTOM_TRASH);
+    mp->list = wigMafLoadInRegion(conn, conn2, mp->ct->dbTableName,
+				chromName, winStart - 2 , winEnd + 2, fileName);
+    hFreeConn(&conn);
+    hFreeConn(&conn2);
+    }
+else
+    {
+    char *fileName = getTrackMafFile(track);  // optional
+    conn = hAllocConn(database);
+    conn2 = hAllocConn(database);
+    mp->list = wigMafLoadInRegion(conn, conn2, track->table,
+				chromName, winStart - 2 , winEnd + 2, fileName);
+    hFreeConn(&conn);
+    hFreeConn(&conn2);
+    }
+}
+
+static struct wigMafItem *loadBaseByBaseItems(struct track *track)
+/* Make up base-by-base track items. */
+{
+struct wigMafItem *miList = NULL, *speciesList = NULL, *mi;
+int scoreHeight = 0;
+
+bool lowerFirstChar = TRUE;
+char *firstCase;
+
+firstCase = trackDbSetting(track->tdb, ITEM_FIRST_CHAR_CASE);
+if (firstCase != NULL)
+    {
+    if (sameWord(firstCase, "noChange")) lowerFirstChar = FALSE;
+    }
+
+loadMafsToTrack(track);
+
+/* NOTE: we are building up the item list backwards */
+
+/* Add items for conservation wiggles */
+struct track *wigTrack = track->subtracks;
+if (wigTrack)
+    {
+    enum trackVisibility wigVis = (wigTrack->limitedVis == tvDense ? tvDense : tvFull);
+    while (wigTrack !=  NULL)
+        {
+        scoreHeight = wigTotalHeight(wigTrack, wigVis);
+        mi = scoreItem(scoreHeight, wigTrack->shortLabel);
+        slAddHead(&miList, mi);
+        wigTrack = wigTrack->next;
+        }
+    }
+
+/* Make up item that will show gaps in this organism. */
+AllocVar(mi);
+
+mi->name = GAP_ITEM_LABEL;
+mi->height = tl.fontHeight;
+slAddHead(&miList, mi);
+
+/* Make up item for this organism. */
+mi = newMafItem(database, 0, lowerFirstChar);
+slAddHead(&miList, mi);
+speciesList = newSpeciesItems(track, tl.fontHeight);
+/* Make items for other species */
+miList = slCat(speciesList, miList);
+
+slReverse(&miList);
+return miList;
+}
+
+static char *summarySetting(struct track *track)
+/* Return the setting for the MAF summary table
+ * or NULL if none set  */
+{
+return trackDbSetting(track->tdb, SUMMARY_VAR);
+}
+
+static char *pairwiseSuffix(struct track *track)
+/* Return the suffix for the wiggle tables for the pairwise alignments,
+ * or NULL if none set  */
+{
+char *suffix = trackDbSetting(track->tdb, PAIRWISE_VAR);
+if (suffix != NULL)
+    suffix = firstWordInLine(cloneString(suffix));
+return suffix;
+}
+
+static int pairwiseWigHeight(struct track *track)
+/* Return the height of a pairwise wiggle for this track, or 0 if n/a
+ * NOTE: set one pixel smaller than we actually want, to
+ * leave a border at the bottom of the wiggle.
+ */
+{
+char *words[2];
+int wordCount;
+char *settings;
+struct track *wigTrack = track->subtracks;
+int pairwiseHeight = tl.fontHeight;
+int consWigHeight = 0;
+
+settings = cloneString(trackDbSetting(track->tdb, PAIRWISE_HEIGHT));
+if (settings != NULL)
+    return(atoi(firstWordInLine(settings)));
+
+if (wigTrack)
+    {
+    consWigHeight = wigTotalHeight(wigTrack, tvFull);
+    pairwiseHeight = max(consWigHeight/3 - 1, pairwiseHeight);
+    }
+
+settings = cloneString(trackDbSetting(track->tdb, PAIRWISE_VAR));
+if (settings == NULL)
+    return pairwiseHeight;
+
+/* get height for pairwise wiggles */
+if ((wordCount = chopLine(settings, words)) > 1)
+    {
+    int settingsHeight = atoi(words[1]);
+    if (settingsHeight < tl.fontHeight)
+       pairwiseHeight = tl.fontHeight;
+    else if (settingsHeight > consWigHeight && consWigHeight > 0)
+        pairwiseHeight = consWigHeight;
+    else
+        pairwiseHeight = settingsHeight;
+    }
+freez(&settings);
+return pairwiseHeight;
+}
+
+static char *getWigTablename(char *species, char *suffix)
+/* generate tablename for wiggle pairwise: "<species>_<table>_wig" */
+{
+char table[64];
+
+safef(table, sizeof(table), "%s_%s_wig", species, suffix);
+return cloneString(table);
+}
+
+static char *getMafTablename(char *species, char *suffix)
+/* generate tablename for wiggle maf:  "<species>_<table>" */
+{
+char table[64];
+
+safef(table, sizeof(table), "%s_%s", species, suffix);
+return cloneString(table);
+}
+
+static boolean displayPairwise(struct track *track)
+/* determine if tables are present for pairwise display */
+{
+return winBaseCount < MAF_SUMMARY_VIEW || isCustomTrack(track->table) ||
+	pairwiseSuffix(track) || summarySetting(track);
+}
+
+static boolean displayZoomedIn(struct track *track)
+/* determine if mafs are loaded -- zoomed in display */
+{
+struct mafPriv *mp = getMafPriv(track);
+
+return mp->list != (char *)-1;
+}
+
+static void markNotPairwiseItem(struct wigMafItem *mi)
+{
+    mi->ix = -1;
+}
+static boolean isPairwiseItem(struct wigMafItem *mi)
+{
+    return mi->ix != -1;
+}
+
+static struct wigMafItem *loadPairwiseItems(struct track *track)
+/* Make up items for modes where pairwise data are shown.
+   First an item for the score wiggle, then a pairwise item
+   for each "other species" in the multiple alignment.
+   These may be density plots (pack) or wiggles (full).
+   Return item list.  Also set customPt with mafList if
+   zoomed in */
+{
+struct wigMafItem *miList = NULL, *speciesItems = NULL, *mi;
+struct track *wigTrack = track->subtracks;
+int scoreHeight = tl.fontHeight * 4;
+
+if (winBaseCount < MAF_SUMMARY_VIEW)
+    {
+    /* "close in" display uses actual alignments from file */
+    struct mafPriv *mp = getMafPriv(track);
+    struct sqlConnection *conn, *conn2;
+
+    if (mp->ct)
+	{
+	char *fileName = getCustomMafFile(track);
+	conn = hAllocConn(CUSTOM_TRASH);
+	conn2 = hAllocConn(CUSTOM_TRASH);
+	mp->list = wigMafLoadInRegion(conn, conn2, mp->ct->dbTableName,
+					chromName, winStart, winEnd, fileName);
+	hFreeConn(&conn);
+	hFreeConn(&conn2);
+	}
+    else
+	{
+        char *fileName = getTrackMafFile(track);  // optional
+	conn = hAllocConn(database);
+	conn2 = hAllocConn(database);
+	mp->list = wigMafLoadInRegion(conn, conn2, track->table,
+					chromName, winStart, winEnd, fileName);
+	hFreeConn(&conn);
+	hFreeConn(&conn2);
+	}
+#ifdef DEBUG
+    slSort(&mp->list, mafCmp);
+#endif
+    }
+while (wigTrack != NULL)
+    {
+    /* display score graph along with pairs only if a wiggle
+     * is provided */
+    scoreHeight = wigTotalHeight(wigTrack, tvFull);
+    mi = scoreItem(scoreHeight, wigTrack->shortLabel);
+    /* mark this as not a pairwise item */
+    markNotPairwiseItem(mi);
+    slAddHead(&miList, mi);
+    wigTrack = wigTrack->next;
+    }
+if (displayPairwise(track))
+    /* make up items for other organisms by scanning through
+     * all mafs and looking at database prefix to source. */
+    {
+    speciesItems = newSpeciesItems(track, track->limitedVis == tvFull ?
+                                                pairwiseWigHeight(track) :
+                                                tl.fontHeight);
+    miList = slCat(speciesItems, miList);
+    }
+slReverse(&miList);
+return miList;
+}
+
+static struct wigMafItem *loadWigMafItems(struct track *track,
+                                                 boolean isBaseLevel)
+/* Load up items */
+{
+struct wigMafItem *miList = NULL, *mi;
+int scoreHeight = tl.fontHeight * 4;
+struct track *wigTrack = track->subtracks;
+
+struct mafPriv *mp = getMafPriv(track);
+mp->list = (char *)-1;   /* no maf's loaded or attempted to load */
+
+/* if we're out in summary view and rendering a custom
+ * track we force dense mode since we don't have
+ * a summary table (yet). */
+if ((winBaseCount >= MAF_SUMMARY_VIEW) && isCustomTrack(track->table))
+    track->limitedVis = tvDense;
+
+/* Load up mafs and store in track so drawer doesn't have
+ * to do it again. */
+/* Make up tracks for display. */
+if (track->limitedVis == tvFull || track->limitedVis == tvPack)
+    {
+    if (isBaseLevel)
+	{
+	miList = loadBaseByBaseItems(track);
+	}
+    /* zoomed out */
+    else
+	{
+	miList = loadPairwiseItems(track);
+	}
+    }
+else if (track->limitedVis == tvSquish)
+    {
+    if (!wigTrack)
+        {
+        scoreHeight = tl.fontHeight * 4;
+        if (winBaseCount < MAF_SUMMARY_VIEW)
+            loadMafsToTrack(track);
+        /* not a real meausre of conservation, so don't label it so */
+        miList = scoreItem(scoreHeight, "");
+        }
+    else while (wigTrack)
+        {
+        /* have a wiggle */
+        scoreHeight = wigTotalHeight(wigTrack, tvFull);
+        mi = scoreItem(scoreHeight, wigTrack->shortLabel);
+        slAddTail(&miList, mi);
+        wigTrack = wigTrack->next;
+        }
+    }
+else
+    {
+    /* dense mode, zoomed out - show density plot, with track label */
+    if (!wigTrack)
+        {
+        /* no wiggle -- use mafs if close in */
+        if (winBaseCount < MAF_SUMMARY_VIEW)
+#ifndef NOTYET
+           loadMafsToTrack(track);
+	AllocVar(miList);
+	miList->name = cloneString(track->shortLabel);
+	miList->height = tl.fontHeight;
+#else
+	    miList =  loadPairwiseItems(track);
+
+	/* remove components that aren't selected */
+	struct wigMafItem *mil = miList;
+	struct hash *nameHash = newHash(5);
+	for(;mil; mil = mil->next)
+	    hashStore(nameHash, mil->name);
+
+	struct mafPriv *mp = getMafPriv(track);
+	struct mafAli *mafList = mp->list;
+	struct mafComp *mc;
+
+	for(; mafList; mafList = mafList->next)
+	    {
+	    struct mafComp *prev = mafList->components;
+
+	    /* start after the master component */
+	    for(mc = mafList->components->next; mc; mc = mc->next)
+		{
+		char *ptr = strchr(mc->src, '.');
+		if (ptr)
+		    *ptr = 0;
+		char *ptr2 = hOrganism(mc->src);
+		*ptr2 = tolower(*ptr2);
+		if (!hashLookup(nameHash, ptr2))
+		    /* delete this component */
+		    prev->next = mc->next;
+		else
+		    {
+		    if (ptr)
+			*ptr = '.';
+		    prev = mc;
+		    }
+		}
+	    }
+
+	/* label with the track name */
+        miList->name = cloneString(track->shortLabel);
+	miList->next = NULL;
+#endif /* NOTYET */
+        }
+    else while (wigTrack)
+        {
+        AllocVar(mi);
+        mi->name = cloneString(wigTrack->shortLabel);
+        mi->height = tl.fontHeight + 1;
+        slAddTail(&miList, mi);
+        wigTrack = wigTrack->next;
+        }
+    }
+return miList;
+}
+
+static void wigMafLoad(struct track *track)
+/* Load up maf tracks.  What this will do depends on
+ * the zoom level and the display density. */
+{
+struct wigMafItem *miList = NULL;
+struct track *wigTrack = track->subtracks;
+
+// Make sure visibility takes into account any composite track with multi-views
+track->limitedVis = tvMin(track->visibility,limitedVisFromComposite(track));
+track->limitedVisSet = (track->limitedVis != tvHide && track->visibility != track->limitedVis);
+
+miList = loadWigMafItems(track, zoomedToBaseLevel);
+track->items = miList;
+
+while (wigTrack != NULL)
+    // load wiggle subtrack items
+    {
+    /* update track visibility from parent track,
+     * since hgTracks will update parent vis before loadItems */
+    wigTrack->visibility = track->visibility;
+    wigTrack->limitedVis = track->limitedVis;
+    wigTrack->loadItems(wigTrack);
+    wigTrack = wigTrack->next;
+    }
+}
+
+static int wigMafTotalHeight(struct track *track, enum trackVisibility vis)
+/* Return total height of maf track.  */
+{
+struct wigMafItem *mi;
+int total = 0,count=0;
+for (mi = track->items; mi != NULL; mi = mi->next)
+    {
+    total += mi->height;
+    count++;
+    }
+
+track->height = total;
+if (track->limitedVis == tvDense)
+    track->height=(tl.fontHeight+1)*count; // Evidence that track-height comes in as 9 but should be 10!
+return track->height;
+}
+
+static int wigMafItemHeight(struct track *track, void *item)
+/* Return total height of maf track.  */
+{
+struct wigMafItem *mi = item;
+return mi->height;
+}
+
+static void wigMafFree(struct track *track)
+/* Free up maf items. */
+{
+struct mafPriv *mp = getMafPriv(track);
+if (mp->list != NULL && mp->list != (char *)-1)
+    mafAliFreeList((struct mafAli **)&mp->list);
+if (track->items != NULL)
+    wigMafItemFreeList((struct wigMafItem **)&track->items);
+}
+
+static char *wigMafItemName(struct track *track, void *item)
+/* Return name of maf level track. */
+{
+struct wigMafItem *mi = item;
+return mi->name;
+}
+
+static void processInserts(char *text, struct mafAli *maf,
+                                struct hash *itemHash,
+	                        int insertCounts[], int baseCount)
+/* Make up insert line from sequence of reference species.
+   It has a gap count at each displayed base position, and is generated by
+   counting up '-' chars in the sequence, where  */
+{
+int i, baseIx = 0;
+struct mafComp *mc;
+char c;
+
+for (i=0; i < maf->textSize && baseIx < baseCount - 1; i++)
+    {
+    c = text[i];
+    if (c == '-')
+        {
+        for (mc = maf->components; mc != NULL; mc = mc->next)
+            {
+            char buf[64];
+            mafSrcDb(mc->src, buf, sizeof buf);
+            if (hashLookup(itemHash, buf) == NULL)
+                continue;
+            if (mc->text == NULL)
+                /* empty row annotation */
+                continue;
+            if (mc->text[i] != '-')
+                {
+                insertCounts[baseIx]++;
+                break;
+                }
+            }
+        }
+    else
+        baseIx++;
+    }
+}
+
+
+static int processSeq(char *text, char *masterText, int textSize,
+                            char *outLine, int offset, int outSize,
+			    int *inserts, int insertCounts)
+/* Add text to outLine, suppressing copy where there are dashes
+ * in masterText.  This effectively projects the alignment onto
+ * the master genome.
+ * If no dash exists in this sequence, count up size
+ * of the insert and save in the line.
+ */
+{
+int i, outIx = 0, outPositions = 0;
+int insertSize = 0, previousInserts = 0;
+int previousBreaks = 0;
+
+outLine = outLine + offset + previousBreaks + (previousInserts * 2);
+for (i=0; i < textSize /*&& outPositions < outSize*/;  i++)
+    {
+    if (masterText[i] != '-')
+        {
+        if (insertSize != 0)
+            {
+	    inserts[insertCounts++] = offset + outIx + 1;
+            insertSize = 0;
+            }
+	outLine[outIx++] = text[i];
+        outPositions++;
+	}
+    else
+        {
+        /* gap in master (reference) sequence but not in this species */
+	switch(text[i])
+	    {
+	    case 'N':
+	    case '-':
+	    case '=':
+	    case ' ':
+		break;
+	    default:
+		insertSize++;
+	    }
+        }
+    }
+    if (insertSize != 0)
+	{
+	inserts[insertCounts++] = offset + outIx + 1;
+	}
+return insertCounts;
+}
+
+static int drawScore(float score, int chromStart, int chromEnd, int seqStart,
+                        double scale, struct hvGfx *hvg, int xOff, int yOff,
+                        int height, Color color, enum trackVisibility vis)
+/* Draw density plot or graph based on score. Return last X drawn  */
+{
+int x1,x2,y,w;
+int height1 = height-1;
+
+x1 = round((chromStart - seqStart)*scale);
+x2 = round((chromEnd - seqStart)*scale);
+w = x2-x1+1;
+if (vis == tvFull)
+    {
+    y = score * height1;
+    hvGfxBox(hvg, x1 + xOff, yOff + height1 - y, w, y+1, color);
+    }
+else
+    {
+    Color c;
+    int shade = (score * maxShade) + 1;
+    if (shade < 0)
+        shade = 0;
+    else if (shade > maxShade)
+        shade = maxShade;
+    c = shadesOfGray[shade];
+    hvGfxBox(hvg, x1 + xOff, yOff, w, height1, c);
+    }
+return xOff + x1 + w - 1;
+}
+
+static void drawScoreSummary(struct mafSummary *summaryList, int height,
+                             int seqStart, int seqEnd,
+                            struct hvGfx *hvg, int xOff, int yOff,
+                            int width, MgFont *font,
+                            Color color, Color altColor,
+                            enum trackVisibility vis, boolean chainBreaks)
+/* Draw density plot or graph for summary maf scores */
+{
+struct mafSummary *ms;
+double scale = scaleForPixels(width);
+boolean isDouble = FALSE;
+int x1, x2;
+int w = 0;
+int chromStart = seqStart;
+int lastX;
+
+/* draw chain before first alignment */
+ms = summaryList;
+if (chainBreaks && ms->chromStart > chromStart)
+    {
+    if (isContigOrTandem(ms->leftStatus[0]) ||
+	 ms->leftStatus[0] == MAF_INSERT_STATUS)
+	{
+	isDouble = (ms->leftStatus[0] == MAF_INSERT_STATUS);
+	x1 = xOff;
+	x2 = round((double)((int)ms->chromStart-1 - seqStart) * scale) + xOff;
+	w = x2 - x1;
+	if (w > 0)
+	    drawMafChain(hvg, x1, yOff, w, height, isDouble);
+	}
+    else if (ms->leftStatus[0] == MAF_MISSING_STATUS )
+	{
+	Color fuzz = shadesOfGray[1];
+
+	x1 = xOff;
+	x2 = round((double)((int)ms->chromStart-1 - seqStart) * scale) + xOff;
+	w = x2 - x1;
+	hvGfxBox(hvg, x1, yOff, w, height, fuzz);
+	}
+    }
+for (ms = summaryList; ms != NULL; ms = ms->next)
+    {
+    lastX = drawScore(ms->score, ms->chromStart, ms->chromEnd, seqStart,
+                        scale, hvg, xOff, yOff, height, color, vis);
+
+    /* draw chain after alignment */
+    if (chainBreaks && ms->chromEnd < seqEnd && ms->next != NULL)
+	{
+	if (isContigOrTandem(ms->rightStatus[0]) ||
+	     ms->rightStatus[0] == MAF_INSERT_STATUS)
+	    {
+	    isDouble = (ms->rightStatus[0] == MAF_INSERT_STATUS);
+	    x1 = round((double)((int)ms->chromEnd+1 - seqStart) * scale) + xOff;
+	    x2 = round((double)((int)ms->next->chromStart-1 - seqStart) * scale)
+		    + xOff;
+	    w = x2 - x1;
+	    if (w == 1 && x1 == lastX)
+		continue;
+	    if (w > 0);
+		drawMafChain(hvg, x1, yOff, w, height, isDouble);
+	    }
+	else if (ms->rightStatus[0] == MAF_MISSING_STATUS )
+	    {
+	    Color fuzz = shadesOfGray[2];
+
+	    x1 = round((double)((int)ms->chromEnd+1 - seqStart) * scale) + xOff;
+	    x2 = round((double)((int)ms->next->chromStart-1 - seqStart) * scale) + xOff ;
+	    w = x2 - x1;
+	    if (w == 1 && x1 == lastX)
+		continue;
+	    if (w > 0)
+		hvGfxBox(hvg, x1, yOff, w, height, fuzz);
+	    }
+	}
+    }
+}
+
+static void drawScoreOverviewC(struct sqlConnection *conn,
+			    char *tableName, int height,
+                             int seqStart, int seqEnd,
+                            struct hvGfx *hvg, int xOff, int yOff,
+                            int width, MgFont *font,
+                            Color color, Color altColor,
+                            enum trackVisibility vis)
+/* Draw density plot or graph for overall maf scores rather than computing
+ * by sections, for speed.  Don't actually load the mafs -- just
+ * the scored refs from the table.
+ * TODO: reuse code in mafTrack.c
+ */
+{
+char **row;
+int rowOffset;
+struct sqlResult *sr = hRangeQuery(conn, tableName, chromName,
+			    seqStart, seqEnd, NULL, &rowOffset);
+
+double scale = scaleForPixels(width);
+while ((row = sqlNextRow(sr)) != NULL)
+    {
+    struct scoredRef ref;
+    scoredRefStaticLoad(row + rowOffset, &ref);
+    drawScore(ref.score, ref.chromStart, ref.chromEnd, seqStart, scale,
+                hvg, xOff, yOff, height, color, vis);
+    }
+sqlFreeResult(&sr);
+}
+
+static void drawScoreOverview(char *tableName,
+	int height, int seqStart, int seqEnd,
+	struct hvGfx *hvg, int xOff, int yOff,
+	int width, MgFont *font,
+	Color color, Color altColor,
+	enum trackVisibility vis)
+{
+struct sqlConnection *conn = hAllocConn(database);
+
+drawScoreOverviewC(conn, tableName, height, seqStart, seqEnd,
+	hvg, xOff, yOff, width, font, color, altColor, vis);
+
+hFreeConn(&conn);
+}
+
+static void drawScoreOverviewCT(char *tableName,
+	int height, int seqStart, int seqEnd,
+	struct hvGfx *hvg, int xOff, int yOff,
+	int width, MgFont *font,
+	Color color, Color altColor,
+	enum trackVisibility vis)
+{
+struct sqlConnection *conn = hAllocConn(CUSTOM_TRASH);
+
+drawScoreOverviewC(conn, tableName, height, seqStart, seqEnd,
+	hvg, xOff, yOff, width, font, color, altColor, vis);
+
+hFreeConn(&conn);
+}
+
+
+static boolean drawPairsFromSummary(struct track *track,
+        int seqStart, int seqEnd,
+        struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font,
+        Color color, enum trackVisibility vis)
+{
+/* Draw pairwise display for this multiple alignment */
+char *summary;
+struct wigMafItem *miList = track->items, *mi = miList;
+struct sqlConnection *conn;
+struct sqlResult *sr = NULL;
+char **row = NULL;
+int rowOffset = 0;
+struct mafSummary *ms, *summaryList;
+struct hash *componentHash = newHash(6);
+struct hashEl *hel;
+struct hashCookie cookie;
+struct dyString *where = dyStringNew(256);
+char *whereClause = NULL;
+boolean useIrowChains = TRUE;
+char option[64];
+
+if (miList == NULL)
+    return FALSE;
+
+/* get summary table name from trackDb */
+if ((summary = summarySetting(track)) == NULL)
+    return FALSE;
+
+char *cfgPrefix = compositeViewControlNameFromTdb(track->tdb);
+
+safef(option, sizeof(option), "%s.%s", cfgPrefix, MAF_CHAIN_VAR);
+compositeViewControlNameFree(&cfgPrefix);
+if (cartVarExists(cart, option))
+    useIrowChains = cartCgiUsualBoolean(cart, option, TRUE);
+else
+    {
+    char *irowString = trackDbSetting(track->tdb, "irows");
+    if (irowString && sameString(irowString, "off"))
+	useIrowChains = FALSE;
+    cartSetBoolean(cart, option, useIrowChains);
+    }
+
+/* Create SQL where clause that will load up just the
+ * summaries for the species that we are including. */
+conn = hAllocConn(database);
+dyStringAppend(where, "src in (");
+for (mi = miList; mi != NULL; mi = mi->next)
+    {
+    if (!isPairwiseItem(mi))
+	/* exclude non-species items (e.g. conservation wiggle */
+	continue;
+    dyStringPrintf(where, "'%s'", mi->db);
+    if (mi->next != NULL)
+	dyStringAppend(where, ",");
+    }
+dyStringAppend(where, ")");
+/* check for empty where clause */
+if (!sameString(where->string,"src in ()"))
+    whereClause = where->string;
+sr = hOrderedRangeQuery(conn, summary, chromName, seqStart, seqEnd,
+                        whereClause, &rowOffset);
+
+boolean hasFieldLeftStatus = hHasField(database, summary, "leftStatus");
+
+/* Loop through result creating a hash of lists of maf summary blocks.
+ * The hash is keyed by species. */
+while ((row = sqlNextRow(sr)) != NULL)
+    {
+    if (hasFieldLeftStatus)
+        ms = mafSummaryLoad(row + rowOffset);
+    else
+        /* previous table schema didn't have status fields */
+        ms = mafSummaryMiniLoad(row + rowOffset);
+    /* prune to fit in window bounds */
+    if (ms->chromStart < seqStart)
+        ms->chromStart = seqStart;
+    if (ms->chromEnd > seqEnd)
+        ms->chromEnd = seqEnd;
+    if ((hel = hashLookup(componentHash, ms->src)) == NULL)
+        hashAdd(componentHash, ms->src, ms);
+    else
+        slAddHead(&(hel->val), ms);
+    }
+sqlFreeResult(&sr);
+
+/* reverse summary lists */
+cookie = hashFirst(componentHash);
+while ((hel = hashNext(&cookie)) != NULL)
+    slReverse(&hel->val);
+hFreeConn(&conn);
+
+/* display pairwise items */
+for (mi = miList; mi != NULL; mi = mi->next)
+    {
+    if (mi->ix < 0)
+        /* ignore item for the score */
+        continue;
+    summaryList = (struct mafSummary *)hashFindVal(componentHash, mi->db);
+    if (summaryList == NULL)
+        summaryList = (struct mafSummary *)hashFindVal(componentHash, mi->name);
+
+    if (summaryList != NULL)
+	{
+	if (vis == tvFull)
+	    {
+	    hvGfxSetClip(hvg, xOff, yOff, width, 16);
+	    drawScoreSummary(summaryList, mi->height, seqStart, seqEnd, hvg,
+				    xOff, yOff, width, font, track->ixAltColor,
+				    track->ixAltColor, tvFull, useIrowChains);
+	    hvGfxUnclip(hvg);
+	    }
+	else
+	    {
+	    /* pack */
+	    /* get maf table, containing pairwise alignments for this organism */
+	    /* display pairwise alignments in this region in dense format */
+	    hvGfxSetClip(hvg, xOff, yOff, width, mi->height);
+	    drawScoreSummary(summaryList, mi->height, seqStart, seqEnd, hvg,
+				xOff, yOff, width, font, color, color, tvDense,
+				useIrowChains);
+	    hvGfxUnclip(hvg);
+	    }
+	}
+    yOff += mi->height;
+    }
+return TRUE;
+}
+
+static boolean drawPairsFromPairwiseMafScores(struct track *track,
+        int seqStart, int seqEnd, struct hvGfx *hvg, int xOff, int yOff,
+        int width, MgFont *font, Color color, enum trackVisibility vis)
+/* Draw pairwise display for this multiple alignment */
+{
+char *suffix;
+char *tableName;
+Color pairColor;
+struct track *wigTrack = track->subtracks;
+int pairwiseHeight = pairwiseWigHeight(track);
+struct wigMafItem *miList = track->items, *mi = miList;
+
+if (miList == NULL)
+    return FALSE;
+
+/* get pairwise table suffix from trackDb */
+suffix = pairwiseSuffix(track);
+
+if (vis == tvFull && !isCustomTrack(track->table))
+    {
+    double minY = 50.0;
+    double maxY = 100.0;
+
+    /* NOTE: later, remove requirement for wiggle */
+    if (wigTrack == NULL)
+        return FALSE;
+    /* swap colors for pairwise wiggles */
+    pairColor = wigTrack->ixColor;
+    wigTrack->ixColor = wigTrack->ixAltColor;
+    wigTrack->ixAltColor = pairColor;
+    wigSetCart(wigTrack, MIN_Y, (void *)&minY);
+    wigSetCart(wigTrack, MAX_Y, (void *)&maxY);
+    }
+
+/* display pairwise items */
+for (mi = miList; mi != NULL; mi = mi->next)
+    {
+    if (mi->ix < 0)
+        /* ignore item for the score */
+        continue;
+    if (isCustomTrack(track->table))
+	{
+	struct mafPriv *mp = getMafPriv(track);
+	drawScoreOverviewCT(mp->ct->dbTableName, mi->height,
+		seqStart, seqEnd,
+		hvg, xOff, yOff, width, font, color, color, vis);
+	hvGfxUnclip(hvg);
+	}
+    else if (vis == tvFull)
+        {
+        /* get wiggle table, of pairwise
+           for example, percent identity */
+        tableName = getWigTablename(mi->name, suffix);
+        if (!hTableExists(database, tableName))
+            tableName = getWigTablename(mi->db, suffix);
+        if (hTableExists(database, tableName))
+            {
+            /* reuse the wigTrack for pairwise tables */
+            wigTrack->track = tableName;
+            wigTrack->table = tableName;
+            wigTrack->loadItems(wigTrack);
+            wigTrack->height = wigTrack->lineHeight = wigTrack->heightPer =
+                                                    pairwiseHeight - 1;
+            /* clip, but leave 1 pixel border */
+            hvGfxSetClip(hvg, xOff, yOff, width, wigTrack->height);
+            wigTrack->drawItems(wigTrack, seqStart, seqEnd, hvg, xOff, yOff,
+                             width, font, color, tvFull);
+            hvGfxUnclip(hvg);
+            }
+        else
+            {
+            /* no wiggle table for this -- compute a graph on-the-fly
+               from mafs */
+            hvGfxSetClip(hvg, xOff, yOff, width, mi->height);
+            tableName = getMafTablename(mi->name, suffix);
+            if (!hTableExists(database, tableName))
+                tableName = getMafTablename(mi->db, suffix);
+            if (hTableExists(database, tableName))
+                drawScoreOverview(tableName, mi->height, seqStart, seqEnd, hvg,
+                                xOff, yOff, width, font, track->ixAltColor,
+                                track->ixAltColor, tvFull);
+            hvGfxUnclip(hvg);
+            }
+        /* need to add extra space between wiggles (for now) */
+        mi->height = pairwiseHeight;
+        }
+    else
+        {
+	/* pack */
+	/* get maf table, containing pairwise alignments for this organism */
+	/* display pairwise alignments in this region in dense format */
+	hvGfxSetClip(hvg, xOff, yOff, width, mi->height);
+	tableName = getMafTablename(mi->name, suffix);
+	if (!hTableExists(database, tableName))
+	    tableName = getMafTablename(mi->db, suffix);
+	if (hTableExists(database, tableName))
+	    drawScoreOverview(tableName, mi->height, seqStart, seqEnd, hvg,
+			    xOff, yOff, width, font, color, color, tvDense);
+        hvGfxUnclip(hvg);
+        }
+    yOff += mi->height;
+    }
+return TRUE;
+}
+
+static boolean drawPairsFromMultipleMaf(struct track *track,
+        int seqStart, int seqEnd,
+        struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font,
+        Color color, enum trackVisibility vis)
+/* Draw pairwise display from maf of multiple alignment.
+ * Extract pairwise alignments from maf and rescore.
+ * This is used only when zoomed-in.
+ */
+{
+struct wigMafItem *miList = track->items, *mi = miList;
+int graphHeight = 0;
+Color pairColor = (vis == tvFull ? track->ixAltColor : color);
+boolean useIrowChains = TRUE;
+char option[64];
+
+struct mafPriv *mp = getMafPriv(track);
+if (miList == NULL || mp->list == NULL)
+    return FALSE;
+
+char *cfgPrefix = compositeViewControlNameFromTdb(track->tdb);
+
+safef(option, sizeof(option), "%s.%s", cfgPrefix, MAF_CHAIN_VAR);
+compositeViewControlNameFree(&cfgPrefix);
+if (cartVarExists(cart, option))
+    useIrowChains = cartCgiUsualBoolean(cart, option, TRUE);
+else
+    {
+    char *irowString = trackDbSetting(track->tdb, "irows");
+    if (irowString && sameString(irowString, "off"))
+	useIrowChains = FALSE;
+    cartSetBoolean(cart, option, useIrowChains);
+    }
+
+if (vis == tvFull)
+    graphHeight = pairwiseWigHeight(track);
+
+/* display pairwise items */
+for (mi = miList; mi != NULL; mi = mi->next)
+    {
+    struct mafAli *mafList = NULL, *maf, *pairMaf;
+    struct mafComp *mcThis, *mcPair = NULL, *mcMaster = NULL;
+
+    if (mi->ix < 0)
+        /* ignore item for the score */
+        continue;
+
+    /* using maf sequences from file */
+    /* create pairwise maf list from the multiple maf */
+    struct mafPriv *mp = getMafPriv(track);
+    for (maf = mp->list; maf != NULL; maf = maf->next)
+        {
+        if ((mcThis = mafMayFindCompSpecies(maf, mi->db, '.')) == NULL)
+            continue;
+	//if (mcPair->srcSize != 0)
+        // TODO: replace with a cloneMafComp()
+        AllocVar(mcPair);
+        mcPair->src = cloneString(mcThis->src);
+        mcPair->srcSize = mcThis->srcSize;
+        mcPair->strand = mcThis->strand;
+        mcPair->start = mcThis->start;
+        mcPair->size = mcThis->size;
+        mcPair->text = cloneString(mcThis->text);
+        mcPair->leftStatus = mcThis->leftStatus;
+        mcPair->leftLen = mcThis->leftLen;
+        mcPair->rightStatus = mcThis->rightStatus;
+        mcPair->rightLen = mcThis->rightLen;
+
+        mcThis = mafFindCompSpecies(maf, database, '.');
+        AllocVar(mcMaster);
+        mcMaster->src = cloneString(mcThis->src);
+        mcMaster->srcSize = mcThis->srcSize;
+        mcMaster->strand = mcThis->strand;
+        mcMaster->start = mcThis->start;
+        mcMaster->size = mcThis->size;
+        mcMaster->text = cloneString(mcThis->text);
+        mcMaster->next = mcPair;
+
+        AllocVar(pairMaf);
+        pairMaf->components = mcMaster;
+        pairMaf->textSize = maf->textSize;
+        slAddHead(&mafList, pairMaf);
+        }
+    slReverse(&mafList);
+
+    /* compute a graph or density on-the-fly from mafs */
+    hvGfxSetClip(hvg, xOff, yOff, width, mi->height);
+    drawMafRegionDetails(mafList, mi->height, seqStart, seqEnd, hvg, xOff, yOff,
+                         width, font, pairColor, pairColor, vis, FALSE,
+                         useIrowChains);
+    hvGfxUnclip(hvg);
+
+    /* need to add extra space between graphs ?? (for now) */
+    if (vis == tvFull)
+        mi->height = graphHeight;
+
+    yOff += mi->height;
+    mafAliFreeList(&mafList);
+    }
+return TRUE;
+}
+
+static boolean wigMafDrawPairwise(struct track *track, int seqStart, int seqEnd,
+        struct hvGfx *hvg, int xOff, int yOff, int width, MgFont *font,
+        Color color, enum trackVisibility vis)
+/* Draw pairwise display for this multiple alignment
+ * When zoomed in, use on-the-fly scoring of alignments extracted from multiple
+ * When zoomed out:
+ *  if "pairwise" setting is on, use pairwise tables (maf or wiggle)
+ *      <species>_<suffix> for maf, <species>_<suffix>_wig for wiggle
+ *              For full mode, display graph.
+ *              for pack mode, display density plot.
+ *  if "summary" setting is on, use maf summary table
+ *      (saves space, and performs better) */
+{
+    if (displayZoomedIn(track))
+        return drawPairsFromMultipleMaf(track, seqStart, seqEnd, hvg,
+                                        xOff, yOff, width, font, color, vis);
+    if (isCustomTrack(track->table) || pairwiseSuffix(track))
+        return drawPairsFromPairwiseMafScores(track, seqStart, seqEnd, hvg,
+                                        xOff, yOff, width, font, color, vis);
+    if (summarySetting(track))
+        return drawPairsFromSummary(track, seqStart, seqEnd, hvg,
+                                        xOff, yOff, width, font, color, vis);
+    return FALSE;
+}
+
+static void alternateBlocksBehindChars(struct hvGfx *hvg, int x, int y,
+	int width, int height, int charWidth, int charCount,
+	int stripeCharWidth, Color a, Color b)
+/* Draw blocks that alternate between color a and b. */
+{
+int x1,x2 = x + width;
+int color = a;
+int i;
+for (i=0; i<charCount; i += stripeCharWidth)
+    {
+    x1 = i * width / charCount;
+    x2 = (i+stripeCharWidth) * width/charCount;
+    hvGfxBox(hvg, x1+x, y, x2-x1, height, color);
+    if (color == a)
+        color = b;
+    else
+        color = a;
+    }
+}
+
+void alignSeqToUpperN(char *line)
+/* force base chars to upper, ignoring insert counts */
+{
+int i;
+for (i=0; line[i] != 0; i++)
+    line[i] = toupper(line[i]);
+}
+
+void complementUpperAlignSeq(DNA *dna, int size)
+/* Complement DNA (not reverse), ignoring insert counts.
+ * Assumed to be all upper case bases */
+{
+int i;
+for (i = 0; i < size; i++, dna++)
+    {
+    if (*dna == 'A')
+        *dna = 'T';
+    else if (*dna == 'C')
+        *dna = 'G';
+    else if (*dna == 'G')
+        *dna = 'C';
+    else if (*dna == 'T')
+        *dna = 'A';
+    }
+}
+
+void reverseForStrand(DNA *dna, int length, char strand, bool alreadyComplemented)
+{
+if (strand == '-')
+    {
+    if (alreadyComplemented)
+	reverseBytes(dna, length);
+    else
+	reverseComplement(dna, length);
+    }
+else
+    {
+    if (alreadyComplemented)
+	complement(dna, length);
+    }
+}
+
+#define ISGAP(x)  (((x) == '=') || (((x) == '-')))
+#define ISN(x)  ((x) == 'N')
+#define ISSPACE(x)  ((x) == ' ')
+#define ISGAPSPACEORN(x)  (ISSPACE(x) || ISGAP(x) || ISN(x))
+
+static AA lookupAndCheckCodon(char *codon)
+{
+AA retValue;
+
+if ((retValue = lookupCodon(codon)) == 0)
+    return '*';
+
+return retValue;
+}
+
+static void translateCodons(struct sqlConnection *conn,
+    struct sqlConnection *conn2, char *tableName, char *compName,
+    DNA *dna, int start, int length, int frame, char strand,
+    int prevEnd, int nextStart, bool alreadyComplemented,
+    int x, int y, int width, int height, struct hvGfx *hvg, char *mafFile)
+{
+int size = length;
+DNA *ptr;
+int color;
+int end = start + length;
+int x1;
+char masterChrom[128];
+struct mafAli *ali, *sub = NULL;
+struct mafComp *comp = NULL;
+int mult = 1;
+char codon[4];
+int fillBox = FALSE;
+
+safef(masterChrom, sizeof(masterChrom), "%s.%s", database, chromName);
+
+dna += start;
+
+reverseForStrand(dna, length, strand, alreadyComplemented);
+
+ptr = dna;
+color = shadesOfSea[0];
+
+mult = 0;
+if (frame && (prevEnd == -1))
+    {
+    switch(frame)
+	{
+	case 1:
+	    if (0)//!( ISGAPSPACEORN(ptr[0]) ||ISGAPSPACEORN(ptr[1])))
+		{
+		fillBox = TRUE;
+		*ptr++ = 'X';
+		*ptr++ = 'X';
+		mult = 2;
+		}
+	    else
+		{
+		reverseForStrand(ptr, 2, strand, alreadyComplemented);
+		ptr +=2;
+		}
+	    length -=2;
+	    break;
+	case 2:
+	    if (0)//!( ISGAPSPACEORN(ptr[0])))
+		{
+		fillBox = TRUE;
+		*ptr++ = 'X';
+		length -=1;
+		mult = 1;
+		}
+	    else
+		{
+		reverseForStrand(ptr, 1, strand, alreadyComplemented);
+		ptr++;
+		}
+	    length -=1;
+	    break;
+	}
+    }
+else if (frame && (prevEnd != -1))
+    {
+    memset(codon, 0, sizeof(codon));
+    switch(frame)
+	{
+	case 1:
+	    ali = mafLoadInRegion2(conn, conn2, tableName, chromName, prevEnd , prevEnd + 1, mafFile  );
+	    if (ali != NULL)
+		{
+		sub = mafSubset(ali, masterChrom, prevEnd , prevEnd + 1  );
+		comp = mafMayFindCompSpecies(sub, compName, '.');
+		}
+	    if (comp && comp->text && (!(ISGAPSPACEORN(comp->text[0]) ||ISGAPSPACEORN(ptr[0]) ||ISGAPSPACEORN(ptr[1]))))
+		{
+		if (strand == '-')
+		    complement(comp->text, 1);
+		codon[0] = comp->text[0];
+		codon[1] = ptr[0];
+		codon[2] = ptr[1];
+		fillBox = TRUE;
+		mult = 2;
+		*ptr++ = ' ';
+		*ptr++ = lookupAndCheckCodon(codon);
+		}
+	    else
+		ptr+=2;
+	    length -= 2;
+	    break;
+	case 2:
+	    if (strand == '-')
+		{
+		ali = mafLoadInRegion2(conn, conn2, tableName, chromName,
+			    prevEnd, prevEnd + 2, mafFile);
+		if (ali != NULL)
+		    sub = mafSubset(ali, masterChrom, prevEnd, prevEnd + 2  );
+		}
+	    else
+		{
+		ali = mafLoadInRegion2(conn, conn2, tableName, chromName,
+			    prevEnd - 1, prevEnd + 1, mafFile);
+		if (ali != NULL)
+		    sub = mafSubset(ali, masterChrom, prevEnd - 1, prevEnd + 1);
+		}
+	    if (sub != NULL)
+		comp = mafMayFindCompSpecies(sub, compName, '.');
+	    if (comp && comp->text && (!(ISGAPSPACEORN(comp->text[0])||ISGAPSPACEORN(comp->text[1]) ||ISGAPSPACEORN(*ptr))))
+		{
+		if (strand == '-')
+		    reverseComplement(comp->text, 2);
+		codon[0] = comp->text[0];
+		codon[1] = comp->text[1];
+		codon[2] = *ptr;
+		fillBox = TRUE;
+		mult = 1;
+		*ptr++ = lookupAndCheckCodon(codon);
+		}
+	    else
+		ptr++;
+	    length -= 1;
+	    break;
+	}
+    }
+if (fillBox)
+    {
+    if (strand == '-')
+	{
+	x1 = x + ( end - ( 5 - frame)  ) * width / winBaseCount;
+	}
+    else
+	{
+	x1 = x + (start - 2) * width / winBaseCount;
+	}
+    hvGfxBox(hvg, x1, y, mult*width/winBaseCount + 1 , height, color);
+    }
+
+for (;length > 2; ptr +=3 , length -=3)
+    {
+    if (!(ISGAPSPACEORN(ptr[0]) || ISGAPSPACEORN(ptr[1]) || ISGAPSPACEORN(ptr[2]) ))
+	{
+	ptr[1] = lookupAndCheckCodon(ptr);
+	ptr[0] = ' ';
+	ptr[2] = ' ';
+
+	if (strand == '-')
+	    {
+	    x1 = x + ( start + length - 3 - 2) * width / winBaseCount;
+	    }
+	else
+	    {
+	    x1 = x + (end - length - 2) * width / winBaseCount;
+	    }
+
+	if (color == shadesOfSea[0])
+	    color = shadesOfSea[1];
+	else
+	    color = shadesOfSea[0];
+	hvGfxBox(hvg, x1, y, 3*width/winBaseCount + 1 , height, color);
+	}
+    }
+
+if (length && (nextStart != -1))
+    {
+    char codon[4];
+    int mult = 1;
+    boolean fillBox = FALSE;
+
+    memset(codon, 0, sizeof(codon));
+    sub = NULL;
+
+    if (strand == '-')
+	{
+	ali = mafLoadInRegion2(conn, conn2, tableName, chromName,
+		    nextStart - 2 + length, nextStart + 1, mafFile );
+	if (ali != NULL)
+	    sub = mafSubset(ali, masterChrom,
+		nextStart - 2 + length, nextStart + 1);
+	}
+    else
+	{
+	ali = mafLoadInRegion2(conn, conn2, tableName, chromName,
+				nextStart , nextStart + 2, mafFile );
+	if (ali != NULL)
+	    sub = mafSubset(ali, masterChrom, nextStart , nextStart + 2);
+	}
+    if (sub != NULL)
+	comp = mafMayFindCompSpecies(sub, compName, '.');
+    if (sub && comp && comp->text)
+	{
+	switch(length)
+	    {
+	    case 2:
+		if (strand == '-')
+		    complement(comp->text, 1);
+		codon[0] = *ptr;
+		codon[1] = *(1 + ptr);
+		codon[2] = *comp->text;
+
+		if (!(ISGAPSPACEORN(codon[0]) ||ISGAPSPACEORN(codon[1]) ||ISGAPSPACEORN(codon[2])))
+		    {
+		    fillBox = TRUE;
+		    *ptr++ = ' ';
+		    *ptr++ = lookupAndCheckCodon(codon);
+		    mult = 2;
+		    }
+		break;
+	    case 1:
+		if (strand == '-')
+		    reverseComplement(comp->text, 2);
+		codon[0] = *ptr;
+		codon[1] = comp->text[0];
+		codon[2] = comp->text[1];
+		if (!(ISGAPSPACEORN(codon[0]) ||ISGAPSPACEORN(codon[1]) ||ISGAPSPACEORN(codon[2])))
+		    {
+		    *ptr++ = lookupAndCheckCodon(codon);
+		    fillBox = TRUE;
+		    }
+		break;
+	    }
+	if (fillBox)
+	    {
+	    if (strand == '-')
+		{
+		x1 = x + ( start  - 2   ) * width / winBaseCount;
+		}
+	    else
+		{
+		x1 = x + (end - length - 2) * width / winBaseCount;
+		}
+	    if (color == shadesOfSea[0])
+		color = shadesOfSea[1];
+	    else
+		color = shadesOfSea[0];
+	    hvGfxBox(hvg, x1, y, mult*width/winBaseCount + 1 , height, color);
+	    }
+	}
+    }
+else if (length)	 /* broken frame, just show nucs */
+    {
+    if (strand == '-')
+	{
+	if (!alreadyComplemented)
+	    complement(ptr, length);
+	}
+    else
+	{
+	if (alreadyComplemented)
+	    complement(ptr, length);
+	}
+    }
+
+if (strand == '-')
+    reverseBytes(dna, size);
+}
+
+static int wigMafDrawBases(struct track *track, int seqStart, int seqEnd,
+        struct hvGfx *hvg, int xOff, int yOff, int width,
+        MgFont *font, Color color, enum trackVisibility vis,
+	struct wigMafItem *miList)
+/* Draw base-by-base view, return new Y offset. */
+{
+struct wigMafItem *mi;
+struct mafAli *mafList, *maf, *sub;
+struct mafComp *mc, *mcMaster;
+int lineCount = slCount(miList);
+char **lines = NULL, *selfLine, *insertLine;
+int *insertCounts;
+int i, x = xOff, y = yOff;
+struct dnaSeq *seq = NULL;
+struct hash *miHash = newHash(9);
+struct hash *srcHash = newHash(0);
+char dbChrom[64];
+char buf[1024];
+char option[64];
+int alignLineLength = winBaseCount * 2;
+        /* doubled to allow space for insert counts */
+boolean complementBases = cartUsualBooleanDb(cart, database, COMPLEMENT_BASES_VAR, FALSE);
+bool dots = FALSE;         /* configuration option */
+/* this line must be longer than the longest base-level display */
+char noAlignment[2000];
+boolean useIrowChains = TRUE;
+int offset;
+char *framesTable = NULL;
+char *defaultCodonSpecies = cartUsualString(cart, SPECIES_CODON_DEFAULT, NULL);
+char *codonTransMode = NULL;
+boolean startSub2 = FALSE;
+
+int mafOrig = 0;
+int mafOrigOffset = 0;
+char query[256];
+struct mafPriv *mp = getMafPriv(track);
+char *mafFile = NULL;
+struct sqlConnection *conn2 = NULL;
+struct sqlConnection *conn3 = NULL;
+char *tableName = NULL;
+
+if (mp->ct != NULL)
+    {
+    conn2 = hAllocConn(CUSTOM_TRASH);
+    conn3 = hAllocConn(CUSTOM_TRASH);
+    tableName = mp->ct->dbTableName;
+    mafFile = getCustomMafFile(track);
+    }
+else
+    {
+    conn2 = hAllocConn(database);
+    conn3 = hAllocConn(database);
+    tableName = track->table;
+    mafFile = getTrackMafFile(track);  // optional
+    }
+
+if (hIsGsidServer())
+    {
+    /* decide the value of mafOrigOffset to be used to display xxAaMaf tracks. */
+    struct sqlConnection *conn = hAllocConn(database);
+    safef(query, sizeof(query), "select chromStart from %s", track->table);
+    mafOrig = atoi(sqlNeedQuickString(conn, query));
+    mafOrigOffset = (mafOrig % 3) - 1;
+    /* offset has to be non-negative */
+    if (mafOrigOffset < 0) mafOrigOffset = mafOrigOffset +3;
+
+    hFreeConn(&conn);
+    }
+
+if (defaultCodonSpecies == NULL)
+    defaultCodonSpecies = trackDbSetting(track->tdb, "speciesCodonDefault");
+
+if (defaultCodonSpecies == NULL)
+    defaultCodonSpecies = database;
+
+if (seqStart > 2)
+    {
+    startSub2 = TRUE;
+    seqStart -=2;
+    }
+seqEnd +=2;
+if (seqEnd > seqBaseCount)
+    seqEnd = seqBaseCount;
+
+char *cfgPrefix = compositeViewControlNameFromTdb(track->tdb);
+
+safef(option, sizeof(option), "%s.%s", cfgPrefix, MAF_DOT_VAR);
+if (cartVarExists(cart, option))
+    {
+    dots = cartCgiUsualBoolean(cart, option, FALSE);
+    }
+else
+    {
+    char *dotString = trackDbSetting(track->tdb, MAF_DOT_VAR);
+    if (dotString && sameString(dotString, "on"))
+	{
+	dots = TRUE;
+	cartSetBoolean(cart, option, TRUE);
+	}
+    }
+
+safef(buf, sizeof(buf), "%s.frames",/*cfgPrefix*/track->track);
+if (cartVarExists(cart, buf))
+    framesTable = cartUsualString(cart, buf, NULL);
+else
+    framesTable = trackDbSetting(track->tdb, "frames");
+
+if (framesTable)
+    {
+    safef(buf, sizeof(buf), "%s.codons",cfgPrefix);
+    codonTransMode = cartUsualString(cart, buf, "codonDefault");
+    if (sameString("codonNone", codonTransMode))
+	framesTable = NULL;
+    }
+
+boolean newTableType = FALSE;
+
+if (framesTable != NULL)
+    newTableType = hHasField(database, framesTable, "isExonStart");
+
+/* initialize "no alignment" string to o's */
+for (i = 0; i < sizeof noAlignment - 1; i++)
+    noAlignment[i] = UNALIGNED_SEQ;
+
+
+safef(option, sizeof(option), "%s.%s", cfgPrefix, MAF_CHAIN_VAR);
+if (cartVarExists(cart, option))
+    useIrowChains = cartCgiUsualBoolean(cart, option, TRUE);
+else
+    {
+    char *irowString = trackDbSetting(track->tdb, "irows");
+    if (irowString && sameString(irowString, "off"))
+	useIrowChains = FALSE;
+    cartSetBoolean(cart, option, useIrowChains);
+    }
+
+/* Allocate a line of characters for each item. */
+AllocArray(lines, lineCount);
+lines[0] = needMem(alignLineLength);
+for (i=1; i<lineCount; ++i)
+    {
+    lines[i] = needMem(alignLineLength);
+    memset(lines[i], ' ', alignLineLength - 1);
+    }
+
+/* Give nice names to first two. */
+insertLine = lines[0];
+selfLine = lines[1];
+
+/* Allocate a line for recording gap sizes in reference */
+AllocArray(insertCounts, alignLineLength);
+
+/* Load up self-line with DNA */
+seq = hChromSeqMixed(database, chromName, seqStart , seqEnd);
+memcpy(selfLine, seq->dna, winBaseCount + 4);
+//toUpperN(selfLine, winBaseCount);
+freeDnaSeq(&seq);
+
+/* Make hash of species items keyed by database. */
+i = 0;
+for (mi = miList; mi != NULL; mi = mi->next)
+    {
+    mi->ix = i++;
+    if (mi->db != NULL)
+	hashAdd(miHash, mi->db, mi);
+    }
+
+/* Go through the mafs saving relevant info in lines. */
+mafList = mp->list;
+safef(dbChrom, sizeof(dbChrom), "%s.%s", database, chromName);
+
+for (maf = mafList; maf != NULL; maf = maf->next)
+    {
+    int mafStart;
+    /* get info about sequences from full alignment,
+       for use later, when determining if sequence is unaligned or missing */
+    for (mc = maf->components; mc != NULL; mc = mc->next)
+        if (!hashFindVal(srcHash, mc->src))
+            hashAdd(srcHash, mc->src, maf);
+
+    mcMaster = mafFindComponent(maf, dbChrom);
+    mafStart = mcMaster->start;
+    /* get portion of maf in this window */
+    if (startSub2)
+	sub = mafSubset(maf, dbChrom, winStart - 2, winEnd + 2);
+    else
+	sub = mafSubset(maf, dbChrom, winStart , winEnd + 2);
+    if (sub != NULL)
+        {
+	int subStart,subEnd;
+	int lineOffset, subSize;
+	int startInserts = 0;
+	char *ptr;
+
+        /* process alignment for reference ("master") species */
+	for(ptr = mcMaster->text; *ptr == '-'; ptr++)
+	    startInserts++;
+
+	mcMaster = mafFindComponent(sub, dbChrom);
+	if (mcMaster->strand == '-')
+	    mafFlipStrand(sub);
+	subStart = mcMaster->start;
+	subEnd = subStart + mcMaster->size;
+	subSize = subEnd - subStart;
+	lineOffset = subStart - seqStart;
+        processInserts(mcMaster->text, sub, miHash,
+                                &insertCounts[lineOffset], subSize);
+	insertCounts[lineOffset] = max(insertCounts[lineOffset],startInserts);
+
+        /* fill in bases for each species */
+        for (mi = miList; mi != NULL; mi = mi->next)
+            {
+            char *seq;
+            bool needToFree = FALSE;
+            int size = sub->textSize;
+            if (mi->ix == 1)
+                /* reference */
+                continue;
+            if (mi->db == NULL)
+                /* not a species line -- it's the gaps line, or... */
+                continue;
+            if ((mc = mafMayFindCompSpecies(sub, mi->db, '.')) == NULL)
+                continue;
+	    if (mafStart == subStart)
+		{
+		if (mc->size && mc->leftStatus == MAF_INSERT_STATUS && (*mc->text != '-') &&
+		 !((lineOffset) && (((lines[mi->ix][lineOffset-1]) == '=') || (lines[mi->ix][lineOffset-1]) == '-')))
+		    {
+		    insertCounts[lineOffset] = max(insertCounts[lineOffset],mc->leftLen);
+		    mi->inserts[mi->insertsSize] =  (subStart - seqStart)+ 1;
+		    mi->insertsSize++;
+		    }
+		}
+	    if (startInserts)
+		{
+		struct mafComp *mc1;
+		if (((mc1 = mafMayFindCompSpecies(maf, mi->db, '.')) != NULL) &&
+		    ((mc1->text) && (countNonDash(mc1->text, startInserts) > 0)))
+			{
+			mi->inserts[mi->insertsSize] =  (subStart - seqStart)+ 1;
+			mi->insertsSize++;
+			}
+		}
+            seq = mc->text;
+            if ( mc->text == NULL )
+                {
+                /* if no alignment here, but MAF annotation indicates continuity
+                 * of flanking alignments, fill with dashes or ='s */
+               if (!useIrowChains)
+                   continue;
+                if (isContigOrTandem(mc->leftStatus) &&
+                    isContigOrTandem(mc->rightStatus))
+                    {
+                    char fill = '-';
+                    seq = needMem(size+1);
+                    needToFree = TRUE;
+                    memset(seq, fill, size);
+                    }
+		else if (mc->leftStatus == MAF_INSERT_STATUS && mc->rightStatus == MAF_INSERT_STATUS)
+		    {
+		    char fill = MAF_DOUBLE_GAP;
+		    seq = needMem(size+1);
+		    needToFree = TRUE;
+		    memset(seq, fill, size);
+		    }
+		else if (mc->leftStatus == MAF_MISSING_STATUS && mc->rightStatus == MAF_MISSING_STATUS)
+		    {
+                    char fill = 'N';
+                    seq = needMem(size+1);
+                    needToFree = TRUE;
+                    memset(seq, fill, size);
+		    }
+                else
+                    continue;
+                }
+
+            if (((mc->leftStatus == MAF_NEW_STATUS ||
+                mc->rightStatus == MAF_NEW_STATUS )
+            || (mc->leftStatus == MAF_NEW_NESTED_STATUS ||
+                mc->rightStatus == MAF_NEW_NESTED_STATUS )))
+                {
+                int i;
+                char *p;
+                seq = needMem(size+1);
+                needToFree = TRUE;
+                for (p = seq, i = 0; i < size; p++, i++)
+                    *p = ' ';
+                p = seq;
+                if (mc->text != NULL)
+                    strcpy(p, mc->text);
+                if (mc->leftStatus == MAF_NEW_STATUS)
+                    {
+		    char *m = mcMaster->text;
+		    if (mafStart == subStart)
+			mi->seqEnds[mi->seqEndsSize] = (subStart - seqStart) + 1;
+		    while(*p == '-')
+			{
+			if ((*m++ != '-') && (mafStart == subStart))
+			    mi->seqEnds[mi->seqEndsSize]++;
+			*p++ = ' ';
+			}
+
+		    if (mafStart == subStart)
+			mi->seqEndsSize++;
+                    }
+                if (mc->leftStatus == MAF_NEW_NESTED_STATUS)
+		    {
+		    char *m = mcMaster->text;
+		    if (mafStart == subStart)
+			mi->brackStarts[mi->brackStartsSize] =  (subStart - seqStart)+ 1;
+		    while(*p == '-')
+			{
+			*p++ = '=';
+			if ((*m++ != '-') && (mafStart == subStart))
+			    mi->brackStarts[mi->brackStartsSize]++;
+			}
+		    if (mafStart == subStart)
+			mi->brackStartsSize++;
+		    }
+                if (mc->rightStatus == MAF_NEW_NESTED_STATUS)
+		    {
+		    char *p = seq + size - 1;
+		    char *m = mcMaster->text + size - 1;
+		    if (subEnd <= seqEnd)
+			mi->brackEnds[mi->brackEndsSize] = (subStart - seqStart)+ subSize + 1;
+		    while(*p == '-')
+			{
+			if ((*m-- != '-') && (subEnd <= seqEnd))
+			    mi->brackEnds[mi->brackEndsSize]--;
+			*p-- = '=';
+			}
+		    if (subEnd <= seqEnd)
+		    	mi->brackEndsSize++;
+		    }
+                if (mc->rightStatus == MAF_NEW_STATUS)
+		    {
+		    char *p = seq + size - 1;
+		    char *m = mcMaster->text + size - 1;
+
+		    if (mc->size && ((subEnd <= seqEnd)))
+			mi->seqEnds[mi->seqEndsSize] = (subStart - seqStart)+ subSize + 1;
+		    while(*p == '-')
+			{
+			if ((*m-- != '-') && (mc->size && (subEnd <= seqEnd)))
+			    mi->seqEnds[mi->seqEndsSize]--;
+			*p-- = ' ';
+			}
+		    if (mc->size && ((subEnd <= seqEnd)))
+		    	mi->seqEndsSize++;
+		    }
+		}
+            if (mc->text && ((mc->leftStatus == MAF_MISSING_STATUS)))
+		{
+                char *p = seq;
+		while(*p == '-')
+		    *p++ = 'N';
+		}
+            if (mc->text && ((mc->leftStatus == MAF_INSERT_STATUS)))
+		{
+                char *p = seq;
+		while(*p == '-')
+		    *p++ = '=';
+		}
+            if (mc->text && ((mc->rightStatus == MAF_MISSING_STATUS)))
+		{
+                char *p = seq + size - 1;
+		while(*p == '-')
+		    *p-- = 'N';
+		}
+            if (mc->text && ((mc->rightStatus == MAF_INSERT_STATUS)))
+		{
+		char *m = mcMaster->text + size - 1;
+                char *p = seq + size - 1;
+		while((*p == '-') || (*m == '-'))
+		    {
+		    *p-- = '=';
+		    m--;
+		    }
+		}
+
+            mi->insertsSize = processSeq(seq, mcMaster->text, size, lines[mi->ix], lineOffset, subSize,
+	    	mi->inserts, mi->insertsSize);
+            if (needToFree)
+                freeMem(seq);
+	    }
+	}
+    mafAliFree(&sub);
+    }
+/* draw inserts line */
+mi = miList;
+
+for(offset=startSub2*2; (offset < alignLineLength) && (offset < winBaseCount + startSub2 * 2); offset++)
+    {
+    int  x1, x2;
+
+    x1 = (offset - startSub2 * 2) * width/winBaseCount;
+    x2 = ((offset - startSub2 * 2)+1) * width/winBaseCount - 1;
+    if (insertCounts[offset] != 0)
+	{
+	struct dyString *label = newDyString(20);
+	int haveRoomFor = (width/winBaseCount)/tl.mWidth;
+
+	/* calculate number of AAs instead of bases if it is wigMafProt */
+	if (strstr(track->tdb->type, "wigMafProt"))
+	    {
+	    dyStringPrintf(label, "%d",insertCounts[offset]/3);
+	    }
+	else
+	    {
+	    dyStringPrintf(label, "%d",insertCounts[offset]);
+	    }
+
+	if (label->stringSize > haveRoomFor)
+	    {
+	    dyStringClear(label);
+	    dyStringPrintf(label, "%c",(insertCounts[offset] % 3) == 0 ? '*' : '+');
+	    }
+	hvGfxTextCentered(hvg, x1+x - (width/winBaseCount)/2, y, x2-x1, mi->height,
+		getOrangeColor(), font, label->string);
+	dyStringFree(&label);
+	}
+    }
+y += mi->height;
+
+/* draw alternating colors behind base-level alignments */
+    {
+    int alternateColorBaseCount, alternateColorBaseOffset;
+    safef(buf, sizeof(buf), "%s.%s", cfgPrefix, BASE_COLORS_VAR);
+    alternateColorBaseCount = cartCgiUsualInt(cart, buf, 0);
+    safef(buf, sizeof(buf), "%s.%s", cfgPrefix, BASE_COLORS_OFFSET_VAR);
+    alternateColorBaseOffset = cartCgiUsualInt(cart, buf, 0);
+    if (alternateColorBaseCount != 0)
+        {
+        int baseWidth = spreadStringCharWidth(width, winBaseCount);
+        int colorX = x + alternateColorBaseOffset * baseWidth;
+        alternateBlocksBehindChars(hvg, colorX, y-1, width,
+                mi->height*(lineCount-1), tl.mWidth, winBaseCount,
+                alternateColorBaseCount, shadesOfSea[0], MG_WHITE);
+        }
+    }
+compositeViewControlNameFree(&cfgPrefix);
+
+/* draw base-level alignments */
+for (mi = miList->next, i=1; mi != NULL && mi->db != NULL; mi = mi->next, i++)
+    {
+    char *line;
+
+    line  = lines[i];
+    /* TODO: leave lower case in to indicate masking ?
+       * NOTE: want to make sure that all sequences are soft-masked
+       * if we do this */
+    /* HAVE DONE:  David doesn't like lower case by default
+     * TODO: casing based on quality values ?? */
+    alignSeqToUpperN(line);
+    if (complementBases)
+        {
+	complement(line, strlen(line));
+        }
+    /* draw sequence letters for alignment */
+    hvGfxSetClip(hvg, x, y-1, width, mi->height);
+
+    if (framesTable != NULL)
+	{
+	int rowOffset;
+	char **row;
+	struct sqlConnection *conn = hAllocConn(database);
+	struct sqlResult *sr;
+	char extra[512];
+	boolean found = FALSE;
+
+	if (sameString("codonDefault", codonTransMode))
+	    {
+	    safef(extra, sizeof(extra), "src='%s'",defaultCodonSpecies);
+
+	    found = TRUE;
+	    }
+	else if (sameString("codonFrameDef", codonTransMode))
+	    {
+	    safef(extra, sizeof(extra), "src='%s'",mi->db);
+
+	    found = FALSE;
+	    }
+	else if (sameString("codonFrameNone", codonTransMode))
+	    {
+	    safef(extra, sizeof(extra), "src='%s'",mi->db);
+
+	    found = TRUE;
+	    }
+	else
+	    errAbort("unknown codon translation mode %s",codonTransMode);
+tryagain:
+	sr = hRangeQuery(conn, framesTable, chromName, seqStart, seqEnd, extra, &rowOffset);
+	while ((row = sqlNextRow(sr)) != NULL)
+	    {
+	    struct mafFrames mf;
+	    int start, end, w;
+	    int frame;
+
+	    found = TRUE;
+	    if (newTableType)
+		mafFramesStaticLoad(row + rowOffset, &mf);
+	    else
+		mafFramesStaticLoadOld(row + rowOffset, &mf);
+
+	    if (mf.chromStart < seqStart)
+		start = 0;
+	    else
+		start = mf.chromStart-seqStart;
+	    frame = mf.frame;
+	    if (mf.strand[0] == '-')
+		{
+		if (mf.chromEnd > seqEnd)
+		    frame = (frame + mf.chromEnd-seqEnd  ) % 3;
+		}
+	    else
+		{
+		if (mf.chromStart < seqStart)
+		    frame = (frame + seqStart-mf.chromStart  ) % 3;
+		}
+
+	    end = mf.chromEnd > seqEnd ? seqEnd - seqStart  : mf.chromEnd - seqStart;
+	    w= end - start;
+
+	    translateCodons(conn2, conn3, tableName, mi->db, line, start ,
+		w, frame, mf.strand[0],mf.prevFramePos,mf.nextFramePos,
+		complementBases, x, y, width, mi->height,  hvg, mafFile);
+
+	    }
+	sqlFreeResult(&sr);
+
+	if (!found)
+	    {
+	    /* try the default species */
+	    safef(extra, sizeof(extra), "src='%s'",defaultCodonSpecies);
+
+	    found = TRUE; /* don't try again */
+	    goto tryagain;
+	    }
+
+	hFreeConn(&conn);
+	}
+
+    if (startSub2)
+	{
+        if (strstr(track->tdb->type, "wigMafProt"))
+            {
+            spreadAlignStringProt(hvg, x, y, width, mi->height-1, color,
+                        font, &line[2], &selfLine[2], winBaseCount, dots, FALSE, seqStart, mafOrigOffset);
+            }
+	else
+	    {
+	    /* make sure we have bases to display before printing them */
+	    if (strlen(line) > 2)
+		spreadAlignString(hvg, x, y, width, mi->height-1, color,
+		    font, &line[2], &selfLine[2], winBaseCount, dots, FALSE);
+	    }
+	}
+    else
+	spreadAlignString(hvg, x, y, width, mi->height-1, color,
+                        font, line, selfLine, winBaseCount, dots, FALSE);
+    for(offset = 0; offset < mi->seqEndsSize; offset++)
+	{
+	int x1;
+
+	x1 = x + (mi->seqEnds[offset] -1 - startSub2 * 2) * width/winBaseCount;
+	hvGfxBox(hvg, x1, y-1, 1, mi->height-1, getChromBreakBlueColor());
+	}
+    for(offset = 0; offset < mi->insertsSize; offset++)
+	{
+	int x1;
+
+	x1 = x + (mi->inserts[offset] -1 - startSub2 * 2) * width/winBaseCount;
+	hvGfxBox(hvg, x1, y-1, 1, mi->height-1, getOrangeColor());
+	}
+    for(offset = 0; offset < mi->brackStartsSize; offset++)
+	{
+	int x1;
+
+	x1 = x + (mi->brackStarts[offset] -1- startSub2 * 2) * width/winBaseCount;
+	hvGfxBox(hvg, x1, y-1, 2, 1, getChromBreakGreenColor());
+	hvGfxBox(hvg, x1, y-1, 1, mi->height-1, getChromBreakGreenColor());
+	hvGfxBox(hvg, x1, y + mi->height-3, 2, 1, getChromBreakGreenColor());
+	}
+    for(offset = 0; offset < mi->brackEndsSize; offset++)
+	{
+	int x1;
+
+	x1 = x + (mi->brackEnds[offset] -1- startSub2 * 2) * width/winBaseCount;
+	hvGfxBox(hvg, x1-1, y-1, 2, 1, getChromBreakGreenColor());
+	hvGfxBox(hvg, x1, y-1, 1, mi->height-1, getChromBreakGreenColor());
+	hvGfxBox(hvg, x1-1, y + mi->height-3, 2, 1, getChromBreakGreenColor());
+	}
+
+    hvGfxUnclip(hvg);
+    y += mi->height;
+    }
+
+/* Clean up */
+/*
+for (i=0; i<lineCount-1; ++i)
+    freeMem(lines[i]);
+freez(&lines);
+*/
+hFreeConn(&conn2);
+hFreeConn(&conn3);
+hashFree(&miHash);
+return y;
+}
+
+static int wigMafDrawScoreGraph(struct track *track, int seqStart, int seqEnd,
+        struct hvGfx *hvg, int xOff, int yOff, int width,
+        MgFont *font, Color color, enum trackVisibility vis)
+{
+/* Draw routine for score graph, returns new Y offset */
+struct track *wigTrack = track->subtracks;
+enum trackVisibility scoreVis;
+
+scoreVis = (vis == tvDense ? tvDense : tvFull);
+
+if (wigTrack == NULL)
+    {
+    /* no wiggle */
+    int height = tl.fontHeight * 4;
+    if (vis == tvFull || vis == tvPack)
+        /* suppress graph if other items displayed (bases or pairs) */
+        return yOff;
+    else if (vis == tvDense)
+        height = track->height; // Evidence that track-height comes in as 9 but should be 10!
+    /* draw some kind of graph from multiple alignment */
+    struct mafPriv *mp = getMafPriv(track);
+    if (mp->list != (char *)-1 && mp->list != NULL)
+        {
+        /* use mafs */
+        drawMafRegionDetails(mp->list, height, seqStart, seqEnd,
+                                hvg, xOff, yOff, width, font,
+                                color, color, scoreVis, FALSE, FALSE);
+        }
+    else if (mp->ct != NULL)
+        {
+        /* use or scored refs from maf table*/
+        drawScoreOverviewCT(mp->ct->dbTableName, height, seqStart, seqEnd,
+		hvg, xOff, yOff, width, font, color, color, scoreVis);
+        yOff++;
+        }
+    else
+        {
+        /* use or scored refs from maf table*/
+        drawScoreOverview(track->table, height, seqStart, seqEnd, hvg,
+                            xOff, yOff, width, font, color, color, scoreVis);
+        yOff++;
+        }
+    yOff += height;
+    }
+else
+    {
+    Color wigColor = 0;
+    while (wigTrack != NULL)
+        {
+        /* draw conservation wiggles */
+        if (!wigColor)
+            wigColor = hvGfxFindRgb(hvg, &wigTrack->color);
+        else
+            wigColor = slightlyLighterColor(hvg, wigColor);
+        wigTrack->ixColor = wigColor;
+        wigTrack->ixAltColor = hvGfxFindRgb(hvg, &wigTrack->altColor);
+        hvGfxSetClip(hvg, xOff, yOff, width, wigTotalHeight(wigTrack, scoreVis) - 1);
+        wigTrack->drawItems(wigTrack, seqStart, seqEnd, hvg, xOff, yOff,
+                             width, font, color, scoreVis);
+        hvGfxUnclip(hvg);
+        yOff += wigTotalHeight(wigTrack, scoreVis);
+        wigTrack = wigTrack->next;
+        }
+    }
+return yOff;
+}
+
+
+static void wigMafDraw(struct track *track, int seqStart, int seqEnd,
+        struct hvGfx *hvg, int xOff, int yOff, int width,
+        MgFont *font, Color color, enum trackVisibility vis)
+/* Draw routine for wigmaf type tracks */
+{
+int y = yOff;
+y = wigMafDrawScoreGraph(track, seqStart, seqEnd, hvg, xOff, y, width,
+                                font, color, vis);
+if (vis == tvFull || vis == tvPack)
+    {
+    if (zoomedToBaseLevel)
+	{
+	struct wigMafItem *wiList = track->items;
+        /* skip over cons wiggles */
+        struct track *wigTrack = track->subtracks;
+        while (wigTrack)
+            {
+            wiList = wiList->next;
+            wigTrack = wigTrack->next;
+            }
+	y = wigMafDrawBases(track, seqStart, seqEnd, hvg, xOff, y, width, font,
+				    color, vis, wiList);
+				    //MG_RED, vis, wiList);
+	}
+    else
+	wigMafDrawPairwise(track, seqStart, seqEnd, hvg, xOff, y,
+				width, font, color, vis);
+    }
+mapBoxHc(hvg, seqStart, seqEnd, xOff, yOff, width, track->height, track->track,
+            track->track, NULL);
+}
+
+void wigMafMethods(struct track *track, struct trackDb *tdb,
+                                        int wordCount, char *words[])
+/* Make track for maf multiple alignment. */
+{
+struct track *wigTrack;
+int i;
+struct dyString *wigType;
+struct consWiggle *consWig, *consWigList = NULL;
+
+track->loadItems = wigMafLoad;
+track->freeItems = wigMafFree;
+track->drawItems = wigMafDraw;
+track->itemName = wigMafItemName;
+track->mapItemName = wigMafItemName;
+track->totalHeight = wigMafTotalHeight;
+track->itemHeight = wigMafItemHeight;
+track->itemStart = tgItemNoStart;
+track->itemEnd = tgItemNoEnd;
+track->itemLabelColor = wigMafItemLabelColor;
+track->mapsSelf = TRUE;
+//track->canPack = TRUE;
+
+/* deal with conservation wiggle(s) */
+consWigList = wigMafWiggles(database, tdb);
+if (consWigList == NULL)
+    return;
+
+/* determine which conservation wiggles to use -- from cart,
+ or if none there, use first entry in trackDb setting */
+boolean first = TRUE;
+for (consWig = consWigList; consWig != NULL; consWig = consWig->next)
+    {
+    if (differentString(consWig->leftLabel, DEFAULT_CONS_LABEL))
+        {
+        char *wigVar = wigMafWiggleVar(tdb, consWig);
+        if (!cartCgiUsualBoolean(cart, wigVar, first))
+            continue;
+        }
+    first = FALSE;
+
+    //  Manufacture and initialize wiggle subtrack, both tdb and track
+    struct trackDb *wigTdb = CloneVar(tdb);
+    wigType = newDyString(64);
+    dyStringPrintf(wigType, "type wig ");
+    for (i = 1; i < wordCount; i++)
+        dyStringPrintf(wigType, "%s ", words[i]);
+    wigTdb->type = cloneString(wigType->string);
+    wigTdb->track = consWig->table;
+    wigTdb->table= consWig->table;
+
+    /* Tweak wiggle left labels: replace underscore with space and
+     * append 'Cons' */
+    struct dyString *ds = dyStringNew(0);
+    dyStringAppend(ds, consWig->leftLabel);
+    if (differentString(consWig->leftLabel, DEFAULT_CONS_LABEL))
+        dyStringAppend(ds, " Cons");
+    wigTdb->shortLabel = dyStringCannibalize(&ds);
+    subChar(wigTdb->shortLabel, '_', ' ');
+
+    wigTrack = trackFromTrackDb(wigTdb);
+
+
+    /* setup wiggle methods in subtrack */
+    wigMethods(wigTrack, tdb, wordCount, words);
+
+    wigTrack->mapsSelf = FALSE;
+    wigTrack->drawLeftLabels = NULL;
+    wigTrack->next = NULL;
+    slAddTail(&track->subtracks, wigTrack);
+    dyStringFree(&wigType);
+    }
+}
+
+