/*
* The MIT License (MIT)
*
* Copyright (c) 2007-2015 Broad Institute
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.broad.igv.tools.parsers;
//~--- non-JDK imports --------------------------------------------------------
import org.apache.log4j.Logger;
import org.broad.igv.Globals;
import org.broad.igv.data.WiggleDataset;
import org.broad.igv.data.WiggleParser;
import org.broad.igv.feature.genome.Genome;
import org.broad.igv.track.TrackProperties;
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.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Parses a wiggle file, as described by UCSC
* See http://genome.ucsc.edu/goldenPath/help/wiggle.html
* The data read in is added to a {@link DataConsumer}
*/
public class ToolsWiggleParser extends WiggleParser{
static private Logger log = Logger.getLogger(ToolsWiggleParser.class);
private DataConsumer dataConsumer;
// State variables. This is a serial type parser, these variables are used to hold temporary
// state.
String trackLine = null;
String nextLine = null;
public ToolsWiggleParser(String file, DataConsumer dataConsumer, Genome genome) {
super(new ResourceLocator(file), genome);
this.dataConsumer = dataConsumer;
parseHeader();
String[] trackNames = {resourceLocator.getTrackName()};
// TODO -- total hack to get Manuel's file parsed quickly. Revisit (obviously);
if (resourceLocator.getPath().endsWith(".ewig") || resourceLocator.getPath().endsWith(".ewig.gz")
|| resourceLocator.getPath().endsWith("ewig.map")) {
trackNames = new String[5];
trackNames[4] = resourceLocator.getTrackName();
trackNames[0] = "A";
trackNames[1] = "C";
trackNames[2] = "G";
trackNames[3] = "T";
}
dataConsumer.setTrackParameters(TrackType.OTHER, trackLine, trackNames);
// Parse track line, if any, to get the coordinate convention
if (trackLine != null) {
TrackProperties props = new TrackProperties();
ParsingUtils.parseTrackLine(trackLine, props);
TrackProperties.BaseCoord convention = props.getBaseCoord();
if (convention == TrackProperties.BaseCoord.ZERO) {
startBase = 0;
}
}
}
/**
* @return the dataConsumer
*/
public DataConsumer getDataConsumer() {
return dataConsumer;
}
/**
* Utility method. Returns true if this looks like a wiggle locator. The criteria is to scan
* the first 100 lines looking for a valid "track" line. According to UCSC documentation
* track lines must contain a type attribute, which must be equal to "wiggle_0".
*
* @param file
* @return
*/
public static boolean isWiggle(ResourceLocator file) {
AsciiLineReader reader = null;
try {
reader = ParsingUtils.openAsciiReader(file);
String nextLine = null;
int lineNo = 0;
while ((nextLine = reader.readLine()) != null && (nextLine.trim().length() > 0)) {
if (nextLine.startsWith("track") && nextLine.contains("wiggle_0")) {
return true;
}
if (lineNo++ > 100) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
if (reader != null) {
reader.close();
}
}
return false;
}
private void parseHeader() {
AsciiLineReader reader = null;
// The DataConsumer interface takes an array of data per position, however wig
// files contain a single data point. Create an "array" once that can
// be resused
try {
reader = ParsingUtils.openAsciiReader(resourceLocator);
while ((nextLine = reader.readLine()) != null && (nextLine.trim().length() > 0)) {
// Skip comment lines
if (nextLine.startsWith("#") || nextLine.startsWith("data") || nextLine.startsWith(
"browser") || nextLine.trim().length() == 0) {
continue;
}
if (nextLine.startsWith("track")) {
trackLine = nextLine;
} else {
return;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Parse Wiggle file into the DataConsumer
* @return null
* @throws IOException
*/
@Override
public WiggleDataset parse(){
lastPosition = -1;
unsortedChromosomes = new HashSet();
if (resourceLocator.getPath().endsWith("ewig.map")) {
startBase = 0;
windowSpan = 1;
type = Type.VARIABLE;
String parent = new File(resourceLocator.getPath()).getParent();
Map<String, String> fileMap = null;
try {
fileMap = parseEwigList(resourceLocator.getPath());
} catch (IOException e) {
log.error(e.getMessage(), e);
throw new RuntimeException(e);
}
for (Map.Entry<String, String> entry : fileMap.entrySet()) {
chr = entry.getKey();
File f = new File(parent, entry.getValue());
parseFile(new ResourceLocator(f.getAbsolutePath()));
}
} else {
parseFile(resourceLocator);
}
parsingComplete();
return null;
}
private Map<String, String> parseEwigList(String path) throws IOException {
BufferedReader reader = null;
try {
reader = ParsingUtils.openBufferedReader(path);
String nextLine;
LinkedHashMap<String, String> fileMap = new LinkedHashMap();
while ((nextLine = reader.readLine()) != null) {
String[] tokens = Globals.whitespacePattern.split(nextLine);
fileMap.put(tokens[0], tokens[1]);
}
return fileMap;
} finally {
if (reader != null) reader.close();
}
}
@Override
protected void changedChromosome(WiggleDataset dataset, String lastChr) {
lastPosition = -1;
}
@Override
protected void parsingComplete() {
getDataConsumer().parsingComplete();
}
float[] buffer = new float[1];
@Override
public void addData(String chr, int start, int end, float value) {
buffer[0] = value;
addData(chr, start, end, buffer);
}
@Override
public void addData(String chr, int start, int end, float[] values) {
getDataConsumer().addData(chr, start, end, values, null);
}
}