de29d745d32fb04a5187fb5998cc94bbb9bf41a4
angie
  Wed Aug 9 13:39:59 2017 -0700
Add optional HGVS output to annoGratorGpVar and hgVai. Since annoGratorGpVar is genePred-based, it can't yet take advantage of variantProjector's full PSL+CDS+sequence support, so when transcripts don't align cleanly to genome, HGVS c./n./p. output may be incorrect. refs #19968

diff --git src/hg/hgVai/hgVai.c src/hg/hgVai/hgVai.c
index 24d4ac0..4784225 100644
--- src/hg/hgVai/hgVai.c
+++ src/hg/hgVai/hgVai.c
@@ -968,30 +968,58 @@
            isVisible ? "block" : "none");
     cartMakeCheckBox(cart, "hgva_txStatus_refSeqStatus", FALSE);
     puts("Include the "
          "<A HREF=" REFSEQ_STATUS_DOC_URL " "
          "TARGET=_BLANK>RefSeq status</A> of each transcript.<BR>");
     puts("</div>");
     }
 printf("<div class=\"noTxStatus\" style=\"display: %s;\">",
        somethingIsVisible ? "none" : "block");
 puts("No transcript status data are available for the selected gene track.");
 puts("</div>");
 puts("<BR>");
 endCollapsibleSection();
 }
 
+static void selectHgvsOut()
+/* Offer HGVS output choices */
+{
+startCollapsibleSection("hgvsOut", "HGVS variant nomenclature", TRUE);
+printf("The <a href='http://www.hgvs.org/' target=_blank>Human Genome Variation Society (HGVS)</a> "
+       "has established a "
+       "<a href='http://varnomen.hgvs.org/' target=_blank>sequence variant nomenclature</a>, "
+       "an international standard used to report variation in "
+       "genomic, transcript and protein sequences.<br>\n");
+cartMakeCheckBox(cart, "hgva_hgvsG", FALSE);
+printf("Include HGVS genomic (g.) terms in output<br>\n");
+cartMakeCheckBox(cart, "hgva_hgvsCN", FALSE);
+printf("Include HGVS coding (c.) terms if applicable, otherwise noncoding (n.) terms, in output"
+       "<br>\n");
+cartMakeCheckBox(cart, "hgva_hgvsP", FALSE);
+printf("Include HGVS protein (p.) terms (if applicable) in output<br>\n");
+cartMakeCheckBox(cart, "hgva_hgvsPAddParens", FALSE);
+printf("When including HGVS protein (p.) terms, add parentheses around changes to emphasize "
+       "that they are predictions<br>\n");
+cartMakeCheckBox(cart, "hgva_hgvsBreakDelIns", FALSE);
+printf("For variants that involve both a deletion and insertion, "
+       "including multi-nucleotide variants, "
+       "include the deleted sequence (e.g. show \"delAGinsTT\" instead of only \"delinsTT\")"
+       "<br>\n");
+puts("<br>");
+endCollapsibleSection();
+}
+
 boolean isHg19RegulatoryTrack(struct trackDb *tdb, void *filterData)
 /* For now, just look for a couple specific tracks by tableName. */
 {
 //#*** NEED METADATA
 return (sameString("wgEncodeRegDnaseClusteredV3", tdb->table) ||
 	sameString("wgEncodeRegTfbsClusteredV3", tdb->table));
 }
 
 boolean isHg38RegulatoryTrack(struct trackDb *tdb, void *filterData)
 /* For now, just look for a couple specific tracks by tableName. */
 {
 //#*** NEED METADATA
 return (sameString("wgEncodeRegDnaseClustered", tdb->table) ||
 	sameString("wgEncodeRegTfbsClusteredV3", tdb->table));
 }
@@ -1117,30 +1145,31 @@
 struct slName *dbNsfpTables = findDbNsfpTables();
 boolean gotSnp = findSnpBed4("", NULL, NULL);
 struct slRef *elTrackRefList = NULL, *scoreTrackRefList = NULL;
 findCons(&elTrackRefList, &scoreTrackRefList);
 struct slRef *cosmicTrackRefList = findTrackRefByName("cosmic");
 boolean hasTxStat = hasTxStatus();
 if (dbNsfpTables == NULL && !gotSnp && elTrackRefList == NULL && scoreTrackRefList == NULL &&
     cosmicTrackRefList == NULL && !hasTxStat)
     return;
 puts("<BR>");
 printf("<div class='sectionLiteHeader'>Select More Annotations (optional)</div>\n");
 // Make wrapper table for collapsible sections:
 puts("<TABLE border=0 cellspacing=5 cellpadding=0 style='padding-left: 10px;'>");
 selectDbNsfp(dbNsfpTables);
 selectTxStatus(hasTxStat, geneTrack);
+selectHgvsOut();
 selectDbSnp(gotSnp);
 trackCheckBoxSection("Cosmic", "COSMIC", cosmicTrackRefList);
 trackCheckBoxSection("ConsEl", "Conserved elements", elTrackRefList);
 trackCheckBoxSection("ConsScore", "Conservation scores", scoreTrackRefList);
 puts("</TABLE>");
 }
 
 void selectFiltersFunc()
 /* Options to restrict variants based on gene region/soTerm from gpFx */
 {
 startCollapsibleSection("filtersFunc", "Functional role", FALSE);
 printf("Include variants annotated as<BR>\n");
 jsMakeSetClearContainer();
 cartMakeCheckBox(cart, "hgva_include_intergenic", TRUE);
 printf("intergenic<BR>\n");
@@ -1398,30 +1427,47 @@
 ZeroVar(&aggvFuncFilter);
 aggvFuncFilter.intergenic = cartUsualBoolean(cart, "hgva_include_intergenic", TRUE);
 aggvFuncFilter.upDownstream = cartUsualBoolean(cart, "hgva_include_upDownstream", TRUE);
 aggvFuncFilter.nmdTranscript = cartUsualBoolean(cart, "hgva_include_nmdTranscript", TRUE);
 aggvFuncFilter.exonLoss = cartUsualBoolean(cart, "hgva_include_exonLoss", TRUE);
 aggvFuncFilter.utr = cartUsualBoolean(cart, "hgva_include_utr", TRUE);
 aggvFuncFilter.cdsSyn = cartUsualBoolean(cart, "hgva_include_cdsSyn", TRUE);
 aggvFuncFilter.cdsNonSyn = cartUsualBoolean(cart, "hgva_include_cdsNonSyn", TRUE);
 aggvFuncFilter.intron = cartUsualBoolean(cart, "hgva_include_intron", TRUE);
 aggvFuncFilter.splice = cartUsualBoolean(cart, "hgva_include_splice", TRUE);
 aggvFuncFilter.nonCodingExon = cartUsualBoolean(cart, "hgva_include_nonCodingExon", TRUE);
 aggvFuncFilter.noVariation = cartUsualBoolean(cart, "hgva_include_noVariation", TRUE);
 annoGratorGpVarSetFuncFilter(gpVarGrator, &aggvFuncFilter);
 }
 
+static void setHgvsOutOptions(struct annoGrator *gpVarGrator)
+/* Use cart variables to configure gpVarGrator's HGVS output. */
+{
+uint hgvsOutOptions = 0;
+if (cartUsualBoolean(cart, "hgva_hgvsG", FALSE))
+    hgvsOutOptions |= HGVS_OUT_G;
+if (cartUsualBoolean(cart, "hgva_hgvsCN", FALSE))
+    hgvsOutOptions |= HGVS_OUT_CN;
+if (cartUsualBoolean(cart, "hgva_hgvsP", FALSE))
+    hgvsOutOptions |= HGVS_OUT_P;
+if (cartUsualBoolean(cart, "hgva_hgvsPAddParens", FALSE))
+    hgvsOutOptions |= HGVS_OUT_P_ADD_PARENS;
+if (cartUsualBoolean(cart, "hgva_hgvsBreakDelIns", FALSE))
+    hgvsOutOptions |= HGVS_OUT_BREAK_DELINS;
+annoGratorGpVarSetHgvsOutOptions(gpVarGrator, hgvsOutOptions);
+}
+
 struct annoGrator *gratorForSnpBed4(struct hash *gratorsByName, char *suffix,
 				    struct annoAssembly *assembly, char *chrom,
 				    enum annoGratorOverlap overlapRule,
 				    char **retDescription)
 /* Look up snpNNNsuffix; if we find it, return a grator (possibly for a bigBed 4 file),
  * otherwise return NULL. */
 {
 char *fileName = NULL;
 struct trackDb *tdb = NULL;
 if (! findSnpBed4(suffix, &fileName, &tdb))
     return NULL;
 struct annoGrator *grator = NULL;
 // First look in gratorsByName to see if this grator has already been constructed:
 if (tdb != NULL)
     {
@@ -2738,30 +2784,31 @@
         if (! isCommandLine)
             doUi();
 	return;
 	}
     primary = hAnnoStreamerFromTrackDb(assembly, varTdb->table, varTdb, chrom, maxVarRows, NULL);
     primaryLongLabel = varTdb->longLabel;
     }
 
 enum annoGratorOverlap geneOverlapRule = agoMustOverlap;
 struct joinerDtf *txStatusExtras = getTxStatusExtras(database, geneTrack);
 struct jsonElement *gpConfig = configForStreamer(database, geneTdb, txStatusExtras);
 struct annoGrator *gpVarGrator = hAnnoGratorFromTrackDb(assembly, geneTdb->table, geneTdb, chrom,
                                                         ANNO_NO_LIMIT, primary->asObj,
                                                         geneOverlapRule, gpConfig);
 setGpVarFuncFilter(gpVarGrator);
+setHgvsOutOptions(gpVarGrator);
 
 // Some grators may be used as both filters and output values. To avoid making
 // multiple grators for the same source, hash them by trackName:
 struct hash *gratorsByName = hashNew(8);
 
 struct annoGrator *snpGrator = NULL;
 char *snpDesc = NULL;
 if (cartUsualBoolean(cart, "hgva_rsId", TRUE))
     snpGrator = gratorForSnpBed4(gratorsByName, "", assembly, chrom, agoNoConstraint, &snpDesc);
 
 // Now construct gratorList in the order in which annoFormatVep wants to see them,
 // i.e. first the gpVar, then the snpNNN, then whatever else:
 struct annoGrator *gratorList = NULL;
 slAddHead(&gratorList, gpVarGrator);
 if (snpGrator != NULL)