/*
 * 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.
*/

/*
 * BinaryParser.java
 *
 * Created on July 26, 2007, 1:01 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package org.broad.igv.preprocess;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

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

    private boolean littleEndian = false;

    /** Creates a new instance of BinaryParser */
    public BinaryReader() {
    }

    public BinaryReader(boolean littleEndian) {
        this.setLittleEndian(littleEndian);
    }

    /**
     * Read an array of floats from a  binary file.   It is assumed that the
     * file contains floats written with DataOutput.writeFloat();
     */
    public float[] readFloats(File file) {
        return convertBytesToFloats(readBytes(file));
    }

    /**
     * Read an array of ints from the binary file.   It is assumed that the
     * file contains ints written with DataOutput.writeInt();
     */
    /**
     * Read an array of ints from the binary file.   It is assumed that the
     * file contains ints written with DataOutput.writeInt();
     */
    public int[] readInts(File file) {
        try {
            int nInts =(int) (file.length() / (Integer.SIZE / 8));
            int[] ints = new int[nInts];
            DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
            for (int i = 0; i < nInts; i++) {
                if (dis.available() >= (Integer.SIZE / 8)) {
                    ints[i] = dis.readInt();
                }
            }
            dis.close();
            return ints;
        } catch (IOException ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex);
        }
    }

    /**
     * Read an array of longs from the binary file.   It is assumed that the
     * file contains longs written with DataOutput.writeInt();
     */
    public long[] readLongs(File file) {
        try {
            int nLongs = (int) (file.length() / (Long.SIZE / 8));
            long[] longs = new long[nLongs];
            DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(file)));
            for (int i = 0; i < nLongs; i++) {
                if (dis.available() >= (Long.SIZE / 8)) {
                    longs[i] = dis.readLong();
                }
            }
            dis.close();
            return longs;
        } catch (IOException ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex);
        }
    }

    protected byte [] readBytes(File file) {
        try {
            int fileSize = (int) file.length();
            BufferedInputStream inStream = new BufferedInputStream(new FileInputStream(file), fileSize);
            // Read in chunks of 100MB
            byte [] bytes = readBytes(inStream, fileSize);
            inStream.close();
            return bytes;
        } catch (IOException ex) {
            ex.printStackTrace();
            throw new RuntimeException(ex);
        }
        
    }
      
    public  List<File> getDataFiles(String dataFileDirectory) { 
        FilenameFilter filter = new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.endsWith("bin");
            }
        };
        return getDataFiles(dataFileDirectory, filter);
    }

    
   /**
     * Return all data files in the data directory. This includes location,
     * marker (snp) id, and copy number files for all chromosomes.
     *
     */
    public  List<File> getDataFiles(String dataFileDirectory, FilenameFilter filter) {
        File dfd = new File(dataFileDirectory);
        if(!dfd.exists()) {
            System.err.println("Input directory: " + dfd.getAbsolutePath() + " does not exist.  Exiting!");
            System.exit(-1);
        }
        
        File[] files = new File(dataFileDirectory).listFiles(filter);
        return (files == null ? new ArrayList<File>() : java.util.Arrays.asList(files));
    }
    
    
    /**
     * Read the number of bytes specificed from the input stream
     */
    protected byte[] readBytes(InputStream inStream, int nBytes) throws IOException {
        byte[] bytes = new byte[nBytes];
        int bytesRead = 0;
        while (bytesRead < nBytes) {
            bytesRead += inStream.read(bytes, bytesRead, inStream.available());
        }
        return bytes;
    }

    /**
     * Convert bytes to floats.  Handles endian conversion
     */
    private float[] convertBytesToFloats(byte[] bytes) {
        if (littleEndian) {
            float[] floats = new float[bytes.length / (Float.SIZE / 8)];
            EndianConverter.convertLittleEndianToFloat(bytes, floats, bytes.length, 0, floats.length);
            return floats;
        } else {
            return ByteConverter.convertBytesToFloats(bytes);
        }
    }

    public void setLittleEndian(boolean littleEndian) {
        this.littleEndian = littleEndian;
    }
}
