8a0946dd6870f10cde056ba243f1fb4ec1fd16b4
angie
  Thu Feb 27 11:58:33 2014 -0800
Adding support for plain VCF custom tracks (as opposed to VCF+tabix),since users seem to want to upload VCF, and as long as the file is
not too big it will work OK.  This means adding a new track type
vcf (as opposed to vcfTabix) and supporting it in hgTracks, hgTrackUi,
hgc, hgTables and hgVai.  (and others I've forgotten?)
refs #12416

diff --git src/hg/hgTracks/vcfTrack.c src/hg/hgTracks/vcfTrack.c
index 15f50ad..dd9d086 100644
--- src/hg/hgTracks/vcfTrack.c
+++ src/hg/hgTracks/vcfTrack.c
@@ -1,35 +1,29 @@
 /* vcfTrack -- handlers for Variant Call Format data. */
 
 #include "common.h"
 #include "bigWarn.h"
 #include "dystring.h"
 #include "errCatch.h"
 #include "hacTree.h"
 #include "hdb.h"
 #include "hgColors.h"
 #include "hgTracks.h"
 #include "pgSnp.h"
 #include "trashDir.h"
 #include "vcf.h"
 #include "vcfUi.h"
-#if (defined USE_TABIX && defined KNETFILE_HOOKS)
-#include "knetUdc.h"
-#include "udc.h"
-#endif//def USE_TABIX && KNETFILE_HOOKS
-
-#ifdef USE_TABIX
 
 static boolean getMinQual(struct trackDb *tdb, double *retMinQual)
 /* Return TRUE and set retMinQual if cart contains minimum QUAL filter */
 {
 if (cartUsualBooleanClosestToHome(cart, tdb, FALSE,
 				  VCF_APPLY_MIN_QUAL_VAR, VCF_DEFAULT_APPLY_MIN_QUAL))
     {
     if (retMinQual != NULL)
 	*retMinQual = cartUsualDoubleClosestToHome(cart, tdb, FALSE, VCF_MIN_QUAL_VAR,
 						   VCF_DEFAULT_MIN_QUAL);
     return TRUE;
     }
 return FALSE;
 }
 
@@ -1109,30 +1103,47 @@
  * this to overwrite the methods for the rest of execution: */
 {
 tg->heightPer = (tg->visibility == tvSquish) ? (tl.fontHeight/4) : (tl.fontHeight / 2);
 tg->lineHeight = tg->heightPer + 1;
 tg->drawItems = vcfHapClusterDraw;
 tg->totalHeight = vcfHapClusterTotalHeight;
 tg->itemHeight = tgFixedItemHeight;
 tg->itemName = vcfHapClusterTrackName;
 tg->mapItemName = vcfHapClusterTrackName;
 tg->itemStart = tgItemNoStart;
 tg->itemEnd = tgItemNoEnd;
 tg->mapsSelf = TRUE;
 tg->extraUiData = vcff;
 }
 
+static void indelTweakMapItem(struct track *tg, struct hvGfx *hvg, void *item,
+        char *itemName, char *mapItemName, int start, int end, int x, int y, int width, int height)
+/* Pass the original vcf chromStart to pgSnpMapItem, so if we have trimmed an identical
+ * first base from item's alleles and start, we will still pass the correct start to hgc. */
+{
+struct pgSnpVcfStart *psvs = item;
+pgSnpMapItem(tg, hvg, item, itemName, mapItemName, psvs->vcfStart, end, x, y, width, height);
+}
+
+
+#ifdef USE_TABIX
+
+#ifdef KNETFILE_HOOKS
+#include "knetUdc.h"
+#include "udc.h"
+#endif//def KNETFILE_HOOKS
+
 static void vcfTabixLoadItems(struct track *tg)
 /* Load items in window from VCF file using its tabix index file. */
 {
 char *fileOrUrl = NULL;
 /* Figure out url or file name. */
 if (tg->parallelLoading)
     {
     /* do not use mysql during parallel-fetch load */
     fileOrUrl = trackDbSetting(tg->tdb, "bigDataUrl");
     }
 else
     {
     struct sqlConnection *conn = hAllocConnTrack(database, tg->tdb);
     fileOrUrl = bbiNameFromSettingOrTableChrom(tg->tdb, conn, tg->table, chromName);
     hFreeConn(&conn);
@@ -1162,39 +1173,30 @@
 	    }
 	// Don't vcfFileFree here -- we are using its string pointers!
 	}
     }
 errCatchEnd(errCatch);
 if (errCatch->gotError || vcff == NULL)
     {
     if (isNotEmpty(errCatch->message->string))
 	tg->networkErrMsg = cloneString(errCatch->message->string);
     tg->drawItems = bigDrawWarning;
     tg->totalHeight = bigWarnTotalHeight;
     }
 errCatchFree(&errCatch);
 }
 
-static void indelTweakMapItem(struct track *tg, struct hvGfx *hvg, void *item,
-        char *itemName, char *mapItemName, int start, int end, int x, int y, int width, int height)
-/* Pass the original vcf chromStart to pgSnpMapItem, so if we have trimmed an identical
- * first base from item's alleles and start, we will still pass the correct start to hgc. */
-{
-struct pgSnpVcfStart *psvs = item;
-pgSnpMapItem(tg, hvg, item, itemName, mapItemName, psvs->vcfStart, end, x, y, width, height);
-}
-
 void vcfTabixMethods(struct track *track)
 /* Methods for VCF + tabix files. */
 {
 #ifdef KNETFILE_HOOKS
 knetUdcInstall();
 #endif
 pgSnpMethods(track);
 track->mapItem = indelTweakMapItem;
 // Disinherit next/prev flag and methods since we don't support next/prev:
 track->nextExonButtonable = FALSE;
 track->nextPrevExon = NULL;
 track->nextPrevItem = NULL;
 track->loadItems = vcfTabixLoadItems;
 track->canPack = TRUE;
 }
@@ -1214,15 +1216,78 @@
       "Get tabix from samtools.sourceforge.net and recompile kent/src with USE_TABIX=1");
 Color yellow = hvGfxFindRgb(hvg, &undefinedYellowColor);
 hvGfxBox(hvg, xOff, yOff, width, tg->heightPer, yellow);
 hvGfxTextCentered(hvg, xOff, yOff, width, tg->heightPer, MG_BLACK, font, message);
 }
 
 void vcfTabixMethods(struct track *track)
 /* Methods for VCF alignment files, in absence of tabix lib. */
 {
 // NOP warning method to warn users that tabix is not installed.
 messageLineMethods(track);
 track->drawItems = drawUseVcfTabixWarning;
 }
 
 #endif // no USE_TABIX
+
+static void vcfLoadItems(struct track *tg)
+/* Load items in window from VCF file. */
+{
+int vcfMaxErr = -1;
+struct vcfFile *vcff = NULL;
+boolean hapClustEnabled = cartUsualBooleanClosestToHome(cart, tg->tdb, FALSE,
+							VCF_HAP_ENABLED_VAR, TRUE);
+char *table = tg->table;
+struct customTrack *ct = tg->customPt;
+struct sqlConnection *conn;
+if (ct == NULL)
+    conn = hAllocConnTrack(database, tg->tdb);
+else
+    {
+    conn = hAllocConn(CUSTOM_TRASH);
+    table = ct->dbTableName;
+    }
+char *vcfFile = bbiNameFromSettingOrTable(tg->tdb, conn, table);
+hFreeConn(&conn);
+/* protect against parse error */
+struct errCatch *errCatch = errCatchNew();
+if (errCatchStart(errCatch))
+    {
+    vcff = vcfFileMayOpen(vcfFile, chromName, winStart, winEnd, vcfMaxErr, -1, TRUE);
+    if (vcff != NULL)
+	{
+	filterRecords(vcff, tg->tdb);
+	if (hapClustEnabled && vcff->genotypeCount > 1 && vcff->genotypeCount < 3000 &&
+	    (tg->visibility == tvPack || tg->visibility == tvSquish))
+	    vcfHapClusterOverloadMethods(tg, vcff);
+	else
+	    {
+	    tg->items = vcfFileToPgSnp(vcff, tg->tdb);
+	    // pgSnp bases coloring/display decision on count of items:
+	    tg->customInt = slCount(tg->items);
+	    }
+	// Don't vcfFileFree here -- we are using its string pointers!
+	}
+    }
+errCatchEnd(errCatch);
+if (errCatch->gotError || vcff == NULL)
+    {
+    if (isNotEmpty(errCatch->message->string))
+	tg->networkErrMsg = cloneString(errCatch->message->string);
+    tg->drawItems = bigDrawWarning;
+    tg->totalHeight = bigWarnTotalHeight;
+    }
+errCatchFree(&errCatch);
+}
+
+void vcfMethods(struct track *track)
+/* Methods for Variant Call Format. */
+{
+pgSnpMethods(track);
+track->mapItem = indelTweakMapItem;
+// Disinherit next/prev flag and methods since we don't support next/prev:
+track->nextExonButtonable = FALSE;
+track->nextPrevExon = NULL;
+track->nextPrevItem = NULL;
+track->loadItems = vcfLoadItems;
+track->canPack = TRUE;
+}