package picard.illumina.parser;
import htsjdk.samtools.util.IOUtil;
import picard.PicardException;
import picard.illumina.parser.fakers.BciFileFaker;
import picard.illumina.parser.fakers.FileFaker;
import picard.illumina.parser.fakers.FilterFileFaker;
import picard.illumina.parser.fakers.MultiTileLocsFileFaker;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
/**
* For file types for which there is one file per lane, with fixed record size, and all the tiles in it,
* so the s_<lane>.bci file can be used to figure out where each tile starts and ends.
*/
public abstract class MultiTileFileUtil<OUTPUT_RECORD extends IlluminaData> extends ParameterizedFileUtil {
protected final File bci;
protected TileIndex tileIndex;
protected File dataFile;
MultiTileFileUtil(final String extension, final File base, final File bciDir, final FileFaker fileFaker,
final int lane) {
super(false, extension, base, fileFaker, lane);
bci = new File(bciDir, "s_" + lane + ".bci");
if (bci.exists()) {
tileIndex = new TileIndex(bci);
} else {
tileIndex = null;
}
final File[] filesMatchingRegexp = IOUtil.getFilesMatchingRegexp(base, matchPattern);
if (filesMatchingRegexp == null || filesMatchingRegexp.length == 0) {
dataFile = null;
} else if (filesMatchingRegexp.length == 1) {
dataFile = filesMatchingRegexp[0];
} else {
throw new PicardException("More than one filter file found in " + base.getAbsolutePath());
}
}
@Override
public boolean filesAvailable() {
return tileIndex != null && dataFile != null && dataFile.exists();
}
@Override
public List<Integer> getTiles() {
if (tileIndex == null) {
return Collections.emptyList();
}
return tileIndex.getTiles();
}
/**
* expectedCycles are not checked in this implementation.
*/
@Override
public List<String> verify(final List<Integer> expectedTiles, final int[] expectedCycles) {
if (tileIndex == null) {
return Collections.singletonList("Tile index(" + bci.getAbsolutePath() + ") does not exist!");
}
return tileIndex.verify(expectedTiles);
}
@Override
public List<String> fakeFiles(final List<Integer> expectedTiles, final int[] expectedCycles,
final IlluminaFileUtil.SupportedIlluminaFormat format) {
//we need to fake a bci file for the tile index
final BciFileFaker bciFileFaker = new BciFileFaker();
try {
bciFileFaker.fakeBciFile(bci, expectedTiles);
tileIndex = new TileIndex(bci);
faker.fakeFile(base, expectedTiles, lane, extension);
final File[] filesMatchingRegexp = IOUtil.getFilesMatchingRegexp(base, matchPattern);
if (filesMatchingRegexp == null || filesMatchingRegexp.length == 0) {
dataFile = null;
} else if (filesMatchingRegexp.length == 1) {
dataFile = filesMatchingRegexp[0];
} else {
throw new PicardException("More than one filter file found in " + base.getAbsolutePath());
}
} catch (final IOException e) {
return Collections.singletonList("Could not create tile index file: " + bci.getAbsolutePath());
}
return tileIndex.verify(expectedTiles);
}
abstract IlluminaParser<OUTPUT_RECORD> makeParser(List<Integer> requestedTiles);
}
class MultiTileFilterFileUtil extends MultiTileFileUtil<PfData> {
/**
* @param basecallLaneDir location of .filter file and also .bci file
*/
MultiTileFilterFileUtil(final File basecallLaneDir, final int lane) {
super(".filter", basecallLaneDir, basecallLaneDir, new FilterFileFaker(), lane);
}
@Override
IlluminaParser<PfData> makeParser(final List<Integer> requestedTiles) {
return new MultiTileFilterParser(tileIndex, requestedTiles, dataFile);
}
}
class MultiTileLocsFileUtil extends MultiTileFileUtil<PositionalData> {
MultiTileLocsFileUtil(final File basecallLaneDir, final File bciDir, final int lane) {
super(".locs", basecallLaneDir, bciDir, new MultiTileLocsFileFaker(), lane);
}
@Override
IlluminaParser<PositionalData> makeParser(final List<Integer> requestedTiles) {
return new MultiTileLocsParser(tileIndex, requestedTiles, dataFile, lane);
}
}