
package org.fda.alignment;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import org.fda.basicstats.BasicStatsComputeFromList;
import org.fda.data.Reference;
import org.fda.data.Utilities;

/**
 *
 * @author Gokhan.Yavas
 */
public class AlignmentFilterG extends AlignmentFilter{

    public AlignmentFilterG(BlockingQueue queue, int no,  BlockingQueue oqueue) {
        super(queue, oqueue);
        id = "GlobalFilter"+no;
    }
    public AlignmentFilterG(BlockingQueue queue, int no,  BlockingQueue oqueue, BasicStatsComputeFromList bsc) {
        super(queue, oqueue, bsc);
        id = "GlobalFilter"+no;
    }
    
    private int RevC (int coord, int len){
        return len - coord + 1;
    }
    private double score(List<Alignment> alignments){
        double sum =0;
        for(Alignment a : alignments){
            sum = sum + a.getIdentity() * a.getRefAlignmentLength();
        }
        return sum;
    }
    @Override
    public void filter(ScaffoldContig as){
        List<Alignment>  a2ret = new ArrayList<>();
        List<Alignment>  tmp;
        double best =0;
        double curr;
        int i;
        for(Reference c: as.getReferences()){
            tmp =filterU(as, c);
            curr = score(tmp);
            if(curr > best){
                a2ret = tmp;
                best = curr;
            }
        }
        setAlignments(as, a2ret);
                
    }
    
    private List<Alignment> filterU(ScaffoldContig as, Reference c){
          
        int i, j, n;
        int olap, olapR, olapQ, lenR, lenQ, len;
        long score, diff;

        AlignmentWrapper[] lis = this.createAlignmentWrappers(as.getAlignments(c)).toArray(new AlignmentWrapper[0]);        

        n = lis.length;
          //-- Continue until all equivalent repeats are extracted
        List<Integer> allbest = new ArrayList<>();
        do{          
        //-- Dynamic
            for ( i = 0; i < n; ++ i ){
                if(lis[i].getUsed()) 
                    continue;
                lenR = lis[i].getAlign().getRefAlignmentLength();
                lenQ = lis[i].getAlign().getContigAlignmentLength();
                len = lenR > lenQ ? lenQ : lenR;
            
                lis[i].setScore(Utilities.scoreGlobal (0, len, 0, lis[i].getAlign().getIdentity()));
                lis[i].setFrom(-1);
                lis[i].setDiff( 0);
            
                for ( j = 0; j < i; ++ j ){
                    if ( lis[j].getUsed() )
                        continue;
                    if ( lis[i].getAlign().getContigOrientation()!=lis[j].getAlign().getContigOrientation() )
                        continue;
                    olapQ = lis[j].getAlign().overlapContig(lis[i].getAlign());
                    olapR = lis[j].getAlign().overlapRef(lis[i].getAlign());
                    olap = olapR > olapQ ? olapR : olapQ;
                    if ( olap < 0 )
                        olap = 0;
                    diff = lis[j].getDiff() + diffAligns (lis[i].getAlign(), lis[j].getAlign());
//                    score = Utilities.scoreGlobal(lis[j].getScore(), len, olap, lis[i].getAlign().getIdentity());
                    score = Utilities.scoreGlobal2(lis[j].getScore(), lenR, lenQ, lis[j].getAlign().getRefAlignmentLength(), lis[j].getAlign().getContigAlignmentLength(), olapR, olapQ, lis[i].getAlign().getIdentity(), Utilities.maxOverlap);
                    
                    if ( score > lis[i].getScore() || (score == lis[i].getScore() && diff < lis[i].getDiff()) || 
                            (score == lis[i].getScore() && diff == lis[i].getDiff() && 
                            Arrays.equals(lis[j].getAlign().getReference().getSeqHashValue(), as.getSeqHashValue()))){

                        lis[i].setFrom( j);
                        lis[i].setScore(score);
                        lis[i].setDiff(diff);
                    }
                }
            }
        } while ( updateBest (lis, n, allbest, Utilities.epsilon) );
        //int beg = pickBest (lis, allbest, Utilities.epsilon);
        int beg =0;
        int end = allbest.size();
        if ( beg == end ) beg = 0;
        else end = beg + 1;
        List<Alignment> a2ret = new ArrayList();
        for ( ; beg < end; ++ beg )
            for( i = allbest.get(beg); i >= 0  &&  i < n; i = lis[i].getFrom() ){
                a2ret.add(lis[i].getAlign());              
            }
        return a2ret;
    }        
    
}
