content: /*
   * Copyright (C) 2014 Andreas Maier, Christian Jaremenko
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */
  package edu.stanford.rsl.conrad.io;
  
  
  import java.io.DataInputStream;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.IOException;
  import java.nio.ByteBuffer;
  import java.util.ArrayList;
  import java.util.Arrays;
  
  import edu.stanford.rsl.conrad.data.numeric.Grid2D;
  import edu.stanford.rsl.conrad.utils.CONRAD;
  import ij.IJ;
  import ij.io.FileInfo;
  
  /**
   * Class to stream Cellvizio's MTK Format.  
   * 
   * @author akmaier
   *
   */
  public class MKTProjectionSource extends FileProjectionSource {
  
  	protected boolean debug = true;
  	private boolean directoryMode;
  	private ArrayList<File> fileList;
  
  	@Override
  	public void initStream (String filename) throws IOException {
  		File file = new File(filename);
  		if (file.isDirectory()){
  			// multi file format
  			fileList = new ArrayList<File>();
  			String [] files = file.list();
  			Arrays.sort(files);
  			for (String f: files){
  				if (f.substring(f.length()-4).compareToIgnoreCase(".mkt")==0){
  					fileList.add(new File(file.getAbsolutePath() + "/" +f));
  				}
  			}
  			if (fileList.size() == 0) throw new IOException("Directory does not contain .viv files");
  			fi = getHeaderInfo(fileList.get(0).getAbsolutePath());
  			directoryMode = true;
  		} else {
  			// Code for single file
  			fi = getHeaderInfo(filename);
  		}
  		init();
  	}
  
  	/**
  	 * Reads the header information from the file into a fileinfo object
  	 * @param filename the filename
  	 * @return the FileInfo
  	 * @throws IOException
  	 */
  	public FileInfo getHeaderInfo( String filename ) throws IOException {
  		if (IJ.debugMode) CONRAD.log("Entering MKT_Reader.getHeaderInfo():");
  		FileInfo fi = new FileInfo();
  		File file = new File(filename);
  		fi.fileName=file.getName();
  		fi.directory = file.getParent() + "/";
  		// NB Need RAF in order to ensure that we know file offset
  		fi.fileType = FileInfo.GRAY16_SIGNED;  // just assume this for the mo    
  		fi.fileFormat = FileInfo.RAW;
  		fi.nImages = 1;
  		// read header info
  		FileInputStream fis = new FileInputStream(file);
  		byte [] unknownHeader = new byte[10];
  		byte [] size = new byte[4];
  		fis.read(unknownHeader);
  		fis.read(size);
  		long sizeInByte = ByteBuffer.wrap(size).getInt();
  		fis.close();
  		fi.offset = 16;
  		fi.gapBetweenImages=32;
  		//System.out.println("Read " + fi.offset);
  		if (fi.offset != 16){
  			throw new IOException("Wrong Header Size; Not an MKT File.");
  		}
  		fi.width = 576;
  		if((sizeInByte/(2*fi.width))%2!=0){
  			fi.width=512;
  			fi.height = (int) (sizeInByte/(2*fi.width));
  		} else {
  			fi.height = (int) (sizeInByte/(2*fi.width));
  		}
  		
  		/* Here we had a look at the 16 byte header and this is what we found so far:
  		 * Width	Height	Size	Size (Byte)	Found	Size B Hex
  		 * 576		580		334080	668160		320A	A3200
  		 * 576		578		332928	665856		290A	A2900
  		 * 576		576		331776	663552		200A	A2000
  		 * 512		512		262144	524288		0008	80000
  		*/
  		fi.nImages = 1204;
  
  		if (true) {
  			System.out.println("MTK Reading image with " + fi.nImages + " frames with " + fi.width + "x" + fi.height + " resolution");
  		}
  		fi.compression = FileInfo.COMPRESSION_NONE;
  		
  		fi.intelByteOrder = true;
  
  		return (fi);
  	}
  
  	private Grid2D readSingleImage(){
  		Grid2D revan = super.getNextProjection();
  		if (revan != null) {
  			try {
  				Thread.sleep(CONRAD.INPUT_QUEUE_DELAY);
  			} catch (InterruptedException e) {
  				// TODO Auto-generated catch block
  				e.printStackTrace();
  			}
  			Grid2D uncompressed = new Grid2D(revan.getWidth(), revan.getHeight());
  			// uncompression
  			int min = Integer.MAX_VALUE;
  			int max = Integer.MIN_VALUE;
  			for (int i = 0; i< revan.getWidth(); i++){
  				for (int j = 0; j< revan.getHeight(); j++){
  					int val = (int) (revan.getPixelValue(i, j));
  					if (val > max) max = val;
  					if (val < min) min = val;
  
  
  					uncompressed.putPixelValue(i,j,val);
  					
  				}
  			}
  			//System.out.println("Range: " + min + " " + max);
  			return uncompressed;
  		} else {
  			return null;
  		}
  
  	}
  
  	@Override
  	public Grid2D getNextProjection(){
  		if (!directoryMode) {
  			return readSingleImage();
  		} else {
  			try{
  				fi = getHeaderInfo(fileList.get(currentIndex+1).getPath());
  				initStack();
  				return readSingleImage();
  			} catch (IOException e) {
  				e.printStackTrace();				
  				return null;
  			} catch (IndexOutOfBoundsException e){
  				return null;
  			}
  		}
  	}
  
  
  
  	public   byte[] convertInt2Bytes(int value) {
  		byte[] buf = new byte[4];
  		buf[3] = (byte) ((value & 0xFF000000)>>24);
  		buf[2] = (byte) ((value & 0x00FF0000)>>16);
  		buf[1] = (byte) ((value & 0x0000FF00)>>8);
  		buf[0] = (byte) (value & 0x000000FF);
  		return buf;
  	}
  
  	public   byte[] convertInt2UnShort(int value) {
  		byte[] buf = new byte[2];
  		buf[1] = (byte) ((value & 0x0000FF00)>>8);
  		buf[0] = (byte) (value & 0x000000FF);
  		return buf;
  	}
  
  }
  