package org.broadinstitute.sting.gatk.walkers;

import net.sf.samtools.SAMRecord;
import org.broadinstitute.sting.gatk.LocusContext;
import org.broadinstitute.sting.utils.Utils;
import edu.mit.broad.picard.reference.ReferenceSequence;

import java.util.Iterator;
import java.util.List;
import static java.lang.reflect.Array.*;

public class MismatchHistoWalker extends BasicReadWalker<Integer, Integer> {

    protected long[] mismatchCounts = new long[0];
    protected final int MIN_TARGET_EDIT_DISTANCE = 5;
    protected final int MAX_TARGET_EDIT_DISTANCE = 10;

    public String getName() {
        return "Mismatch_Histogram";
    }

    // Do we actually want to operate on the context?
    public boolean filter(LocusContext context, SAMRecord read) {
	    // we only want aligned reads
	    return !read.getReadUnmappedFlag();
    }

    public Integer map(LocusContext context, SAMRecord read) {

        int editDist = Integer.parseInt(read.getAttribute("NM").toString());

        // ignore alignments with indels for now
        if ( read.getAlignmentBlocks().size() == 1 &&
             editDist >= MIN_TARGET_EDIT_DISTANCE &&
             editDist <= MAX_TARGET_EDIT_DISTANCE ) {

            ReferenceSequence refseq = context.getReferenceContig();

            int start = read.getAlignmentStart()-1;
            int stop  = read.getAlignmentEnd();

            List<Byte> refSeq = Utils.subseq(context.getReferenceContig().getBases(), start, stop);
            List<Byte> readBases = Utils.subseq(read.getReadBases());

            assert(refSeq.size() == readBases.size());

            // it's actually faster to reallocate a resized array than to use ArrayLists...
            if ( refSeq.size() > mismatchCounts.length ) {
                int oldLength = mismatchCounts.length;
                mismatchCounts = (long[])resizeArray(mismatchCounts, refSeq.size());
                for ( int i = oldLength; i < refSeq.size(); i++ )
                    mismatchCounts[i] = 0;
            }

            String refStr = Utils.baseList2string(refSeq).toUpperCase();
            String readStr = Utils.baseList2string(readBases).toUpperCase();
            for ( int i = 0; i < refStr.length(); i++) {
                if ( refStr.charAt(i) != readStr.charAt(i) )
                    mismatchCounts[i]++;
            }
        }

        return 1;
    }

    public Integer reduceInit() { return 0; }

    public Integer reduce(Integer value, Integer sum) {
        return value + sum;
    }

    public void onTraversalDone() {
        for ( int i = 0; i < mismatchCounts.length; i++ ) {
            System.out.printf("%3d %10d%n", (i+1), mismatchCounts[i]);
        }
    }

    private static Object resizeArray (Object oldArray, int newSize) {
        int oldSize = getLength(oldArray);
        Class elementType = oldArray.getClass().getComponentType();
        Object newArray = newInstance(elementType,newSize);
        int preserveLength = Math.min(oldSize,newSize);
        if (preserveLength > 0)
            System.arraycopy (oldArray,0,newArray,0,preserveLength);
        return newArray;
    }
}
@@ -2144,32 +2144,101 @@
 ).toUpperCase();
+%0A%0A            boolean reverseFlag = read.getReadNegativeStrandFlag();
 %0A            for
@@ -2375,17 +2375,57 @@
 hCounts%5B
-i
+(reverseFlag ? (refStr.length()-1-i) : i)
 %5D++;%0A   
@@ -2702,18 +2702,16 @@
 h; i++ )
- %7B
 %0A       
@@ -2735,30 +2735,25 @@
 rint
-f(%22%253d %2510d%25n%22, (i+1),
+ln((i+1) + %22%5Ct%22 +
  mis
@@ -2769,26 +2769,16 @@
 ts%5Bi%5D);%0A
-        %7D%0A
     %7D%0A%0A 

deal with reverse complemented reads