package picard.illumina.parser;
import htsjdk.samtools.util.IOUtil;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import picard.PicardException;
import picard.illumina.parser.IlluminaFileUtil.SupportedIlluminaFormat;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static htsjdk.samtools.util.CollectionUtil.makeList;
public class IlluminaFileUtilTest {
private static final int DEFAULT_LANE = 7;
private static final List<Integer> DEFAULT_TILES = makeList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
private static final List<Integer> DEFAULT_TILE_TEST_SUBSET = makeList(1, 4, 5, 6, 9, 10);
private static final int[] DEFAULT_CYCLES = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
private static final int DEFAULT_LAST_CYCLE = 20;
// We have data for these that should agree
private static final List<SupportedIlluminaFormat> FORMATS_TO_TEST = Arrays.asList(
SupportedIlluminaFormat.Bcl,
SupportedIlluminaFormat.Locs,
SupportedIlluminaFormat.Clocs,
SupportedIlluminaFormat.Pos,
SupportedIlluminaFormat.Filter,
SupportedIlluminaFormat.Barcode);
private File intensityDir;
private File basecallDir;
@BeforeMethod
private void setUp() throws Exception {
intensityDir = IOUtil.createTempDir("ift_test", "Intensities");
basecallDir = new File(intensityDir, "BaseCalls");
if (!basecallDir.mkdir()) {
throw new RuntimeException("Couldn't make basecalls dir " + basecallDir.getAbsolutePath());
}
}
@AfterMethod
private void tearDown() {
IOUtil.deleteDirectoryTree(intensityDir);
}
@DataProvider(name = "validLanes")
public Object[][] validLanes() {
return new Object[][]{
{0, "s_0_1111.test"},
{1, "s_1_23.test"},
{10, "s_10_1.test"}
};
}
public void regexMatches(final String regex, final String toMatch) {
regexMatches(regex, toMatch, true);
}
public void regexMatches(final String regex, final String toMatch, final boolean expectedResult) {
final Pattern pt = Pattern.compile(regex);
final Matcher ma = pt.matcher(toMatch);
Assert.assertEquals(ma.matches(), expectedResult);
}
@Test(dataProvider = "validLanes")
public void regexTests(final int lane, final String ltExample) {
regexMatches(ParameterizedFileUtil.makeLaneTileRegex(".test", lane), ltExample);
}
@DataProvider(name = "validLanesInvalidRegexes")
public Object[][] validLanesInvalidRegexes() {
return new Object[][]{
{0, "s_-0_111"},
{1, "s_1_A3"},
{10, "s_-100_1"},
{20, "s_21_1"}
};
}
@Test(dataProvider = "validLanesInvalidRegexes")
public void notMatchingRegexTest(final int lane, final String ltExample) {
regexMatches(ParameterizedFileUtil.makeLaneTileRegex(".test", lane) , ltExample, false);
}
@DataProvider(name = "invalidLanes")
public Object[][] invalidLanes() {
return new Object[][]{
{-1000},
{-10},
{-1}
};
}
@Test(dataProvider = "invalidLanes", expectedExceptions = PicardException.class)
public void invalidLaneForLTRegex(final int lane) {
ParameterizedFileUtil.makeLaneTileRegex(".test", lane);
}
public void assertDefaults(final IlluminaFileUtil fileUtil, final Integer lane, final List<SupportedIlluminaFormat> formatsToTest) {
if (lane == null) {
Assert.assertEquals(fileUtil.getLane(), DEFAULT_LANE);
} else {
Assert.assertEquals(new Integer(fileUtil.getLane()), lane);
}
Assert.assertEquals(fileUtil.getUtil(SupportedIlluminaFormat.Barcode).getTiles(), DEFAULT_TILES);
Assert.assertEquals(fileUtil.getUtil(SupportedIlluminaFormat.Bcl).getTiles(), DEFAULT_TILES);
Assert.assertEquals(fileUtil.getUtil(SupportedIlluminaFormat.Pos).getTiles(), DEFAULT_TILES);
Assert.assertEquals(fileUtil.getUtil(SupportedIlluminaFormat.Locs).getTiles(), DEFAULT_TILES);
Assert.assertEquals(fileUtil.getUtil(SupportedIlluminaFormat.Clocs).getTiles(), DEFAULT_TILES);
Assert.assertEquals(fileUtil.getUtil(SupportedIlluminaFormat.Filter).getTiles(), DEFAULT_TILES);
final Set<Integer> detectedCycles = ((PerTilePerCycleFileUtil) fileUtil.getUtil(SupportedIlluminaFormat.Bcl)).getDetectedCycles();
Assert.assertEquals(detectedCycles.size(), DEFAULT_CYCLES.length);
int i = 0;
for(final Integer cycle : detectedCycles){
Assert.assertEquals(cycle.intValue(), DEFAULT_CYCLES[i++], "Elements differ at index " + i);
}
Assert.assertEquals(fileUtil.getActualTiles(formatsToTest), DEFAULT_TILES);
}
@Test
public void passNewUtilTest() {
for (final SupportedIlluminaFormat format : SupportedIlluminaFormat.values()) {
makeFiles(format, intensityDir, DEFAULT_LANE, DEFAULT_TILES, DEFAULT_CYCLES);
makeFiles(format, intensityDir, DEFAULT_LANE + 1, DEFAULT_TILES, DEFAULT_CYCLES, ".gz");
makeFiles(format, intensityDir, DEFAULT_LANE + 2, DEFAULT_TILES, DEFAULT_CYCLES, ".bz2");
}
final Set<SupportedIlluminaFormat> formatsToTest = new HashSet<SupportedIlluminaFormat>();
// TODO: I can't be bothered to build files for these. AW
Collections.addAll(formatsToTest, SupportedIlluminaFormat.values());
formatsToTest.remove(SupportedIlluminaFormat.MultiTileBcl);
formatsToTest.remove(SupportedIlluminaFormat.MultiTileFilter);
formatsToTest.remove(SupportedIlluminaFormat.MultiTileLocs);
final ArrayList<SupportedIlluminaFormat> formatsList = new ArrayList<SupportedIlluminaFormat>(formatsToTest);
for (int i = 0; i < 3; i++) {
final IlluminaFileUtil fileUtil = new IlluminaFileUtil(new File(intensityDir, "BaseCalls"), DEFAULT_LANE + i);
Assert.assertEquals(fileUtil.getActualTiles(formatsList), DEFAULT_TILES);
assertDefaults(fileUtil, DEFAULT_LANE + i, formatsList);
}
}
@Test
public void passingVerifyTest() {
for (final SupportedIlluminaFormat format : SupportedIlluminaFormat.values()) {
makeFiles(format, intensityDir, DEFAULT_LANE, DEFAULT_TILES, DEFAULT_CYCLES);
makeFiles(format, intensityDir, DEFAULT_LANE + 1, DEFAULT_TILES, DEFAULT_CYCLES, ".gz");
makeFiles(format, intensityDir, DEFAULT_LANE + 2, DEFAULT_TILES, DEFAULT_CYCLES, ".bz2");
}
for (int i = 0; i < 3; i++) {
final IlluminaFileUtil fileUtil = new IlluminaFileUtil(new File(intensityDir, "BaseCalls"), DEFAULT_LANE + i);
for (final SupportedIlluminaFormat format : FORMATS_TO_TEST) {
Assert.assertEquals(new ArrayList<String>(), fileUtil.getUtil(format).verify(DEFAULT_TILES, DEFAULT_CYCLES));
}
}
}
@DataProvider(name = "missingTileFormats")
public Object[][] missingTileFormats() {
return new Object[][]{
{
1,
makeList(SupportedIlluminaFormat.Bcl, SupportedIlluminaFormat.Barcode),
makeList(SupportedIlluminaFormat.Bcl, SupportedIlluminaFormat.Barcode),
makeList("BaseCalls/s_1_0007_barcode.txt.gz"),
".gz"
},
{
2,
Arrays.asList(SupportedIlluminaFormat.values()),
Arrays.asList(SupportedIlluminaFormat.values()),
makeCycleFileList(new File("BaseCalls"), ".bcl", 2, DEFAULT_CYCLES, 2),
".gz"
},
{
3,
Arrays.asList(SupportedIlluminaFormat.values()),
Arrays.asList(SupportedIlluminaFormat.values()),
makeList("BaseCalls/L003/C1.1/s_3_2.bcl"),
".bz2"
},
{
4,
Arrays.asList(SupportedIlluminaFormat.values()),
Arrays.asList(SupportedIlluminaFormat.Pos, SupportedIlluminaFormat.Locs),
makeList("s_4_10_pos.txt", "L004/s_4_2.locs"),
null
}
};
}
public static void emptyRelativeFiles(final File baseFile, final List<String> relativeFilesToDelete) {
for (final String relativeFile : relativeFilesToDelete) {
final File actualFile = new File(baseFile, relativeFile);
if (!actualFile.exists()) {
throw new RuntimeException("Trying to empty a non-existent file" + actualFile.getAbsolutePath());
}
if (actualFile.isDirectory()) {
throw new RuntimeException("Trying to empty a directory(" + actualFile.getAbsolutePath() + ")");
} else {
if (!actualFile.delete()) {
throw new RuntimeException("Couldn't remove previous file when emptying(" + actualFile.getAbsolutePath() + ")");
} else {
try {
if (!actualFile.createNewFile()) {
throw new RuntimeException("Couldn't create empty file: " + actualFile.getAbsolutePath() + ")");
}
} catch (final IOException ioe) {
throw new RuntimeException(ioe);
}
}
}
if (!actualFile.exists()) {
throw new PicardException("File should exist: " + actualFile);
}
}
}
public static void deleteRelativeFiles(final File baseFile, final List<String> relativeFilesToDelete) {
for (final String relativeFile : relativeFilesToDelete) {
final File actualFile = new File(baseFile, relativeFile);
if (!actualFile.exists()) {
throw new RuntimeException("Trying to delete a non-existent file" + actualFile.getAbsolutePath());
}
if (actualFile.isDirectory()) {
IOUtil.deleteDirectoryTree(actualFile);
} else {
IOUtil.deleteFiles(actualFile);
}
if (actualFile.exists()) {
throw new RuntimeException("File still exists after calling delete: " + actualFile);
}
}
}
public final void deleteRelativeFiles(final List<String> relativeFilesToDelete) {
deleteRelativeFiles(intensityDir, relativeFilesToDelete);
}
@Test(dataProvider = "missingTileFormats")
public void missingTileTest(final int lane,
final List<SupportedIlluminaFormat> formats,
final List<SupportedIlluminaFormat> formatsToGetTiles,
final List<String> relativeFilesToDelete,
final String compression) {
for (final SupportedIlluminaFormat format : formats) {
makeFiles(format, intensityDir, lane, DEFAULT_TILES, DEFAULT_CYCLES, compression);
}
deleteRelativeFiles(relativeFilesToDelete);
PicardException pExc = null;
try {
final IlluminaFileUtil fUtil = new IlluminaFileUtil(new File(intensityDir, "BaseCalls"), lane);
fUtil.getActualTiles(formatsToGetTiles);
} catch (final PicardException exception) {
pExc = exception;
}
Assert.assertNotNull(pExc, "Didn't raise a Picard Exception for missing tile!");
Assert.assertTrue(pExc.getMessage().contains("Formats do not have the same number of tiles! "), "Wrong exception thrown for missing tile!");
}
@DataProvider(name = "perTileFileFormats")
public Object[][] perTileFileUtils() {
return new Object[][]{
{SupportedIlluminaFormat.Locs, null, false, laneDir(DEFAULT_LANE)},
{SupportedIlluminaFormat.Clocs, null, false, laneDir(DEFAULT_LANE)},
{SupportedIlluminaFormat.Pos, ".gz", false, null},
{SupportedIlluminaFormat.Pos, null, false, null},
{SupportedIlluminaFormat.Filter, null, true, "BaseCalls/" + laneDir(DEFAULT_LANE)},
{SupportedIlluminaFormat.Barcode, ".bz2", true, "BaseCalls"}
};
}
public File makePerTileFile(final File parentDir, final int lane, final int tile, final String extension, final String compression, final boolean longFormat) {
return new File(parentDir, "s_" + lane + "_" + longTile(tile, longFormat) + extension + (compression != null ? compression : ""));
}
public void testDefaultPerTileUtil(final PerTileFileUtil ptfu, final String compression, final boolean longFormat, final File parentDir) {
final IlluminaFileMap fm = ptfu.getFiles();
final IlluminaFileMap fmWTiles = ptfu.getFiles(DEFAULT_TILES);
Assert.assertEquals(fm.size(), DEFAULT_TILES.size());
for (final Integer tile : DEFAULT_TILES) {
final File tFile = fm.get(tile);
final File tFile2 = fmWTiles.get(tile);
Assert.assertEquals(tFile.getAbsolutePath(), tFile2.getAbsolutePath());
Assert.assertEquals(tFile, makePerTileFile(parentDir, DEFAULT_LANE, tile, ptfu.extension, compression, longFormat));
Assert.assertTrue(tFile.exists());
Assert.assertTrue(tFile.length() > 0);
}
final List<Integer> tiles = new ArrayList<Integer>(DEFAULT_TILE_TEST_SUBSET);
final IlluminaFileMap subsetMap = ptfu.getFiles(DEFAULT_TILE_TEST_SUBSET);
for (final Integer tile : subsetMap.keySet()) {
tiles.remove(tile);
Assert.assertTrue(DEFAULT_TILE_TEST_SUBSET.contains(tile));
final File tFile = subsetMap.get(tile);
Assert.assertEquals(tFile, makePerTileFile(parentDir, DEFAULT_LANE, tile, ptfu.extension, compression, longFormat));
Assert.assertTrue(tFile.exists());
Assert.assertTrue(tFile.length() > 0);
}
Assert.assertTrue(tiles.isEmpty());
}
@Test(dataProvider = "perTileFileFormats")
public void perTileFileUtilsTest(final SupportedIlluminaFormat format, final String compression, final boolean longFormat, final String parentDir) {
makeFiles(format, intensityDir, DEFAULT_LANE, DEFAULT_TILES, DEFAULT_CYCLES, compression);
final IlluminaFileUtil fileUtil = new IlluminaFileUtil(basecallDir, DEFAULT_LANE);
final PerTileFileUtil ptfu = (PerTileFileUtil) fileUtil.getUtil(format);
Assert.assertTrue(ptfu.filesAvailable());
testDefaultPerTileUtil(ptfu, compression, longFormat, (parentDir == null) ? intensityDir : new File(intensityDir, parentDir));
final IlluminaFileUtil noFilesFu = new IlluminaFileUtil(basecallDir, DEFAULT_LANE + 20);
final PerTileFileUtil noFilesPtfu = (PerTileFileUtil) noFilesFu.getUtil(format);
Assert.assertFalse(noFilesPtfu.filesAvailable());
Assert.assertTrue(noFilesPtfu.getFiles().isEmpty());
Assert.assertTrue(noFilesPtfu.getFiles(DEFAULT_TILES).isEmpty());
}
public File makePerTilePerCycleFilePath(final File parentDir, final int lane, final int tile, final int cycle, final String extension) {
return new File(parentDir, "C" + cycle + ".1/s_" + lane + "_" + tile + extension);
}
public void testDefaultPerTilePerCycleUtil(final PerTilePerCycleFileUtil pcfu, final File parentDir, final int[] cycles) {
final CycleIlluminaFileMap cfm = pcfu.getFiles(cycles);
final CycleIlluminaFileMap cfmWTiles = pcfu.getFiles(DEFAULT_TILES, cycles);
final CycleIlluminaFileMap cfmNoCycles;
if (Arrays.equals(cycles, DEFAULT_CYCLES)) {
cfmNoCycles = pcfu.getFiles();
} else {
cfmNoCycles = null;
}
Assert.assertEquals(cfm.size(), cycles.length);
for (final int cycle : cycles) {
final IlluminaFileMap tFileIter = cfm.get(cycle);
final IlluminaFileMap tFileIter2 = cfmWTiles.get(cycle);
final IlluminaFileMap tFileIter3;
if (cfmNoCycles != null) {
tFileIter3 = cfmNoCycles.get(cycle);
} else {
tFileIter3 = null;
}
for (final Integer tile : DEFAULT_TILES) {
final File tcFile = tFileIter.get(tile);
final File tcFile2 = tFileIter2.get(tile);
Assert.assertEquals(tcFile.getAbsolutePath(), tcFile2.getAbsolutePath());
if (tFileIter3 != null) {
final File tfFile3 = tFileIter3.get(tile);
Assert.assertEquals(tcFile.getAbsolutePath(), tfFile3.getAbsolutePath());
}
Assert.assertEquals(tcFile, makePerTilePerCycleFilePath(parentDir, DEFAULT_LANE, tile, cycle, pcfu.extension));
Assert.assertTrue(tcFile.exists());
Assert.assertTrue(tcFile.length() > 0);
}
}
}
public void testSubsetDefaultPerTilePerCycleUtil(final PerTilePerCycleFileUtil pcfu, final File parentDir, final int[] cycles) {
final List<Integer> tiles = new ArrayList<Integer>(DEFAULT_TILE_TEST_SUBSET);
final CycleIlluminaFileMap subsetMap = pcfu.getFiles(DEFAULT_TILE_TEST_SUBSET, cycles);
final CycleIlluminaFileMap cfmNoCycles;
if (Arrays.equals(cycles, DEFAULT_CYCLES)) {
cfmNoCycles = pcfu.getFiles(DEFAULT_TILE_TEST_SUBSET);
} else {
cfmNoCycles = null;
}
for (final int cycle : cycles) {
final IlluminaFileMap tFileIter = subsetMap.get(cycle);
final IlluminaFileMap tFileIter2;
if (cfmNoCycles != null) {
tFileIter2 = cfmNoCycles.get(cycle);
} else {
tFileIter2 = null;
}
for (final Integer tile : subsetMap.get(cycle).keySet()) {
Assert.assertTrue(DEFAULT_TILE_TEST_SUBSET.contains(tile));
tiles.remove(tile);
final File tcFile = tFileIter.get(tile);
if (tFileIter2 != null) {
Assert.assertEquals(tcFile, tFileIter2.get(tile));
}
Assert.assertEquals(tcFile, makePerTilePerCycleFilePath(parentDir, DEFAULT_LANE, tile, cycle, pcfu.extension));
Assert.assertTrue(tcFile.exists());
Assert.assertTrue(tcFile.length() > 0);
}
}
Assert.assertTrue(tiles.isEmpty());
}
public static int[] cycleRange(final Range range) {
return cycleRange(range.start, range.end);
}
public static int[] cycleRange(final int start, final int end) {
final int[] cycles = new int[end - start + 1];
for (int i = 0; i < cycles.length; i++) {
cycles[i] = start + i;
}
return cycles;
}
public static int[] cycleRange(final int end) {
return cycleRange(1, end);
}
@DataProvider(name = "perTilePerCycleFileFormats")
public Object[][] perTilePerCycleFileFormats() {
return new Object[][]{
{SupportedIlluminaFormat.Bcl, "BaseCalls/" + laneDir(DEFAULT_LANE), DEFAULT_CYCLES, false, false},
{SupportedIlluminaFormat.Bcl, "BaseCalls/" + laneDir(DEFAULT_LANE), cycleRange(4), true, true},
};
}
@Test(dataProvider = "perTilePerCycleFileFormats")
public void perTilePerCycleFileUtilsTest(final SupportedIlluminaFormat format, final String parentDir,
final int[] cycles, final boolean createEarlySkippedCycles,
final boolean createLateSkippedCycles) {
if (createEarlySkippedCycles) {
makeFiles(format, intensityDir, DEFAULT_LANE, DEFAULT_TILES, cycleRange(1, cycles[0]), null);
}
makeFiles(format, intensityDir, DEFAULT_LANE, DEFAULT_TILES, cycles, null);
if (createLateSkippedCycles) {
makeFiles(format, intensityDir, DEFAULT_LANE, DEFAULT_TILES, cycleRange(cycles[cycles.length - 1] + 1, DEFAULT_LAST_CYCLE), null);
}
final IlluminaFileUtil fileUtil = new IlluminaFileUtil(basecallDir, DEFAULT_LANE);
final PerTilePerCycleFileUtil pcfu = (PerTilePerCycleFileUtil) fileUtil.getUtil(format);
Assert.assertTrue(pcfu.filesAvailable());
testDefaultPerTilePerCycleUtil(pcfu, (parentDir == null) ? intensityDir : new File(intensityDir, parentDir), cycles);
testSubsetDefaultPerTilePerCycleUtil(pcfu, (parentDir == null) ? intensityDir : new File(intensityDir, parentDir), cycles);
final IlluminaFileUtil noFilesFu = new IlluminaFileUtil(basecallDir, DEFAULT_LANE + 20);
final PerTilePerCycleFileUtil noFilesPcfu = (PerTilePerCycleFileUtil) noFilesFu.getUtil(format);
Assert.assertFalse(noFilesPcfu.filesAvailable());
Assert.assertTrue(noFilesPcfu.getFiles().isEmpty());
Assert.assertTrue(noFilesPcfu.getFiles(DEFAULT_TILES).isEmpty());
}
@DataProvider(name = "missingCycleDataRanges")
public Object[][] missingCycleDataRanges() {
return new Object[][]{
{makeList(new Range(10, 15))},
{makeList(new Range(9, 12), new Range(14, 15))}
};
}
@Test(expectedExceptions = PicardException.class, dataProvider = "missingCycleDataRanges")
public void perTilePerCycleFileUtilsMissingCycleTest(final List<Range> cycleRangesToMake) {
final SupportedIlluminaFormat format = SupportedIlluminaFormat.Bcl;
for (final Range range : cycleRangesToMake) {
makeFiles(format, intensityDir, DEFAULT_LANE, DEFAULT_TILES, cycleRange(range), null);
}
final IlluminaFileUtil fileUtil = new IlluminaFileUtil(basecallDir, DEFAULT_LANE);
final PerTilePerCycleFileUtil pcfu = (PerTilePerCycleFileUtil) fileUtil.getUtil(format);
Assert.assertTrue(pcfu.filesAvailable());
final int[] cycles = cycleRange(9, 16);
final CycleIlluminaFileMap cfm = pcfu.getFiles(cycles);
cfm.assertValid(DEFAULT_TILES, cycles);
}
public static void makeFiles(final SupportedIlluminaFormat format, final File intensityDir, final int lane,
final List<Integer> tiles, final int[] cycles) {
makeFiles(format, intensityDir, lane, tiles, cycles, null);
}
public static void makeFiles(final SupportedIlluminaFormat format, final File intensityDir, final int lane,
final List<Integer> tiles, final int[] cycles, final String compression) {
String laneDir = String.valueOf(lane);
while (laneDir.length() < 3) {
laneDir = "0" + laneDir;
}
laneDir = "L" + laneDir;
final File basecallDir = new File(intensityDir, "BaseCalls");
final File basecallLaneDir = new File(basecallDir, laneDir);
final File intensityLaneDir = new File(intensityDir, laneDir);
switch (format) {
//per tile formats
case Barcode:
makePerTileFiles(basecallDir, lane, tiles, maybeAddExt("_barcode.txt", compression), true);
break;
case Pos:
makePerTileFiles(intensityDir, lane, tiles, maybeAddExt("_pos.txt", compression), false);
break;
case Locs:
makePerTileFiles(intensityLaneDir, lane, tiles, maybeAddExt(".locs", null), false);
break;
case Clocs:
makePerTileFiles(intensityLaneDir, lane, tiles, maybeAddExt(".clocs", null), false);
break;
case Filter:
makePerTileFiles(basecallLaneDir, lane, tiles, maybeAddExt(".filter", null), true);
break;
//per tile per cycle formats
case Bcl:
makePerTilePerCycleFiles(basecallLaneDir, lane, tiles, cycles, ".bcl");
break;
}
}
private static void makePerTileFiles(final File parentDir, final int lane, final List<Integer> tiles, final String ext, final boolean longName) {
if (!parentDir.exists()) {
if (!parentDir.mkdir()) {
throw new RuntimeException("Couldn't create directory " + parentDir.getAbsolutePath());
}
}
for (final Integer tile : tiles) {
writeNonEmptyFile(new File(parentDir, "s_" + lane + "_" + longTile(tile, longName) + ext));
}
}
private static void makePerTilePerCycleFiles(final File parentDir, final int lane, final List<Integer> tiles, final int[] cycles, final String ext) {
if (!parentDir.exists()) {
if (!parentDir.mkdir()) {
throw new RuntimeException("Couldn't create directory " + parentDir.getAbsolutePath());
}
}
for (final int cycle : cycles) {
final File cycleDir = new File(parentDir, "C" + cycle + ".1");
if (!cycleDir.exists()) {
if (!cycleDir.mkdir()) {
throw new RuntimeException("Couldn't create directory " + cycleDir.getAbsolutePath());
}
}
for (final Integer tile : tiles) {
writeNonEmptyFile(new File(cycleDir, "s_" + lane + "_" + tile + ext));
}
}
}
private static List<String> makeCycleFileList(final File dir, final String ext, final int lane, final int[] cycles, final int... tiles) {
return makeCycleFileList(dir, ext, lane, cycles, false, tiles);
}
private static List<String> makeCycleFileList(final File dir, final String ext, final int lane, final int[] cycles, final boolean longFmt, final int... tiles) {
final List<String> files = new ArrayList<String>();
final File laneDir = new File(dir, laneDir(lane));
for (final int cycle : cycles) {
final File cycleDir = new File(laneDir, "C" + cycle + ".1");
for (final Integer tile : tiles) {
files.add(cycleDir + "/s_" + lane + "_" + longTile(tile, longFmt) + ext);
}
}
return files;
}
private static void writeNonEmptyFile(final File file) {
try {
final OutputStream outputStream = new DataOutputStream(new FileOutputStream(file));
final int expectedLength = 10;
outputStream.write(expectedLength);
// The negative beginning index is to accommodate the header. Fancy. Ever so fancy.
for (int i = -3; i < expectedLength; i++) outputStream.write(0x0);
outputStream.close();
} catch (final IOException e) {
throw new RuntimeException("Exception trying to create non-empty file!", e);
}
}
private static String laneDir(final int lane) {
String ldir = String.valueOf(lane);
while (ldir.length() < 3) {
ldir = "0" + ldir;
}
return "L" + ldir;
}
private static String longTile(final int tile, final boolean makeLong) {
if (makeLong) {
String lt = String.valueOf(tile);
while (lt.length() < 4) {
lt = "0" + lt;
}
return lt;
} else {
return String.valueOf(tile);
}
}
private static String maybeAddExt(final String fileExt, final String compressionExt) {
if (compressionExt != null) {
return fileExt + compressionExt;
} else {
return fileExt;
}
}
}