package com.illumina.basespace.igv.bam;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import net.sf.samtools.SAMFileHeader;
import net.sf.samtools.SAMFileReader;
import net.sf.samtools.SAMRecord;
import net.sf.samtools.SAMSequenceRecord;
import net.sf.samtools.seekablestream.SeekableBufferedStream;
import net.sf.samtools.seekablestream.SeekableStream;
import net.sf.samtools.util.CloseableIterator;
import org.broad.igv.DirectoryManager;
import org.broad.igv.sam.Alignment;
import org.broad.igv.sam.reader.AlignmentReader;
import org.broad.igv.sam.reader.AlignmentReaderFactory;
import org.broad.igv.sam.reader.WrappedIterator;
import org.broad.igv.util.ResourceLocator;
import com.illumina.basespace.ApiClient;
import com.illumina.basespace.igv.BaseSpaceMain;
import com.illumina.basespace.igv.bam.BAMLocatorFactory.BAMTrackLoader;
import com.illumina.basespace.igv.io.BaseSpaceSeekableFileStream;
/**
*
* @author bking
*
*/
public class BaseSpaceBAMHttpReader implements AlignmentReader
{
static Logger log = Logger.getLogger(BaseSpaceBAMHttpReader.class.getPackage().getName());
// Length of day in milliseconds
public static final long oneDay = 24 * 60 * 60 * 1000;
static Hashtable<String, File> indexFileCache = new Hashtable<String, File>();
private SAMFileHeader header;
private File indexFile;
private SAMFileReader reader;
private List<String> sequenceNames;
private BAMTrackLoader locator;
public BaseSpaceBAMHttpReader(ResourceLocator locator) throws IOException
{
try
{
this.locator = (BAMTrackLoader)locator;
indexFile = getIndexFile();
if (indexFile == null)
{
throw new RuntimeException("Could not load index file for file: " + this.locator.getFile().getName());
}
reader = new SAMFileReader(getSeekableStream(),indexFile,false);
}
catch(Throwable t)
{
t.printStackTrace();
throw new RuntimeException(t);
}
}
public void close() throws IOException
{
if (reader != null)
{
reader.close();
}
}
public SAMFileHeader getHeader()
{
if (header == null)
{
header = reader.getFileHeader();
}
return header;
}
public Set<String> getPlatforms()
{
return AlignmentReaderFactory.getPlatforms(getHeader());
}
public boolean hasIndex()
{
return indexFile != null && indexFile.exists();
}
public List<String> getSequenceNames()
{
if (sequenceNames == null)
{
SAMFileHeader header = getHeader();
if (header == null)
{
return null;
}
sequenceNames = new ArrayList<String>();
List<SAMSequenceRecord> records = header.getSequenceDictionary().getSequences();
if (records.size() > 0)
{
for (SAMSequenceRecord rec : header.getSequenceDictionary().getSequences())
{
String chr = rec.getSequenceName();
sequenceNames.add(chr);
}
}
}
return sequenceNames;
}
public CloseableIterator<Alignment> iterator()
{
try
{
if (reader == null)
{
reader = new SAMFileReader(getSeekableStream(),indexFile,false);
}
return new WrappedIterator(reader.iterator());
}
catch (IOException e)
{
log.severe("Error creating iterator" + e.toString());
throw new RuntimeException(e);
}
}
public CloseableIterator<Alignment> query(String sequence, int start, int end, boolean contained)
{
try
{
if (reader == null)
{
reader = new SAMFileReader(getSeekableStream(),indexFile,false);
}
//log.fine("Query reader for sequence " + sequence + ",start=" + start + ",end=" + end + ",contained=" + contained);
CloseableIterator<SAMRecord> iter = reader.query(sequence, start + 1, end, contained);
return new WrappedIterator(iter);
}
catch (IOException e)
{
log.severe("Error opening SAM reader" + e.toString());
throw new RuntimeException("Error opening SAM reader", e);
}
}
private SeekableStream getSeekableStream() throws IOException
{
return new SeekableBufferedStream(new BaseSpaceSeekableFileStream(locator,locator.getFile()));
}
/**
* Delete temporary files which are older than timeLimit.
*
* @param timeLimit
* Minimum age (in milliseconds) to delete. If null, default is 1
* day
* @throws IOException
*/
public static void cleanTempDir(Long timeLimit)
{
if (timeLimit == null)
{
timeLimit = oneDay;
}
File dir = DirectoryManager.getCacheDirectory();
File[] files = dir.listFiles();
long time = System.currentTimeMillis();
for (File f : files)
{
long age = time - f.lastModified();
if (age > timeLimit)
{
f.delete();
}
}
}
protected File getIndexFile() throws IOException
{
try
{
indexFile = getTmpIndexFile();
// Crude staleness check -- if more than a day old discard
long age = System.currentTimeMillis() - indexFile.lastModified();
if (age > oneDay)
{
indexFile.delete();
}
if (!indexFile.exists() || indexFile.length() < 1)
{
log.info("Downloading index file from BaseSpace->" + locator.getBaiFile().getName());
ApiClient client = BaseSpaceMain.instance().getApiClient(locator.getClientId());
client.download(locator.getBaiFile(), indexFile,null);
indexFile.deleteOnExit();
}
return indexFile;
}
catch(Throwable t)
{
t.printStackTrace();
throw new RuntimeException(t);
}
}
private File getTmpIndexFile() throws IOException
{
File indexFile = indexFileCache.get(locator.getFile().getId());
if (indexFile == null)
{
indexFile = File.createTempFile("index_", ".bai", DirectoryManager.getCacheDirectory());
indexFile.deleteOnExit();
log.fine("Create index file=" + indexFile);
indexFileCache.put(locator.getFile().getId(), indexFile);
}
else
{
log.fine("Use cached index file=" + indexFile);
}
return indexFile;
}
}