package org.fda.data;

import org.fda.data.Enums.CoverageType;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.fda.intervaltree.IntervalSearchTree;
/**
 *
 * @author Gokhan.Yavas
 */
public class Reference implements Comparable<Reference>, Serializable{
    private final String refID;
    private final long length;
    private final long gaplength;
    //private final ReferenceFile file;
    private final long gc_count;
    private final double gc_percent;
    private long coveredLength;
    private double coveragePerc;
    private double duplicationRatio;
    private long totalAlignedLength;
    private CoverageType cov_type=CoverageType.NONE;
    private static final long serialVersionUID = 8234343511122882189L;
    //private int id=-1;
    private long id=-1;
    private byte[] hashValue=null;
    private byte[] seqHashValue=null;
    private final IntervalSearchTree gapIntervalTree;

    
    //public Reference(String refID, long length, ReferenceFile file, long gc_count, double gc_percent, IntervalSearchTree gapIntervalTree, long gaplength){
    public Reference(String refID, long length, long gc_count, double gc_percent, IntervalSearchTree nIntervalsTree, long gaplength){
        this.refID = refID;
        this.length = length;
        //this.file = file;
        this.gc_count = gc_count;
        this.gc_percent = gc_percent;
        this.id = extractDigits(refID);
        this.gapIntervalTree = nIntervalsTree;
        this.gaplength = gaplength;
        
    }    
    //public Reference(String refID, long length, ReferenceFile file, long gc_count, double gc_percent, IntervalSearchTree gapIntervalTree, long gaplength, byte[] hashValue, byte[] seqHashValue){
    public Reference(String refID, long length, long gc_count, double gc_percent, IntervalSearchTree nIntervalsTree, long gaplength, byte[] hashValue, byte[] seqHashValue){
        //this(refID, length, file, gc_count, gc_percent, gapIntervalTree, gaplength);
        this(refID, length, gc_count, gc_percent, nIntervalsTree, gaplength);
        this.hashValue = hashValue;
        this.seqHashValue = seqHashValue;
    }
    public long getGaplength() {
        return gaplength;
    }
    public IntervalSearchTree getGapIntervalTree() {
        return gapIntervalTree;
    }

    public byte[] getSeqHashValue() {
        return seqHashValue;
    }

    public byte[] getHashValue() {
        return hashValue;
    }
    
    public CoverageType getCoverageType(){
        return cov_type;
    }
    public void setCoverageType(CoverageType c){
        cov_type =c ;
    }
    public long getTotalAlignedLength(){
        return this.totalAlignedLength;
    }
    public void setTotalAlignedLength(long totalAlignedLength){
        this.totalAlignedLength = totalAlignedLength;
        if(coveredLength>0)
            setDuplicationRatio((double)totalAlignedLength/(double)coveredLength);
        else
            setDuplicationRatio(Double.NaN);
    }
    public double getDuplicationRatio(){
        return this.duplicationRatio;
    }
    public void setDuplicationRatio(double duplicationRatio){
        this.duplicationRatio = duplicationRatio;
    }    
    public double getCoveragePerc(){
        return this.coveragePerc;
    }
    public void setCoveragePerc(double coveragePerc){
        this.coveragePerc = coveragePerc;
        setCoverageType(CoverageType.getCoverageType(coveragePerc));
    }
    public long getCoveredLength(){
        return this.coveredLength;
    }
    public void setCoveredLength(long coveredLength){
        this.coveredLength = coveredLength;
        setCoveragePerc(Utilities.calcPercentage(coveredLength, length));
        
    }
    
    public double getGCpercent(){
        return this.gc_percent;
    }
    public long getGCcount(){
        return this.gc_count;
    }    
    public long getLength(){
        return length;
    }
    public String getRefID(){
        return refID;
    }
    public String toString(){
        return refID;
    }
//    public ReferenceFile getFile(){
//        return file;
//    }
    public long getID(){
        return id;
    }
    private long extractDigits(String s){
        
        Pattern p = Pattern.compile("\\d+");
        Matcher m = p.matcher(s); 
        long max=-1;
        long curr;
        while (m.find()) {
            curr = Long.parseLong(m.group());
            if(curr > max)
                max = curr;
        }
        return max;
    }

    // This method is used for sorting
    @Override
    public int compareTo(Reference o) {
        //return refID.compareToIgnoreCase(o.getRefID());
        if(id==-1 && o.getID()==-1)
            return refID.compareToIgnoreCase(o.getRefID());
        else if(id==-1){
            return 1;
        }
        else if(o.getID()==-1){
            return -1;
        }
        else{
            return Long.compare(id, o.getID()) ;
        }
            
    }
    
    // This method compares if two references are pointing to the same object
    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Reference other = (Reference) obj;
        if (!Objects.equals(this.refID, other.refID)) {
            return false;
        }
        if (this.length != other.length) {
            return false;
        }
        return true;
    }
    public int hashCode(){
        return refID.hashCode();
    }
    
    // This method checks the sequences and names of the two references are same
    public boolean equalsTo(Reference r){
        return Arrays.equals(hashValue, r.getHashValue());
    }

    // This method checks the sequences of the two references are same
    public boolean seqEqualsTo(Reference r){
        return Arrays.equals(seqHashValue, r.getSeqHashValue());
    }

}

