package org.fda.alignment;

import java.text.NumberFormat;
import org.fda.data.Enums.Orientation;
import org.fda.data.Reference;
import org.fda.data.Utilities;
import org.fda.exceptions.IllegalIntervalException;
import java.io.Serializable;
import org.fda.intervaltree.Interval;

/**
 *
 * @author Gokhan.Yavas
 */
public class Alignment implements Comparable<Alignment>, Serializable{
    protected final Reference reference;    
    protected Interval contigInterval, referenceInterval;
    protected double id;
    protected Orientation refOr, contigOr;
    protected boolean startTrimmed, endTrimmed;
    private static final long serialVersionUID = 112414357102382689L;
    
    
    public Alignment(Reference refID, int s_Ref, int e_Ref, int s_Cont, int e_Cont, double id ) throws IllegalIntervalException{    
        
        this.reference = refID;
        this.id = id/100;
        // Set the orientation for this alignment
        refOr = s_Ref <= e_Ref ? Orientation.F : Orientation.R;
        contigOr = s_Cont <= e_Cont ? Orientation.F : Orientation.R;
        startTrimmed = false;
        endTrimmed = false;
        // now swap the coordinates if needed        
        referenceInterval = new Interval((refOr==Orientation.F)?s_Ref:e_Ref, (refOr==Orientation.F)?e_Ref:s_Ref, false);
        contigInterval = new Interval((contigOr==Orientation.F)?s_Cont:e_Cont, (contigOr==Orientation.F)?e_Cont:s_Cont, false);
        
    }
    public boolean getStTrimmed(){
        return startTrimmed;
    }
    public boolean getEndTrimmed(){
        return endTrimmed;
    }    
    public Orientation getRefOrientation(){
        return refOr;
    }
    public Orientation getContigOrientation(){
        return contigOr;
    }
    public void setRefOrientation(Orientation o){
        refOr=o;
    }
    public void setContigOrientation(Orientation o){
        contigOr=o;
    }
    
    private void setRefSt(int s_Ref) throws IllegalIntervalException{
        this.referenceInterval.setlow(s_Ref);
    }
    private void setRefEnd(int e_Ref) throws IllegalIntervalException{
        this.referenceInterval.sethigh(e_Ref);
    }
    public void swapStartEndOnContig() throws IllegalIntervalException{
        int lo = contigInterval.getlow();
        contigInterval.setlow(contigInterval.gethigh());
        contigInterval.sethigh(lo);
    }
    public void _setContSt(int st) throws IllegalIntervalException{
        contigInterval.setlow(st);
    }
    public void _setContEnd(int end) throws IllegalIntervalException{
        contigInterval.sethigh(end);
    }
            
    public void setContEnd(int e_Cont) throws IllegalIntervalException{
        endTrimmed = true;
        int displacement = e_Cont - this.contigInterval.gethigh(); 
        contigInterval.sethigh(e_Cont);      
        // adjust the reference end based on the orientation
        if(contigOr==Orientation.F)
            referenceInterval.sethigh(referenceInterval.gethigh() + displacement);            
        else
            referenceInterval.setlow(referenceInterval.getlow() - displacement);
    }
    public void setContSt(int s_Cont) throws IllegalIntervalException{
        startTrimmed = true;
        int displacement = s_Cont - contigInterval.getlow();
        contigInterval.setlow(s_Cont);
        // adjust the reference st based on the orientation
        if(contigOr==Orientation.F)
            referenceInterval.setlow(referenceInterval.getlow() + displacement);
        else
            referenceInterval.sethigh(referenceInterval.gethigh() - displacement);        
    }    

    public int getRefSt(){
        return referenceInterval.getlow();
    }
    public int getRefEnd(){
        return referenceInterval.gethigh();        
    }
    public int getContEnd(){
        return contigInterval.gethigh();
    }
    public int getContSt(){
        return contigInterval.getlow();
    }
    public Interval getReferenceInterval(){
        return this.referenceInterval;
    }
    public Interval getContigInterval(){
        return this.contigInterval;
    }
    public Reference getReference(){
        return reference;
    }
    public double getIdentity(){
        return id;
    }
    public int getRefAlignmentLength(){
        return referenceInterval.getlength();
    }
    public int getContigAlignmentLength(){
        return contigInterval.getlength();
    }
    public int overlapContig(Alignment a){
        return contigInterval.overlap(a.getContigInterval());
    }
    public int overlapRef(Alignment a){
        return referenceInterval.overlap(a.getReferenceInterval());
    }

    
    @Override
    public String toString(){
        NumberFormat nr = Utilities.numberFormatter;
        StringBuilder sb= new StringBuilder();
        String ref_frame = refOr.toString();
        String contig_frame = contigOr.toString();          
        sb.append("\t"+reference.getRefID()+"\t"+nr.format(referenceInterval.getlow())+"\t"+nr.format(referenceInterval.gethigh())+"\t"+ref_frame+"\t"+
                nr.format(contigInterval.getlow())+"\t"+nr.format(contigInterval.gethigh())+"\t"+contig_frame+"\t"+nr.format(id*100)+"\t"+startTrimmed+"\t"+endTrimmed);                
        
        return sb.toString();
    }

    @Override
    public int compareTo(Alignment o) {
        return getReferenceInterval().compareTo(o.getReferenceInterval());
//        return getContigInterval().compareTo(o.getContigInterval());
    }
}
