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.File;
  import java.io.IOException;
  import java.io.RandomAccessFile;
  
  import edu.stanford.rsl.conrad.utils.CONRAD;
  
  
  import ij.IJ;
  import ij.io.FileInfo;
  
  public class NRRDProjectionSource extends FileProjectionSource {
  
  	public final String uint8Types="uchar, unsigned char, uint8, uint8_t";
  	public final String int16Types="short, short int, signed short, signed short int, int16, int16_t";
  	public final String uint16Types="ushort, unsigned short, unsigned short int, uint16, uint16_t";
  	public final String int32Types="int, signed int, int32, int32_t";
  	public final String uint32Types="uint, unsigned int, uint32, uint32_t";
  	private String notes = "";
  	
  	private boolean detachedHeader=false;
  	protected String headerPath=null;
  	protected String imagePath=null;
  	protected String imageName=null;	
  	
  	public void initStream (String filename) throws IOException {
  		fi = getHeaderInfo(filename); 
  		if (fi!=null && fi.width>0 && fi.height>0) {
  			init();
  		} else {
  			throw new IOException("Format does not match: width = " + fi.width + " height = " + fi.height + " offset = " + fi.offset);
  		}
  	}
  	
  	public FileInfo getHeaderInfo( String filename ) throws IOException {
  
  		if (IJ.debugMode) CONRAD.log("Entering Nrrd_Reader.readHeader():");
  		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
  		RandomAccessFile input = new RandomAccessFile(fi.directory+fi.fileName,"r");
  
  		String thisLine,noteType,noteValue, noteValuelc;
  
  		fi.fileType = FileInfo.GRAY8;  // just assume this for the mo    
  		fi.fileFormat = FileInfo.RAW;
  		fi.nImages = 1;
  		int dimension = 0;
  
  		// parse the header file, until reach an empty line//	boolean keepReading=true;
  		while(true) {
  			thisLine=input.readLine();
  			if(thisLine==null || thisLine.equals("")) {
  				if(!detachedHeader) fi.longOffset = input.getFilePointer();
  				break;
  			}		
  			notes+=thisLine+"\n";
  			if(thisLine.indexOf("#")==0) continue; // ignore comments
  
  			noteType=getFieldPart(thisLine,0).toLowerCase(); // case irrelevant
  			noteValue=getFieldPart(thisLine,1);
  			noteValuelc=noteValue.toLowerCase();
  			String firstNoteValue=getSubField(thisLine,0);
  
  			if (IJ.debugMode) CONRAD.log("NoteType:"+noteType+", noteValue:"+noteValue);
  
  			if (noteType.equals("data file")||noteType.equals("datafile")) {
  				// This is a detached header file
  				// There are 3 kinds of specification for the data files
  				// 	1.	data file: <filename>
  				//	2.	data file: <format> <min> <max> <step> [<subdim>]
  				//	3.	data file: LIST [<subdim>]
  				if(firstNoteValue.equals("LIST")) {
  					// TOFIX - type 3
  					throw new IOException("Nrrd_Reader: not yet able to handle datafile: LIST specifications");
  				} else if(!getSubField(thisLine,1).equals("")) {
  					// TOFIX - type 2
  					throw new IOException("Nrrd_Reader: not yet able to handle datafile: sprintf file specifications");
  				} else {
  					// Type 1 specification
  					File imageFile;
  					// Relative or absolute
  					if(noteValue.indexOf("/")==0) {
  						// absolute
  						imageFile=new File(noteValue);
  						// TOFIX could also check local directory if absolute path given
  						// but dir does not exist
  					} else {
  						//CONRAD.log("fi.directory = "+fi.directory);					
  						imageFile=new File(fi.directory,noteValue);
  					}
  					//CONRAD.log("image file ="+imageFile);
  
  					if(imageFile.exists()) {
  						fi.directory=imageFile.getParent();
  						fi.fileName=imageFile.getName();
  						imagePath=imageFile.getPath();
  						detachedHeader=true;
  					} else {
  						throw new IOException("Unable to find image file ="+imageFile.getPath());
  					}
  				}										
  			}
  
  			if (noteType.equals("dimension")) {
  				dimension=Integer.valueOf(noteValue).intValue();
  				if(dimension>3) throw new IOException("Nrrd_Reader: Dimension>3 not yet implemented!");
  			}
  			if (noteType.equals("sizes")) {
  				for(int i=0;i<dimension;i++) {
  					int integer =Integer.valueOf(getSubField(thisLine,i)).intValue();
  					if(i==0) fi.width=integer;
  					if(i==1) fi.height=integer;
  					if(i==2) fi.nImages=integer;
  				}
  			}
  			if (noteType.equals("type")) {
  				if (uint8Types.indexOf(noteValuelc)>=0) {
  					fi.fileType=FileInfo.GRAY8;
  				} else if(uint16Types.indexOf(noteValuelc)>=0) {
  					fi.fileType=FileInfo.GRAY16_SIGNED;
  				} else if(int16Types.indexOf(noteValuelc)>=0) {
  					fi.fileType=FileInfo.GRAY16_UNSIGNED;
  				} else if(uint32Types.indexOf(noteValuelc)>=0) {
  					fi.fileType=FileInfo.GRAY32_UNSIGNED;
  				} else if(int32Types.indexOf(noteValuelc)>=0) {
  					fi.fileType=FileInfo.GRAY32_INT;
  				} else if(noteValuelc.equals("float")) {
  					fi.fileType=FileInfo.GRAY32_FLOAT;
  				} else if(noteValuelc.equals("double")) {
  					fi.fileType=FileInfo.GRAY64_FLOAT;
  				} else {
  					throw new IOException("Unimplemented data type ="+noteValue);
  				}
  			}
  			if (noteType.equals("byte skip")||noteType.equals("byteskip")) fi.longOffset=Long.valueOf(noteValue).longValue();
  			if (noteType.equals("endian")) {
  				if(noteValuelc.equals("little")) {
  					fi.intelByteOrder = true;
  				} else {
  					fi.intelByteOrder = false;
  				}
  			}
  
  			if (noteType.equals("encoding")) {
  				if(noteValuelc.equals("gz")) noteValuelc="gzip";
  				//fi.encoding=noteValuelc;
  			}	
  		}
  
  		if(!detachedHeader) fi.longOffset = input.getFilePointer();
  		input.close();
  		return (fi);
  	}
  	
  	String getFieldPart(String str, int fieldIndex) {
  		str=str.trim(); // trim the string
  		String[] fieldParts=str.split(":\\s+");
  		if(fieldParts.length<2) return(fieldParts[0]);
  		//CONRAD.log("field = "+fieldParts[0]+"; value = "+fieldParts[1]+"; fieldIndex = "+fieldIndex);
  
  		if(fieldIndex==0) return fieldParts[0];
  		else return fieldParts[1];
  	}
  	
  	String getSubField(String str, int fieldIndex) {
  		String fieldDescriptor=getFieldPart(str,1);
  		fieldDescriptor=fieldDescriptor.trim(); // trim the string
  
  		if (IJ.debugMode) CONRAD.log("fieldDescriptor = "+fieldDescriptor+"; fieldIndex = "+fieldIndex);
  
  		String[] fields_values=fieldDescriptor.split("\\s+");
  
  		if (fieldIndex>=fields_values.length) {
  			return "";
  		} else {
  			String rval=fields_values[fieldIndex];
  			if(rval.startsWith("\"")) rval=rval.substring(1);
  			if(rval.endsWith("\"")) rval=rval.substring(0, rval.length()-1);
  			return rval;
  		}
  	}
  
  }
  