package fr.ens.biologie.genomique.eoulsan.design.io;
import static fr.ens.biologie.genomique.eoulsan.design.io.Eoulsan1DesignReader.SAMPLE_NUMBER_FIELD;
import static fr.ens.biologie.genomique.eoulsan.design.io.Eoulsan2DesignReader.DESIGN_FORMAT_VERSION_METADATA_KEY;
import static fr.ens.biologie.genomique.eoulsan.design.io.Eoulsan2DesignReader.EQUAL_SEPARATOR;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import fr.ens.biologie.genomique.eoulsan.Globals;
/**
* This class allow to automatically detect the format of a design file.
* @author Laurent Jourdren
* @since 2.0
*/
public class DesignFormatFinderInputStream extends InputStream
implements AutoCloseable {
private InputStream is;
private static final int CACHE_SIZE = 5000;
private static final int MAX_LINES_TO_READ = 100;
private int versionFormat;
private boolean testFormatDone;
private int cacheIndex;
private byte[] cache;
/**
* Find the design format version.
* @return the design format version
* @throws IOException if an error occurs while finding the version
*/
private int findFormatVersion() throws IOException {
final byte[] readed = new byte[CACHE_SIZE];
int count = is.read(readed);
if (count != CACHE_SIZE) {
this.cache = new byte[count];
System.arraycopy(readed, 0, this.cache, 0, count);
} else {
this.cache = readed;
}
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(
new ByteArrayInputStream(this.cache), Globals.DEFAULT_CHARSET))) {
String line;
int lineCount = 0;
while (((line = reader.readLine()) != null)
&& lineCount < MAX_LINES_TO_READ) {
line = line.trim();
if ("".equals(line) || line.startsWith("#") || line.startsWith("[")) {
continue;
}
if (line.startsWith(SAMPLE_NUMBER_FIELD + "\t")) {
return 1;
}
if (line
.startsWith(DESIGN_FORMAT_VERSION_METADATA_KEY + EQUAL_SEPARATOR)) {
final int equalPos = line.indexOf(EQUAL_SEPARATOR);
final String version =
line.substring(equalPos + 1).replaceAll("\\s", "");
try {
return Integer.parseInt(version);
} catch (NumberFormatException e) {
throw new IOException("Unknown Design format version: " + version);
}
}
lineCount++;
}
}
return -1;
}
/**
* Get the format of the data to read.
* @return The format of the data to read
* @throws IOException if an error occurs while reading data
*/
public int getDesignFormatVersion() throws IOException {
if (!this.testFormatDone)
this.versionFormat = findFormatVersion();
return this.versionFormat;
}
/**
* Get the DesignReader for the data.
* @return the DesignReader for the data
* @throws IOException if an error occurs while reading data
*/
public DesignReader getDesignReader() throws IOException, IOException {
switch (getDesignFormatVersion()) {
case 1:
return new Eoulsan1DesignReader(this);
case 2:
return new Eoulsan2DesignReader(this);
default:
throw new IOException("Unknown Design format");
}
}
//
// InputStream methods
//
@Override
public int read() throws IOException {
if (this.cacheIndex == -1) {
return -1;
}
if (this.cacheIndex < this.cache.length)
return this.cache[this.cacheIndex++];
return this.is.read();
}
@Override
public void close() throws IOException {
this.is.close();
this.cacheIndex = -1;
}
//
// Constructor
//
/**
* Public constructor.
* @param is InputStream to read
*/
public DesignFormatFinderInputStream(final InputStream is) {
if (is == null) {
throw new NullPointerException("The inputStream is null");
}
this.is = is;
}
}