/*
 * 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.data.wgs;

import org.broad.igv.preprocess.*;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;

/**
 * Processes a dataset with no overlapping features.  Bins can be allocated 
 * more efficiently than overlapping feature datasets.
 */
public class WGSProcessor extends WGSBaseProcessor {

    static private Logger log = Logger.getLogger(WGSProcessor.class);

    static private int maxNumberWarnings = 200;

    static private int numberWarnings = 0;

    public WGSProcessor(SequenceDataset ds, StatusMonitor sm) {
        super(ds, sm);
    }

    public WGSProcessor(SequenceDataset ds) {
        super(ds);
    }
    
    public static void main(String [] args) {
        
        SequenceDataset ds = new SequenceDataset(args[0]);
        WGSProcessor proc = new WGSProcessor(ds);
        proc.setZoomMax(2);
        proc.process(args[1]);
        
    }

    /**
     * Allocate rows from the dataset to bins.  
     * 
     * @param chr
     * @param nBins
     * @param binSize
     * @return
     */
    protected List<Bin> allocateBins(int chrLength, int nBins, double binSize) {

        // Create all potential bins.  Empty bins are removed at the end. 
        // TODO -- this is inefficient.  Refactor to create bins as needed.
        List<RangeBin> allBins = new ArrayList(nBins);
        for (int i = 0; i < nBins; i++) {
            int location = (int) (i * binSize);
            allBins.add(new RangeBin(location));
        }

        RangeBin lastBin = null;
        for (int i = 0; i < chrLength; i++) {
            int start = i;
            int bStart = (int) (start / binSize);
            if (bStart >= allBins.size()) {
                //log.info("Start location " + chr + ": " + start + " exceeds expected length.  Wrong genome?");

            } else {
                RangeBin bin = allBins.get(bStart);
                if (lastBin == null) {
                    bin.setStartIndex(i);
                } else if (bin != lastBin) {
                    bin.setStartIndex(i);
                    lastBin.setEndIndex(i);
                }
                lastBin = bin;
            }
        }
        // Set the end index of the last bin if unset.
        if (lastBin != null && lastBin.getEndIndex() <= 0) {
            lastBin.setEndIndex(chrLength);
        }

        // Remove empty bins.
        List<Bin> occupiedBins = new ArrayList(allBins.size());
        for (RangeBin bin : allBins) {
            if (bin.getFeatureCount() > 0) {
                occupiedBins.add(bin);
            }
        }

        return occupiedBins;
    }

    /**
     * Return the subset of data from the data array that is allocated to
     * this bin.
     * 
     * @param data
     * @param bin
     * @return
     */
    protected float[] getDataForBin(float[] data, Bin bin) {

        RangeBin rBin = (RangeBin) bin;

        // Specifc  -> Get data for bin
        int nDataPts = 0;
        for (int i = rBin.getStartIndex(); i < rBin.getEndIndex() && i < data.length; i++) {
            if (!Float.isNaN(data[i])) {
                nDataPts++;
            }
        }

        if (nDataPts > 0) {
            float[] binData = new float[nDataPts];
            int binDataIndex = 0;
            for (int i = rBin.getStartIndex(); i < rBin.getEndIndex() && binDataIndex < binData.length; i++) {
                if (!Float.isNaN(data[i])) {
                    binData[binDataIndex] = data[i];
                    binDataIndex++;
                }
            }
            //
            return binData;
        } else {
            return null;
        }
    }


}
