package org.fda.alignmentparser.paf;

import java.io.BufferedInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import org.fda.alignment.ScaffoldContig;
import org.fda.alignment.NucmerAlignment;
import org.fda.alignmentparser.AlignmentReaderRunnable;
import org.fda.basicstats.ContigRecord;
import org.fda.data.Enums.Orientation;
import org.fda.data.ReferenceSet;
import org.fda.data.Utilities;
import org.fda.exceptions.IllegalIntervalException;

/**
 *
 * @author Gokhan.Yavas
 */
public class PafReaderRunnable extends AlignmentReaderRunnable{
    private PafFileReader pfr;   
    private final File sourceFolder;
    
    public PafReaderRunnable(BlockingQueue inqueue, BlockingQueue outqueue, ReferenceSet ch, int no, File sourceFolder){
        super(inqueue, outqueue, ch, no);
        pfr = new PafFileReader();
        this.sourceFolder = sourceFolder;
    }
    
    private NucmerAlignment createNucmerAlignment(PafRecord r) throws IllegalIntervalException{
        Cigar cig = r.getCigar();
        List<Integer> deltas = new ArrayList();
        CigarElement cigPrev=null;        
        for(CigarElement cigTmp : cig){
            if(cigTmp.getOperator() == CigarOperator.HARD_CLIP || cigTmp.getOperator() == CigarOperator.SOFT_CLIP){
                // continue
                continue;
            }
            else if(cigTmp.getOperator() == CigarOperator.DELETION){
                if(cigPrev==null){
                    deltas.add(1);
                }
                else if(cigPrev.getOperator()==CigarOperator.MATCH_OR_MISMATCH){
                    deltas.add(cigPrev.getLength()+1);
                }                
                if(cigTmp.getLength()>1){
                    for(int k=0; k<cigTmp.getLength()-1; k++)
                        deltas.add(1);
                }
            }
            else if(cigTmp.getOperator() == CigarOperator.INSERTION){
                if(cigPrev==null){
                    deltas.add(-1);
                }                
                else if(cigPrev!=null && cigPrev.getOperator()==CigarOperator.MATCH_OR_MISMATCH){
                    deltas.add(-(cigPrev.getLength()+1));
                }                
                if(cigTmp.getLength()>1){
                    for(int k=0; k<cigTmp.getLength()-1; k++)
                        deltas.add(-1);
                }                
            }            
            cigPrev = cigTmp;
        }
        int[] del = new int[deltas.size()];
        for(int j=0; j<deltas.size(); j++)
            del[j]=deltas.get(j);
        int idc = deltas.size();
        int total = Math.abs(r.getRefSt()- r.getRefEnd())+1+idc;
        double id = (double)(total-idc)/(double)total * 100;
        int simc = 0;
        int stpc = 0;
        //return new SamAlignment(r, chrset.findReference(r.getReferenceName()), stOnRead, endOnRead, toAdd);
        return new NucmerAlignment(r.getReference(), r.getRefSt(), r.getRefEnd(), (r.getOrientation()==Orientation.F)?r.getContSt():r.getContEnd(), (r.getOrientation()==Orientation.F)?r.getContEnd():r.getContSt(), idc, simc, stpc, id, 0, 0, del );
   
    }

    protected void process(List<File> filelist){
        Set<String> asc= new HashSet();

        ScaffoldContig as;
        PafRecord rec;
        PafFileReader pfr = new PafFileReader();
        Map<String, ScaffoldContig> alignmentCollection = new HashMap(); 
        Map<String, ContigRecord> contigs=null;
        ObjectInputStream input=null;
        
        try{
            input = new ObjectInputStream(new BufferedInputStream(new FileInputStream(new File(sourceFolder.getAbsolutePath()+File.separator+Utilities.contigObjFile))));
            contigs = (Map<String, ContigRecord>)input.readObject();
            
            for(File f : filelist){
                pfr.openFile(f, chrset);
                
                while((rec = pfr.readNextPafRecord())!=null){
                    try{                        
                        asc.add(rec.getContigID());
                        if(alignmentCollection.containsKey(rec.getContigID()))
                            alignmentCollection.get(rec.getContigID()).addAlignment(createNucmerAlignment(rec));
                        else{
                            as = new ScaffoldContig(rec.getContigID(), rec.getContigLength());
                            as.addAlignment(createNucmerAlignment(rec));
                            as.setHashValue(contigs.get(rec.getContigID()).getHashValue());
                            as.setSeqHashValue(contigs.get(rec.getContigID()).getSeqHashValue());
                            as.setGCCount(contigs.get(rec.getContigID()).getGCCount());
                            as.setGapIntervalTree(contigs.get(rec.getContigID()).getGapIntervals());
                            as.setNCount(contigs.get(rec.getContigID()).getNCount());                        
                            
                            alignmentCollection.put(rec.getContigID(), as);
                        }                        
                    }
                    catch(NoSuchElementException e){                        
                    }                                        
                }
                pfr.closeReader();
            }
            
            for(String contID : asc){
                outqueue.put(alignmentCollection.get(contID));                  
            }            
        }
        catch(ClassNotFoundException e){e.printStackTrace();}
        catch (IOException ex) {
            if(!(ex instanceof EOFException))
                ex.printStackTrace();
        } 
        catch (InterruptedException ex) {            
            ex.printStackTrace();
        }            
        catch (IllegalIntervalException ex) {            
            ex.printStackTrace();
        }                    
        finally {
            try {
                input.close();
            } catch (IOException ex) {
                    ex.printStackTrace();                    
            }
        }                            
    }
    
}
