package com.github.lindenb.jvarkit.util.picard;
import htsjdk.samtools.reference.ReferenceSequenceFile;
import htsjdk.samtools.CigarElement;
import htsjdk.samtools.CigarOperator;
import htsjdk.samtools.SAMRecord;
public class CigarIterator
{
private SAMRecord record;
private int refPos=0;
private int readPos=0;
private int displayRefPos=0;
private int displayReadPos=0;
private int cigardElementIndex=0;
private int indexInCigarElement=-1;
private ReferenceSequenceFile referenceSequenceFile;
public boolean next()
{
if(getSAMRecord().getReadUnmappedFlag()) return false;
if(getSAMRecord().getCigar()==null) return false;
for(;;)
{
if(this.cigardElementIndex >= getSAMRecord().getCigar().getCigarElements().size())
{
return false;
}
this.indexInCigarElement++;
final CigarElement ce= getSAMRecord().getCigar().getCigarElement(this.cigardElementIndex);
if(this.indexInCigarElement>= ce.getLength() )
{
this.cigardElementIndex++;
this.indexInCigarElement=-1;
continue;
}
displayRefPos=-1;
displayReadPos=-1;
switch(ce.getOperator())
{
case H:break;
case S:break;
case I:
{
this.displayReadPos= this.readPos;
this.readPos++;
break;
}
case D:
case N:
case P:
{
this.displayRefPos= this.refPos;
this.refPos++;
break;
}
case M:
case EQ:
case X:
{
this.displayReadPos= this.readPos;
this.displayRefPos= this.refPos;
this.readPos++;
this.refPos++;
break;
}
default: throw new IllegalStateException(
"Doesn't know how to handle cigar operator:"+ce.getOperator()+
" cigar:"+getSAMRecord().getSAMString()
);
}
return true;
}
}
public void reset()
{
this.readPos=0;
this.refPos=record.getUnclippedStart();
this.displayRefPos=-1;
this.displayReadPos=-1;
this.cigardElementIndex=0;
this.indexInCigarElement=-1;
}
public SAMRecord getSAMRecord()
{
return record;
}
public int getReferencePosition()
{
return displayRefPos;
}
public int getReadPosition()
{
return displayReadPos;
}
public Character getReadBase()
{
return this.displayReadPos==-1?null:(char)getSAMRecord().getReadBases()[this.displayReadPos];
}
public Integer getReadQual()
{
byte quals[]=getSAMRecord().getBaseQualities();
return this.displayReadPos==-1 ||
quals==null ||
quals.length==0
?null:(int)getSAMRecord().getBaseQualities()[this.displayReadPos];
}
public Character getReferenceBase()
{
if(this.referenceSequenceFile==null || this.displayRefPos==-1)
{
return null;
}
if(getSAMRecord().getReadUnmappedFlag()) return null;
String tid=getSAMRecord().getReferenceName();
if(tid==null) return null;
return (char)this.referenceSequenceFile.getSubsequenceAt(
tid, this.displayRefPos,this.displayRefPos
).getBases()[0];
}
/** return true if : we can get base of read AND reference AND both upper(bases) are the same */
public boolean isBaseMatching()
{
Character c1=getReadBase();
if(c1==null) return false;
Character c2=getReferenceBase();
if(c2==null) return false;
return Character.toUpperCase(c1)==Character.toUpperCase(c2);
}
/** return true if : we can get base of read AND reference AND both upper(bases) are NOT the same */
public boolean isBaseMismatching()
{
Character c1=getReadBase();
if(c1==null) return false;
Character c2=getReferenceBase();
if(c2==null) return false;
return Character.toUpperCase(c1)!=Character.toUpperCase(c2);
}
public CigarElement getCigarElement()
{
return getSAMRecord().getCigar().getCigarElement(cigardElementIndex);
}
public CigarOperator getCigarOperator()
{
return getCigarElement().getOperator();
}
static public CigarIterator create(
SAMRecord record,
ReferenceSequenceFile ref
)
{
CigarIterator iter=new CigarIterator();
iter.record=record;
iter.refPos=record.getUnclippedStart();
iter.referenceSequenceFile=ref;
return iter;
}
}