content: /*
   * Copyright (C) 2010-2014 Andreas Maier
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */
  package edu.stanford.rsl.conrad.io;
  
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.OutputStream;
  import java.text.NumberFormat;
  import java.util.Locale;
  
  import javax.swing.JOptionPane;
  
  import edu.stanford.rsl.conrad.data.numeric.Grid2D;
  import edu.stanford.rsl.conrad.data.numeric.Grid3D;
  import edu.stanford.rsl.conrad.pipeline.BufferedProjectionSink;
  import edu.stanford.rsl.conrad.utils.CONRAD;
  import edu.stanford.rsl.conrad.utils.Configuration;
  
  /**
   * Class to model a directory as projection data sink. The sink creates a new file for each projection in the configured raw format.
   * 
   * @author akmaier
   *
   */
  public class IndividualFilesProjectionDataSink extends
  BufferedProjectionSink {
  
  	/**
  	 * 
  	 */
  	private static final long serialVersionUID = -2991638524617273945L;
  	private String directory = null;
  	private String prefix = null;
  	private String format = null;
  	private int width = 0;
  	private int height = 0;
  	private boolean littleEndian = true;
  	private boolean closed = false;
  	public final static String UnsignedShort = "Unsigned Short";
  	public final static String SignedShort = "Signed Short";
  	public final static String Float32Bit = "Float";
  
  	@Override
  	public String getName() {
  		if (configured) {
  			return "Write files in "+  format + " to " + directory;
  		} else {
  			return "Write files to directory";
  		}
  	}
  
  	@Override
  	public Grid3D getResult() {
  		while (!closed) {
  			try {
  				Thread.sleep(CONRAD.INVERSE_SPEEDUP);
  			} catch (InterruptedException e) {
  				// TODO Auto-generated catch block
  				e.printStackTrace();
  			}
  		}
  		width = 0;
  		height = 0;
  		return null;
  	}
  
  	private synchronized void setDimensions(Grid2D projection){
  		width = projection.getWidth();
  		height = projection.getHeight();	
  		System.out.println("Setting new dimensions: " + width + " " + height);
  	}
  
  	@Override
  	public void process(Grid2D projection, int projectionNumber)
  	throws Exception {
  		if (width == 0) setDimensions(projection);
  		NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
  		//NumberFormat nf = new NumberFormat("0000");
  		nf.setMinimumFractionDigits(0);
  		nf.setMaximumFractionDigits(0);
  		nf.setMaximumIntegerDigits(4);
  		nf.setMinimumIntegerDigits(4);
  		nf.setGroupingUsed(false);
  		String filename = directory + "/" + prefix + nf.format(projectionNumber);
  		FileOutputStream writer = new FileOutputStream(filename);
  		short [] shortPixels = null;
  		if (format.equals(UnsignedShort) || format.equals(SignedShort) ) {
  			shortPixels = new short [width * height];
  		}
  		float [] floatPixels = null;
  		if (format.equals(Float32Bit)){
  			floatPixels = new float [width * height];
  		}
  		for (int j = 0; j <  projection.getHeight(); j++){
  			for (int i = 0; i < projection.getWidth(); i ++){
  				float value = projection.getPixelValue(i, j);
  				if (format.equals(UnsignedShort)) {
  					shortPixels[i + (j*width)] = (short)((int) value);
  				}
  				if (format.equals(SignedShort)) {
  					shortPixels[i + (j*width)] = (short)((int) value - 32768);
  				}
  				if (format.equals(Float32Bit)){
  					floatPixels[i + (j*width)] = (float) value;
  				}
  			}
  		}
  		if (format.equals(UnsignedShort) || format.equals(SignedShort) ) {
  			write16BitImage(writer, shortPixels);
  		}
  		if (format.equals(Float32Bit)){
  			writeFloatImage(writer, floatPixels);
  		}
  		writer.flush();
  		writer.close();
  	}
  
  	@Override
  	public void setConfiguration(Configuration config) {
  
  	}
  
  	@Override
  	public String toString() {
  		return getName();
  	}
  
  	@Override
  	public void configure() throws Exception {
  		boolean success = true;
  		width = 0;
  		height = 0;
  		directory = JOptionPane.showInputDialog("Enter directory:", directory);
  		if (directory == null) success = false;
  		prefix = JOptionPane.showInputDialog("Enter file prefix:", prefix);
  		if (prefix == null) success = false;
  		String [] formats = {Float32Bit, SignedShort, UnsignedShort};
  		format = (String) JOptionPane.showInputDialog(null, "Select format:", "Format Selection", JOptionPane.INFORMATION_MESSAGE, null, formats, format);
  		if (format == null) success = false;
  		String [] endianess = {"Litte Endian", "Big Endian"};
  		String endian = "Big Endian";
  		if (littleEndian) endian = "Litte Endian";
  		endian = (String) JOptionPane.showInputDialog(null, "Select endianess:", "Format Selection", JOptionPane.INFORMATION_MESSAGE, null, endianess, endian);
  		if (endian == null) {
  			success = false;
  		} else {
  			if (endian.equals("Litte Endian")){
  				littleEndian = true;
  			} else {
  				littleEndian = false;
  			}
  		}
  		configured = success;
  	}
  	
  	public void configured(){
  		configured = true;
  	}
  
  	@Override
  	public String getBibtexCitation() {
  		String bibtex = "@BOOK{Harlold06-JIO,\n" +
  		"  author = {{Harold}, E. R.},\n" +
  		"  title = {{Java I/O}},\n" +
  		"  publisher = {O'Reilly Media, Inc.},\n" +
  		"  address = {Sebastopol, CA, United States},\n" +
  		"  year = {2006}\n" +
  		"}";
  		return bibtex;
  	}
  
  	@Override
  	public String getMedlineCitation() {
  		return "Harold ER, Java I/O, O'Reilly Media, Inc., Sebastopol, CA, United States, 2006.";
  	}
  
  	/**
  	 * Same method as in ImageWriter
  	 * @see ij.io.ImageWriter
  	 * 
  	 * @param out the Stream to write the ImageProcessor
  	 * @param pixels the pixel data
  	 * @throws IOException may occur
  	 */
  	void write16BitImage(OutputStream out, short[] pixels)  throws IOException {
  		int bytesWritten = 0;
  		int size = width*height*2;
  		int count = 8192;
  		byte[] buffer = new byte[count];
  
  		while (bytesWritten<size) {
  			if ((bytesWritten + count)>size)
  				count = size - bytesWritten;
  			int j = bytesWritten/2;
  			int value;
  			if (littleEndian)
  				for (int i=0; i < count; i+=2) {
  					value = pixels[j];
  					buffer[i] = (byte)value;
  					buffer[i+1] = (byte)(value>>>8);
  					j++;
  				}
  			else
  				for (int i=0; i < count; i+=2) {
  					value = pixels[j];
  					buffer[i] = (byte)(value>>>8);
  					buffer[i+1] = (byte)value;
  					j++;
  				}
  			out.write(buffer, 0, count);
  			bytesWritten += count;
  		}
  	}
  
  	/**
  	 * Same method as in ImageWriter
  	 * @see ij.io.ImageWriter
  	 * 
  	 * @param out the Stream to write the ImageProcessor
  	 * @param pixels the pixel data
  	 * @throws IOException may occur
  	 */
  	void writeFloatImage(OutputStream out, float[] pixels)  throws IOException {
  		int bytesWritten = 0;
  		int size = width*height*4;
  		int count = 8192;
  		byte[] buffer = new byte[count];
  		int tmp;
  
  		while (bytesWritten<size) {
  
  			if ((bytesWritten + count)>size)
  				count = size - bytesWritten;
  			int j = bytesWritten/4;
  			if (littleEndian)
  				for (int i=0; i < count; i+=4) {
  					tmp = Float.floatToRawIntBits(pixels[j]);
  					buffer[i]   = (byte)tmp;
  					buffer[i+1] = (byte)(tmp>>8);
  					buffer[i+2] = (byte)(tmp>>16);
  					buffer[i+3] = (byte)(tmp>>24);
  					j++;
  				}
  			else
  				for (int i=0; i < count; i+=4) {
  					tmp = Float.floatToRawIntBits(pixels[j]);
  					buffer[i]   = (byte)(tmp>>24);
  					buffer[i+1] = (byte)(tmp>>16);
  					buffer[i+2] = (byte)(tmp>>8);
  					buffer[i+3] = (byte)tmp;
  					j++;
  				}
  			out.write(buffer, 0, count);
  			bytesWritten += count;
  		}
  	}
  	
  	@Override
  	public void close (){
  		closed = true;
  	}
  
  	/**
  	 * @return the directory
  	 */
  	public String getDirectory() {
  		return directory;
  	}
  
  	/**
  	 * @param directory the directory to set
  	 */
  	public void setDirectory(String directory) {
  		this.directory = directory;
  	}
  
  	/**
  	 * @return the prefix
  	 */
  	public String getPrefix() {
  		return prefix;
  	}
  
  	/**
  	 * @param prefix the prefix to set
  	 */
  	public void setPrefix(String prefix) {
  		this.prefix = prefix;
  	}
  
  	/**
  	 * @return the format
  	 */
  	public String getFormat() {
  		return format;
  	}
  
  	/**
  	 * @param format the format to set
  	 */
  	public void setFormat(String format) {
  		this.format = format;
  	}
  
  	/**
  	 * @return the width
  	 */
  	public int getWidth() {
  		return width;
  	}
  
  	/**
  	 * @param width the width to set
  	 */
  	public void setWidth(int width) {
  		this.width = width;
  	}
  
  	/**
  	 * @return the height
  	 */
  	public int getHeight() {
  		return height;
  	}
  
  	/**
  	 * @param height the height to set
  	 */
  	public void setHeight(int height) {
  		this.height = height;
  	}
  
  	/**
  	 * @return the littleEndian
  	 */
  	public boolean isLittleEndian() {
  		return littleEndian;
  	}
  
  	/**
  	 * @param littleEndian the littleEndian to set
  	 */
  	public void setLittleEndian(boolean littleEndian) {
  		this.littleEndian = littleEndian;
  	}
  
  }
  
  