/*
* Copyright (c) 2007-2012 The Broad Institute, Inc.
* SOFTWARE COPYRIGHT NOTICE
* This software and its documentation are the copyright of the Broad Institute, Inc. All rights are reserved.
*
* This software is supplied without any warranty or guaranteed support whatsoever. The Broad Institute is not responsible for its use, misuse, or functionality.
*
* This software is licensed under the terms of the GNU Lesser General Public License (LGPL),
* Version 2.1 which is available at http://www.opensource.org/licenses/lgpl-2.1.php.
*/
package org.broad.igv.dev;
import org.apache.log4j.Logger;
import org.broad.igv.Globals;
import org.broad.igv.data.seg.SegmentedAsciiDataSet;
import org.broad.igv.dev.db.DBManager;
import org.broad.igv.dev.db.DBProfile;
import org.broad.igv.dev.db.WholeTableDBReader;
import org.broad.igv.exceptions.ParserException;
import org.broad.igv.feature.genome.Genome;
import org.broad.igv.track.TrackType;
import org.broad.igv.util.ParsingUtils;
import org.broad.igv.util.ResourceLocator;
import htsjdk.tribble.readers.AsciiLineReader;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* Experimental class to explore using the same class as a reader for
* both a SQL DB and a file.
*
* @author Jacob Silterra
* @date 2012 Aug 30
*/
public class SegmentedReader {
private static Logger log = Logger.getLogger(SegmentedReader.class);
private Genome genome;
private SegmentedAsciiDataSet dataset;
private String[] headings;
private boolean birdsuite = false;
private int sampleColumn = 0;
private int chrColumn = 1;
private int startColumn = 2;
private int endColumn = 3;
//int snpCountColumn = 4; // Default value
private int dataColumn = 5;
private ResourceLocator locator;
enum Type {
SEG, BIRDSUITE, NEXUS
}
private class SegmentedDBReader extends WholeTableDBReader<SegmentedAsciiDataSet> {
private SegmentedDBReader(DBProfile.DBTable table) {
super(table);
}
@Override
protected SegmentedAsciiDataSet processResultSet(ResultSet rs) throws SQLException {
IParser<ResultSet, Integer> parser = IParserFactory.getIndexParser(rs);
readHeader(rs);
while (rs.next()) {
parseLine(parser, rs);
}
DBManager.closeAll(rs);
dataset.sortLists();
return dataset;
}
private int readHeader(ResultSet rs) throws SQLException {
dataset = new SegmentedAsciiDataSet(genome);
/*sampleColumn = 0;
chrColumn = 1;
startColumn = 2;
endColumn = 3;*/
dataColumn = rs.getMetaData().getColumnCount() - 1;
headings = new String[rs.getMetaData().getColumnCount()];
for (int cc = 0; cc < rs.getMetaData().getColumnCount(); cc++) {
headings[cc] = rs.getMetaData().getColumnLabel(cc + 1);
}
return 0;
}
}
public SegmentedReader(ResourceLocator locator) {
this(locator, null);
}
public SegmentedReader(ResourceLocator locator, Genome genome) {
this.locator = locator;
this.genome = genome;
if (locator.getPath().toLowerCase().endsWith("birdseye_canary_calls")) {
birdsuite = true;
}
}
/**
* Load segmented data from a file could be remote)
* Return a map of trackId -> segment datasource
*
* @return
*/
public SegmentedAsciiDataSet loadFromFile() {
dataset = new SegmentedAsciiDataSet(genome);
if (birdsuite) {
dataset.setTrackType(TrackType.CNV);
}
AsciiLineReader reader = null;
String nextLine = null;
int lineNumber = 0;
IParser<String[], Integer> parser = IParserFactory.getIndexParser(new String[0]);
try {
reader = ParsingUtils.openAsciiReader(locator);
lineNumber = readHeader(reader);
while ((nextLine = reader.readLine()) != null && (nextLine.trim().length() > 0)) {
lineNumber++;
String[] tokens = Globals.tabPattern.split(nextLine, -1);
parseLine(parser, tokens);
}
} catch (IOException e) {
if (nextLine != null && lineNumber != 0) {
throw new ParserException(e.getMessage(), e, lineNumber, nextLine);
} else {
throw new RuntimeException(e);
}
} finally {
if (reader != null) {
reader.close();
}
}
dataset.sortLists();
return dataset;
}
public SegmentedAsciiDataSet loadFromDB(DBProfile.DBTable table) {
SegmentedDBReader reader = new SegmentedDBReader(table);
return reader.load();
}
/**
* Note: This is an exact copy of the method in ExpressionFileParser. Refactor to merge these
* two parsers, or share a common base class.
*
* @param comment
* @param dataset
*/
private void parseComment(String comment, SegmentedAsciiDataSet dataset) {
String tmp = comment.substring(1, comment.length());
if (tmp.startsWith("track")) {
ParsingUtils.parseTrackLine(tmp, dataset.getTrackProperties());
} else {
String[] tokens = tmp.split("=");
String key = tokens[0].trim().toLowerCase();
if (key.equals("type")) {
if (tokens.length != 2) {
return;
}
try {
dataset.setTrackType(TrackType.valueOf(tokens[1].trim().toUpperCase()));
} catch (Exception exception) {
log.error("Unknown track type: " + tokens[1].trim().toUpperCase());
}
}
}
}
private int readHeader(AsciiLineReader reader) throws IOException {
// Parse comments, if any
String nextLine = reader.readLine();
int lineNumber = 0;
while (nextLine.startsWith("#") || (nextLine.trim().length() == 0)) {
lineNumber++;
if (nextLine.length() > 0) {
parseComment(nextLine, dataset);
}
nextLine = reader.readLine();
}
// Read column headings
headings = nextLine.split("\t");
if (birdsuite) {
//sample sample_index copy_number chr start end confidence
sampleColumn = 0;
dataColumn = 2;
chrColumn = 3;
startColumn = 4;
endColumn = 5;
} else {
sampleColumn = 0;
chrColumn = 1;
startColumn = 2;
endColumn = 3;
dataColumn = headings.length - 1;
}
return lineNumber;
}
private <TContainer> void parseLine(IParser<TContainer, Integer> parser, TContainer rs) throws ParserException {
int nTokens = parser.size(rs);
if (nTokens > 4) {
String sample = parser.getString(rs, sampleColumn);
String chr = parser.getString(rs, chrColumn);
int start = parser.getInt(rs, startColumn);
int end = parser.getInt(rs, endColumn);
float value = parser.getFloat(rs, dataColumn);
if (genome != null) {
chr = genome.getChromosomeAlias(chr);
}
String trackId = sample;
StringBuffer desc = null;
if (birdsuite) {
desc = new StringBuffer();
desc.append("<br>");
desc.append(headings[6]);
desc.append("=");
desc.append(parser.getString(rs, 6));
} else {
if (nTokens > 4) {
desc = new StringBuffer();
for (int i = 4; i < parser.size(rs) - 1; i++) {
desc.append("<br>");
desc.append(headings[i]);
desc.append(": ");
desc.append(parser.getString(rs, i));
}
}
}
String description = desc == null ? null : desc.toString();
dataset.addSegment(trackId, chr, start, end, value, description);
}
}
}