package com.github.lindenb.jvarkit.tools.liftover;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import com.beust.jcommander.Parameter;
import com.github.lindenb.jvarkit.util.bio.bed.BedLine;
import com.github.lindenb.jvarkit.util.bio.bed.BedLineCodec;
import com.github.lindenb.jvarkit.util.jcommander.Launcher;
import com.github.lindenb.jvarkit.util.jcommander.Program;
import com.github.lindenb.jvarkit.util.log.Logger;
import htsjdk.samtools.liftover.LiftOver;
import htsjdk.samtools.reference.IndexedFastaSequenceFile;
import htsjdk.samtools.util.Interval;
import htsjdk.samtools.util.CloserUtil;
@Program(name="bedliftover",description="Lift-over a VCF file")
public class BedLiftOver extends Launcher
{
private static final Logger LOG = Logger.build(BedLiftOver.class).make();
@Parameter(names={"-o","--output"},description="Output file. Optional . Default: stdout")
private File outputFile = null;
@Parameter(names={"-f","--chain"},description="LiftOver file.",required=true)
private File liftOverFile = null;
@Parameter(names={"-x","--failed"},description=" write bed failing the liftOver here. Optional.")
private File failedFile = null;
@Parameter(names={"-m","--minmatch"},description="lift over min-match.")
private double userMinMatch = LiftOver.DEFAULT_LIFTOVER_MINMATCH ;
@Parameter(names={"-D","-R","-r","--reference"},description="indexed REFerence file.",required=true)
private File faidx = null;
@Parameter(names={"--chainvalid"},description="Ignore LiftOver chain validation")
private boolean ignoreLiftOverValidation=false;
private LiftOver liftOver=null;
private void scan(BufferedReader r,PrintWriter out,PrintWriter failed) throws IOException
{
String line;
final BedLineCodec bedCodec=new BedLineCodec();
while((line=r.readLine())!=null)
{
if(line.startsWith("#") || line.trim().isEmpty()) continue;
final BedLine bedLine = bedCodec.decode(line);
if(bedLine==null) continue;
final Interval srcInterval = bedLine.toInterval();
Interval dest=this.liftOver.liftOver(srcInterval);
if(dest!=null)
{
out.print(dest.getContig());
out.print('\t');
out.print(dest.getStart()-1);
out.print('\t');
out.print(dest.getEnd());
for(int i=3;i< bedLine.getColumnCount();++i) {
out.print('\t');
out.print(bedLine.get(i));
}
out.println();
}
else if(failed!=null)
{
failed.println(line);
}
}
}
@Override
public int doWork(List<String> args) {
if(liftOverFile==null)
{
LOG.error("LiftOver file is undefined.");
return -1;
}
this.liftOver=new LiftOver(liftOverFile);
this.liftOver.setLiftOverMinMatch(this.userMinMatch);
PrintWriter out=null;
PrintWriter failed=null;
try
{
if(!this.ignoreLiftOverValidation) {
IndexedFastaSequenceFile ref=new IndexedFastaSequenceFile(faidx);
this.liftOver.validateToSequences(ref.getSequenceDictionary());
ref.close();
}
out = super.openFileOrStdoutAsPrintWriter(this.outputFile);
if(this.failedFile!=null)
{
failed= super.openFileOrStdoutAsPrintWriter(failedFile);
}
if(args.isEmpty())
{
BufferedReader r= openBufferedReader(null);
scan(r,out,failed);
CloserUtil.close(r);
}
else
{
for(final String filename:args)
{
BufferedReader r=openBufferedReader(filename);
scan(r,out,failed);
CloserUtil.close(r);
}
}
out.flush();
out.close();
out=null;
if(failed!=null) {
failed.flush();
failed.close();
failed=null;
}
return 0;
}
catch(Exception err)
{
LOG.error(err);
return -1;
}
finally
{
CloserUtil.close(out);
CloserUtil.close(failed);
}
}
/**
* @param args
*/
public static void main(String[] args)
{
new BedLiftOver().instanceMainWithExit(args);
}
}