package com.illumina.basespace.igv.bam;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
import org.broad.igv.PreferenceManager;
import org.broad.igv.data.BasicScore;
import org.broad.igv.data.CoverageDataSource;
import org.broad.igv.feature.LocusScore;
import org.broad.igv.feature.genome.Genome;
import org.broad.igv.track.TrackType;
import org.broad.igv.track.WindowFunction;
import org.broad.igv.util.collections.LRUCache;
import com.illumina.basespace.entity.CoverageRecord;
import com.illumina.basespace.igv.BaseSpaceMain;
import com.illumina.basespace.igv.bam.BAMLocatorFactory.BAMTrackLoader;
import com.illumina.basespace.param.CoverageParams;
/**
*
* @author bking
*
*/
public class BaseSpaceCoverageDataSource implements CoverageDataSource
{
protected static Logger log = Logger.getLogger(BaseSpaceCoverageDataSource.class.getPackage().getName());
protected BAMTrackLoader locator;
protected int trackNumber = 0;
protected String trackName;
protected Genome genome;
protected WindowFunction windowFunction = WindowFunction.mean;
protected List<WindowFunction> availableFunctions;
protected boolean normalizeCounts = false;
protected int totalCount = 0;
protected float normalizationFactor = 1.0f;
protected LRUCache<String, List<LocusScore>> summaryScoreCache = new LRUCache<String, List<LocusScore>>(this, 2048);
protected int maxPrecomputedZoom = 15;
private String lastErrorChrZoom;
protected int coverage404MsgCount;
public BaseSpaceCoverageDataSource(BAMTrackLoader locator, int trackNumber, String trackName, Genome genome)
{
this.locator = locator;
this.genome = genome;
this.trackNumber = trackNumber;
this.trackName = trackName;
boolean normalizeCounts = PreferenceManager.getInstance().getAsBoolean(PreferenceManager.NORMALIZE_COVERAGE);
setNormalize(normalizeCounts);
}
public void setNormalize(boolean normalizeCounts)
{
setNormalizeCounts(normalizeCounts, 1.0e6f);
}
public void setNormalizeCounts(boolean normalizeCounts, float scalingFactor)
{
this.normalizeCounts = normalizeCounts;
if (normalizeCounts && totalCount > 0)
{
normalizationFactor = scalingFactor / totalCount;
}
else
{
normalizationFactor = 1;
}
}
public String getPath()
{
String path = "BaseSpace";
return path;
}
public String getTrackName()
{
return trackName;
}
public double getDataMax()
{
//61326
return 10;
}
public double getDataMin()
{
double val = 0;
return val;
}
public TrackType getTrackType()
{
TrackType type = TrackType.COVERAGE;
return type;
}
public void setWindowFunction(WindowFunction wf)
{
this.windowFunction = wf;
}
public boolean isLogNormalized()
{
return getDataMin() < 0;
}
public WindowFunction getWindowFunction()
{
return windowFunction;
}
public Collection<WindowFunction> getAvailableWindowFunctions()
{
return availableFunctions;
}
private List<LocusScore> getSummaryScoresFromAPI(String chr, int startLocation, int endLocation, int zoom)
{
ArrayList<LocusScore> scores = null;
try
{
if (lastErrorChrZoom != null && lastErrorChrZoom.equalsIgnoreCase(chr + "_" + zoom))
{
if (coverage404MsgCount < 10)
log.warning("Bypassing coverage API call for same chr/zoom which returned 404 in prior call");
else if (coverage404MsgCount == 10)
log.warning("Suppressing further warnings related to coverage API 404 error...");
coverage404MsgCount++;
return new ArrayList<LocusScore>();
}
if (chr != null && chr.trim().toLowerCase().indexOf("all") > -1)
{
return new ArrayList<LocusScore>();
}
// API errors out of 0 startLocation
if (startLocation == 0) startLocation = 1;
scores = new ArrayList<LocusScore>(1024);
CoverageParams params = new CoverageParams(startLocation, endLocation, zoom);
CoverageRecord record = BaseSpaceMain.instance().getApiClient(locator.getClientId())
.getCoverage(locator.getFile(), chr, params).get();
int index = 1;
double width = record.getBucketSize();
double scoreStart = record.getStartPosition();
for (float meanCoverage : record.getMeanCoverage())
{
double scoreEnd = scoreStart + width;
scores.add(new BasicScore((int) scoreStart, (int) scoreEnd, meanCoverage));
index++;
scoreStart = record.getStartPosition() + (index * width);
}
lastErrorChrZoom = null;
coverage404MsgCount = 0;
return scores;
}
catch (Throwable t)
{
lastErrorChrZoom = chr + "_" + zoom;
log.warning(t.getMessage());
return new ArrayList<LocusScore>();
}
}
public List<LocusScore> getSummaryScoresForRange(String chr, int startLocation, int endLocation, int zoom)
{
String key = chr + "_" + zoom + "_" + startLocation + "_" + endLocation;
List<LocusScore> scores = summaryScoreCache.get(key);
if (scores == null)
{
scores = this.getSummaryScoresFromAPI(chr, startLocation, endLocation, zoom);
summaryScoreCache.put(key, scores);
}
StringBuilder sb = new StringBuilder();
boolean first = true;
for (int i = 0; i < scores.size(); i++)
{
if (!first) sb.append(",");
sb.append(scores.get(i).getScore());
first = false;
}
return scores;
}
public boolean getNormalize()
{
return false;
}
}