+
+ return 1;
+ }
+
+ /**
+ * A convenience method to get the AF value for the given alternate allele
+ * index
+ *
+ * @param variant
+ * @param alleleIndex
+ * @return
+ */
+ protected float getAlleleFrequency(VariantContext variant, int alleleIndex)
+ {
+ float score = 0f;
+ String attributeValue = getAttributeValue(variant,
+ ALLELE_FREQUENCY_KEY, alleleIndex);
+ if (attributeValue != null)
+ {
+ try
+ {
+ score = Float.parseFloat(attributeValue);
+ } catch (NumberFormatException e)
+ {
+ // leave as 0
+ }
+ }
+
+ return score;
+ }
+
+ /**
+ * A convenience method to get an attribute value for an alternate allele
+ *
+ * @param variant
+ * @param attributeName
+ * @param alleleIndex
+ * @return
+ */
+ protected String getAttributeValue(VariantContext variant,
+ String attributeName, int alleleIndex)
+ {
+ Object att = variant.getAttribute(attributeName);
+
+ if (att instanceof String)
+ {
+ return (String) att;
+ }
+ else if (att instanceof ArrayList)
+ {
+ return ((List<String>) att).get(alleleIndex);
+ }
+
+ return null;
+ }
+
+ /**
+ * Adds one variant feature for each SNP allele in the VCF variant record, and
+ * returns the number of features added.
+ *
+ * @param seq
+ * @param variant
+ * @param featureStart
+ * @param featureEnd
+ * @param forwardStrand
+ * @return
+ */
+ protected int addAlleleFeatures(SequenceI seq, VariantContext variant,
+ int featureStart, int featureEnd, boolean forwardStrand)
+ {
+ int added = 0;
+
+ /*
+ * Javadoc says getAlternateAlleles() imposes no order on the list returned
+ * so we proceed defensively to get them in strict order
+ */
+ int altAlleleCount = variant.getAlternateAlleles().size();
+ for (int i = 0; i < altAlleleCount; i++)
+ {
+ added += addAlleleFeature(seq, variant, i, featureStart, featureEnd,
+ forwardStrand);
+ }
+ return added;
+ }
+
+ /**
+ * Inspects one allele and attempts to add a variant feature for it to the
+ * sequence. Only SNP variants are added as features. We extract as much as
+ * possible of the additional data associated with this allele to store in the
+ * feature's key-value map. Answers the number of features added (0 or 1).
+ *
+ * @param seq
+ * @param variant
+ * @param altAlleleIndex
+ * @param featureStart
+ * @param featureEnd
+ * @param forwardStrand
+ * @return
+ */
+ protected int addAlleleFeature(SequenceI seq, VariantContext variant,
+ int altAlleleIndex, int featureStart, int featureEnd,
+ boolean forwardStrand)
+ {
+ byte[] reference = variant.getReference().getBases();
+ Allele alt = variant.getAlternateAllele(altAlleleIndex);
+ byte[] allele = alt.getBases();
+ if (allele.length != 1)
+ {
+ /*
+ * not a SNP variant
+ */
+ return 0;
+ }
+
+ /*
+ * build the ref,alt allele description e.g. "G,A"
+ */
+ StringBuilder sb = new StringBuilder();
+ sb.append(forwardStrand ? (char) reference[0] : complement(reference));
+ sb.append(COMMA);
+ sb.append(forwardStrand ? (char) allele[0] : complement(allele));
+ String alleles = sb.toString(); // e.g. G,A
+
+ String type = SequenceOntologyI.SEQUENCE_VARIANT;
+ float score = getAlleleFrequency(variant, altAlleleIndex);
+
+ SequenceFeature sf = new SequenceFeature(type, alleles, featureStart,
+ featureEnd, score, FEATURE_GROUP_VCF);
+
+ sf.setValue(Gff3Helper.ALLELES, alleles);
+
+ addAlleleProperties(variant, sf, altAlleleIndex);
+
+ seq.addSequenceFeature(sf);
+
+ return 1;
+ }
+
+ /**
+ * Add any allele-specific VCF key-value data to the sequence feature
+ *
+ * @param variant
+ * @param sf
+ * @param altAlelleIndex
+ */
+ protected void addAlleleProperties(VariantContext variant,
+ SequenceFeature sf, final int altAlelleIndex)
+ {
+ Map<String, Object> atts = variant.getAttributes();
+
+ /*
+ * process variant data, extracting values which are allele-specific
+ * these may be per alternate allele (INFO[key].Number = 'A')
+ * or per allele including reference (INFO[key].Number = 'R')
+ */
+ for (Entry<String, Object> att : atts.entrySet())
+ {
+ String key = att.getKey();
+ VCFHeaderLineCount number = header.getInfoHeaderLine(key)
+ .getCountType();
+ int index = altAlelleIndex;
+ if (number == VCFHeaderLineCount.R)
+ {
+ /*
+ * one value per allele including reference, so bump index
+ * e.g. the 3rd value is for the 2nd alternate allele
+ */
+ index++;
+ }
+ /*
+ * CSQ behaves as if Number=A but declares as Number=.
+ * so give it special treatment
+ */
+ else if (!"CSQ".equals(key) && number != VCFHeaderLineCount.A)
+ {
+ /*
+ * don't save other values as not allele-related
+ */
+ continue;
+ }
+
+ /*
+ * take the index'th value
+ */
+ String value = getAttributeValue(variant, key, index);
+ if (value != null)
+ {
+ sf.setValue(key, value);
+ }
+ }