/*
* Copyright (c) 2003-2012 Fred Hutchinson Cancer Research Center
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.fhcrc.cpl.toolbox.proteomics.feature.filehandler;
import org.fhcrc.cpl.toolbox.proteomics.feature.FeatureSet;
import org.fhcrc.cpl.toolbox.proteomics.feature.FeatureAsMap;
import org.fhcrc.cpl.toolbox.proteomics.feature.Feature;
import org.fhcrc.cpl.toolbox.proteomics.feature.extraInfo.FeatureExtraInformationDef;
import org.fhcrc.cpl.toolbox.filehandler.TabLoader;
import org.apache.log4j.Logger;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.FileOutputStream;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.util.Arrays;
/**
* File handler for native msInspect feature files
*/
public class NativeTSVFeatureFileHandler extends BaseFeatureSetFileHandler
implements FeatureSetFileHandler
{
static Logger _log = Logger.getLogger(NativeTSVFeatureFileHandler.class);
public static final String FILE_TYPE_NAME = "NATIVE_TSV";
protected static NativeTSVFeatureFileHandler singletonInstance = null;
public static NativeTSVFeatureFileHandler getSingletonInstance()
{
if (singletonInstance == null)
singletonInstance = new NativeTSVFeatureFileHandler();
return singletonInstance;
}
/**
* Load a FeatureSet
* @param file
* @return
* @throws IOException
*/
public FeatureSet loadFeatureSet(File file)
throws IOException
{
FeatureSet result = new FeatureSet();
TabLoader loader = new TabLoader(file, FeatureAsMap.class);
TabLoader.ColumnDescriptor[] cols = loader.getColumns();
Feature[] features = null;
//change the columns named "start" and "end" to scanFirst and scanLast,
//and make sure the setters get called.
//Also, register any known extra information types that we find for
//these columns
for (TabLoader.ColumnDescriptor col : cols)
{
if (col.name.equals("start"))
{
col.name = "scanFirst";
col.load = true;
}
else if (col.name.equals("end"))
{
col.name = "scanLast";
col.load = true;
}
//if this column indicates a known extra info type, register it
FeatureExtraInformationDef infoDef =
FeatureExtraInformationDef.getInfoTypeForColumn(col.name);
if (infoDef != null)
{
if (!result.hasExtraInformationType(infoDef))
{
result.addExtraInformationType(infoDef);
}
}
}
if (cols.length > 0)
{
features = (Feature[]) loader.load();
for (Feature feature : features)
feature.afterPopulate();
result.setFeatures(features);
}
for (FeatureExtraInformationDef infoType : result.getExtraInformationTypes())
_log.debug("Discovered extra information type " + infoType.getTextCode());
Map<String,String> commentsMap = (Map<String,String>) loader.getComments();
for (String commentKey : commentsMap.keySet())
{
String propertyValueString = commentsMap.get(commentKey);
_log.debug("Loading property " + commentKey + " = " + propertyValueString);
Object propertyValue = propertyValueString;
//if this property is known about by an extra info def, let the def handle it
Set<FeatureExtraInformationDef> infoDefsToTry = new HashSet<FeatureExtraInformationDef>();
infoDefsToTry.addAll(result.getExtraInformationTypes());
for (FeatureExtraInformationDef standardInfoDef : FeatureExtraInformationDef.getStandardExtraInformationTypes())
{
infoDefsToTry.add(standardInfoDef);
}
for (FeatureExtraInformationDef extraInfoDef : infoDefsToTry)
{
if (extraInfoDef.isThisTypeOfFeatureSetProperty(commentKey))
{
propertyValue =
extraInfoDef.convertFeatureSetPropertyStringValue(
extraInfoDef.stripPrefixFromFeatureSetPropertyName(commentKey),
propertyValueString);
_log.debug("\tproperty claimed by extrainfodef " + extraInfoDef.getTextCode() +
", class " + propertyValue.getClass().getName());
break;
}
}
result.setProperty(commentKey, propertyValue);
}
return result;
}
public void saveFeatureSet(FeatureSet featureSet, File outFile)
throws IOException
{
PrintWriter out = null;
assert null != featureSet.getFeatures();
try
{
out = new PrintWriter(new FileOutputStream(outFile));
saveFeatureSet(featureSet, out);
}
catch(IOException e)
{
throw e;
}
finally
{
if (out != null)
out.close();
}
}
/**
* Save a FeatureSet
* @param featureSet
* @param out
*/
public void saveFeatureSet(FeatureSet featureSet, PrintWriter out)
{
assert null != featureSet.getFeatures();
Set<?> keySet = featureSet.getProperties().keySet();
String[] keys = new String[keySet.size()];
int i = 0;
for (Object key : keySet)
keys[i++] = key.toString();
Arrays.sort(keys);
for (i = 0; i < keys.length; i++)
{
Object propertyValue = featureSet.getProperties().get(keys[i]);
//if this property is known about by an extra info def, let the def handle it
Set<FeatureExtraInformationDef> infoDefsToTry = new HashSet<FeatureExtraInformationDef>();
infoDefsToTry.addAll(featureSet.getExtraInformationTypes());
for (FeatureExtraInformationDef standardInfoDef :
FeatureExtraInformationDef.getStandardExtraInformationTypes())
{
infoDefsToTry.add(standardInfoDef);
}
for (FeatureExtraInformationDef extraInfoDef : infoDefsToTry)
{
if (extraInfoDef.isThisTypeOfFeatureSetProperty(keys[i]))
{
propertyValue =
extraInfoDef.convertFeatureSetPropertyToString(
extraInfoDef.stripPrefixFromFeatureSetPropertyName(keys[i]),
propertyValue);
break;
}
}
out.println("# " + keys[i] + "=" + propertyValue);
}
String header = Feature.getFeatureHeader(featureSet.getExtraInformationTypesArray());
if (dumpWindow)
header += "\twindow";
out.println(header);
out.flush();
Feature[] features = featureSet.getFeatures();
for (i = 0; i < features.length; i++)
{
out.print(features[i].toString(featureSet.getExtraInformationTypesArray()));
if (dumpWindow && null != features[i].intensityWindow)
out.print("\t" + join(features[i].intensityWindow, ","));
out.println();
}
out.flush();
}
// TODO: use StringUtils instead
private static String join(float[] f, String delim)
{
if ( null == f || 0 >= f.length )
return null;
StringBuffer sb = new StringBuffer();
sb.append("" + f[0]);
for(int i = 1; i < f.length; i++)
{
if ( null != delim)
sb.append(delim);
sb.append("" + f[i]);
}
return sb.toString();
}
/**
* Can this type of file handler handle this specific file?
* Implementation is up to the handler, but this should be as low-cost as possible
* @param file
* @return
* @throws IOException
*/
public boolean canHandleFile(File file)
throws IOException
{
if (isXMLFile(file))
return false;
//if it's not an XML file, give it a whirl, since this is the default handler
return true;
}
}