package htsjdk.variant.vcf;
import htsjdk.samtools.SAMFileHeader;
import htsjdk.samtools.SAMSequenceDictionary;
import htsjdk.samtools.util.CloseableIterator;
import htsjdk.samtools.util.CloserUtil;
import htsjdk.samtools.util.Interval;
import htsjdk.samtools.util.IntervalList;
import htsjdk.tribble.AbstractFeatureReader;
import htsjdk.tribble.FeatureCodec;
import htsjdk.tribble.FeatureReader;
import htsjdk.tribble.TribbleException;
import htsjdk.variant.bcf2.BCF2Codec;
import htsjdk.variant.variantcontext.VariantContext;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
/**
* Simplified interface for reading from VCF/BCF files.
*/
public class VCFFileReader implements Closeable, Iterable<VariantContext> {
private final FeatureReader<VariantContext> reader;
/**
* Returns true if the given file appears to be a BCF file.
*/
public static boolean isBCF(final File file) {
return file.getAbsolutePath().endsWith(".bcf");
}
/**
* Returns the SAMSequenceDictionary from the provided VCF file.
*/
public static SAMSequenceDictionary getSequenceDictionary(final File file) {
final SAMSequenceDictionary dict = new VCFFileReader(file, false).getFileHeader().getSequenceDictionary();
CloserUtil.close(file);
return dict;
}
/** Constructs a VCFFileReader that requires the index to be present. */
public VCFFileReader(final File file) {
this(file, true);
}
/** Constructs a VCFFileReader with a specified index. */
public VCFFileReader(final File file, final File indexFile) {
this(file, indexFile, true);
}
/** Allows construction of a VCFFileReader that will or will not assert the presence of an index as desired. */
public VCFFileReader(final File file, final boolean requireIndex) {
this.reader = AbstractFeatureReader.getFeatureReader(
file.getAbsolutePath(),
isBCF(file) ? (FeatureCodec) new BCF2Codec() : new VCFCodec(),
requireIndex);
}
/** Allows construction of a VCFFileReader with a specified index file. */
public VCFFileReader(final File file, final File indexFile, final boolean requireIndex) {
this.reader = AbstractFeatureReader.getFeatureReader(
file.getAbsolutePath(),
indexFile.getAbsolutePath(),
isBCF(file) ? (FeatureCodec) new BCF2Codec() : new VCFCodec(),
requireIndex);
}
/**
* Parse a VCF file and convert to an IntervalList The name field of the IntervalList is taken from the ID field of the variant, if it exists. if not,
* creates a name of the format interval-n where n is a running number that increments only on un-named intervals
* @param file
* @return
*/
public static IntervalList fromVcf(final File file){
final VCFFileReader vcfFileReader = new VCFFileReader(file, false);
final IntervalList intervalList = fromVcf(vcfFileReader);
vcfFileReader.close();
return intervalList;
}
/**
* Converts a vcf to an IntervalList. The name field of the IntervalList is taken from the ID field of the variant, if it exists. if not,
* creates a name of the format interval-n where n is a running number that increments only on un-named intervals
* @param vcf the vcfReader to be used for the conversion
* @return an IntervalList constructed from input vcf
*/
public static IntervalList fromVcf(final VCFFileReader vcf){
//grab the dictionary from the VCF and use it in the IntervalList
final SAMSequenceDictionary dict = vcf.getFileHeader().getSequenceDictionary();
final SAMFileHeader samFileHeader = new SAMFileHeader();
samFileHeader.setSequenceDictionary(dict);
final IntervalList list = new IntervalList( samFileHeader);
int intervals=0;
for(final VariantContext vc : vcf){
if(!vc.isFiltered()){
String name = vc.getID();
if(".".equals(name) || name == null)
name = "interval-" + (++intervals);
list.add(new Interval(vc.getChr(), vc.getStart(), vc.getEnd(), false, name));
}
}
return list;
}
/** Returns the VCFHeader associated with this VCF/BCF file. */
public VCFHeader getFileHeader() {
return (VCFHeader) reader.getHeader();
}
/** Returns an iterator over all records in this VCF/BCF file. */
public CloseableIterator<VariantContext> iterator() {
try { return reader.iterator(); }
catch (final IOException ioe) {
throw new TribbleException("Could not create an iterator from a feature reader.", ioe);
}
}
/** Queries for records within the region specified. */
public CloseableIterator<VariantContext> query(final String chrom, final int start, final int end) {
try { return reader.query(chrom, start, end); }
catch (final IOException ioe) {
throw new TribbleException("Could not create an iterator from a feature reader.", ioe);
}
}
public void close() {
try { this.reader.close(); }
catch (final IOException ioe) {
throw new TribbleException("Could not close a variant context feature reader.", ioe);
}
}
}