/*
 * The Broad Institute
 * SOFTWARE COPYRIGHT NOTICE AGREEMENT
 * This is copyright (2007-2008) by the Broad Institute/Massachusetts Institute
 * of Technology.  It is licensed to You under the Gnu Public License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *    http://www.opensource.org/licenses/gpl-2.0.php
 *
 * This software is supplied without any warranty or guaranteed support
 * whatsoever. Neither the Broad Institute nor MIT can be responsible for its
 * use, misuse, or functionality.
 */
package org.broad.igv.preprocess;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.broad.igv.feature.Genome;
import org.broad.igv.feature.GenomeManager;

/**
 *
 * @author jrobinso
 */
public class ReadCounter {

    File samFile;

    public ReadCounter(File file) {
        this.samFile = file;
    }

    private AlignmentFileIterator getIterator(File f) throws IOException {
        String fn = f.getName().toLowerCase();
        if (fn.endsWith(".sam") || fn.endsWith(".bam"))
        {
            return new SAMFileIterator(f);
        } else
        {
            return new MAQFileIterator(f);
        }
    }

    public static class Counts {

        Map<String, short[]> countsPreChr;
        long totalReadCount;
        float avgReadLength;

        public Counts(Map<String, short[]> countsPreChr, long totalReadCount,
                       float avgReadLength) {
            this.countsPreChr = countsPreChr;
            this.totalReadCount = totalReadCount;
            this.avgReadLength = avgReadLength;
        }
    }

    public Counts doReadCounts(int resolution, int extensionFactor,
                                String genomeId, Map<String, Integer> lastPositionPerChr) {

        int progressStep = 1000000;
        int progressIncrement = 1;
        long cnt = 0;
        float avgReadLength = 0;

        // Optional.  If supplied the genome can be used to get chr lengths, which in
        // turn can be used to size arrays more effeciently.
        Genome genome = ((genomeId == null)
            ? null : GenomeManager.getInstance().getGenome(genomeId));

        Map<String, short[]> readCountMap = new HashMap();

        AlignmentFileIterator iter = null;
        try
        {

            iter = this.getIterator(samFile);

            while (iter.hasNext())
            {
                Alignment record = iter.next();

                // TODO -- make these tests parameters
                if (!record.isDuplicate() && record.getMappingQuality() > 0)
                {
                    String chr = record.getChr();

                    int start = record.getStart();
                    int end = record.getEnd();  // <= currently doesn't correct for indels
                    avgReadLength += (end - start);
                    cnt++;

                    // Extend start or end
                    if (record.isIsNegative())
                    {
                        start = Math.max(0, start - extensionFactor);
                    } else
                    {
                        end = end + extensionFactor;
                    }

                    int lastPosition = lastPositionPerChr.containsKey(chr)
                        ? lastPositionPerChr.get(chr) : 0;
                    lastPosition = Math.max(lastPosition, end);
                    lastPositionPerChr.put(chr, lastPosition);

                    // Increment count
                    short[] counts = readCountMap.get(chr);
                    if (counts == null)
                    {
                        int chrLength = 250000000;
                        if ((genome != null) && (genome.getChromosome(chr) != null))
                        {
                            chrLength = genome.getChromosome(chr).getLength();
                        }
                        int nPoints = (int) (1.1 * chrLength / resolution);
                        counts = new short[nPoints];
                        readCountMap.put(chr, counts);
                    }

                    // An index > the counts array length indicates data beyond the 
                    // the chromosome end
                    int maxIndex = counts.length - 1;
                    int startIndex = Math.min(maxIndex, start / resolution);
                    int endIndex = Math.min(maxIndex, end / resolution);

                    for (int i = startIndex; i <= endIndex; i++)
                    {
                        counts[i]++;
                    }

                //if(cnt > progressIncrement * progressStep) {
                //    System.out.println(cnt + " alignments read");
                //    progressIncrement++;
                //}
                }
            }
            if (cnt > 0)
            {
                avgReadLength /= cnt;
            }


        } catch (Exception e)
        {
            e.printStackTrace();
        } finally
        {
            try
            {
                iter.close();
            } catch (Exception e)
            {
                e.printStackTrace();
            }
        }
        return new Counts(readCountMap, cnt, avgReadLength);
    }
}
