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.physics.detector;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  
  import edu.stanford.rsl.conrad.data.numeric.Grid2D;
  import edu.stanford.rsl.conrad.data.numeric.MultiChannelGrid2D;
  import edu.stanford.rsl.conrad.physics.PhysicalObject;
  import edu.stanford.rsl.conrad.physics.materials.Material;
  import edu.stanford.rsl.jpop.utils.UserUtil;
  
  /**
   * This absorption model records the path lengths of each material and writes it into a MultiChannelGrid
   * @author akmaier
   *
   */
  public class MaterialPathLengthDetector extends XRayDetector {
  
  	/**
  	 * 
  	 */
  	private static final long serialVersionUID = -5709955427012216841L;
  	private int numberOfMaterials = 4;
  	private HashMap<Material, Integer> materialChannelMap;
  	private boolean doesNotFit = false;
  	private String [] names;
  	private boolean debugMode = false;
  
  	@Override
  	public void configure() throws Exception {
  		numberOfMaterials = UserUtil.queryInt("SelectNumber of Recorded Materials:", numberOfMaterials);
  		materialChannelMap = new HashMap<Material, Integer>();
  		names = new String[numberOfMaterials];
  		configured = true;
  	}
  
  	@Override
  	/**
  	 * The material hash map and the corresponding names are set to the initial values, i.e. empty list and array of strings with length corresponding to number of materials.
  	 */
  	public void init() {
  		if (configured){
  			materialChannelMap = new HashMap<Material, Integer>();
  			names = new String[numberOfMaterials];
  		}
  	}
  
  	private synchronized void addMaterial(Material mat){
  		if (!materialChannelMap.containsKey(mat)){
  			Integer number = materialChannelMap.keySet().size();
  			if (number < numberOfMaterials) names[number]=mat.getName();
  			materialChannelMap.put(mat, number);
  		}
  	}
  
  	@Override
  	public void writeToDetector(Grid2D grid, int x, int y, ArrayList<PhysicalObject> segments){
  		HashMap<Material, Double> localMap = XRayDetector.accumulatePathLenghtForEachMaterial(segments);
  		for (Material mat: localMap.keySet()) {
  			MultiChannelGrid2D mGrid = (MultiChannelGrid2D) grid;
  			Integer channel = materialChannelMap.get(mat);
  			if (channel == null){
  				addMaterial(mat);
  				channel = materialChannelMap.get(mat);
  			}
  			if (channel < numberOfMaterials) {
  				mGrid.putPixelValue(x, y, channel, localMap.get(mat));
  			} else {
  				if (!doesNotFit ){
  					System.out.println("MaterialPathLengthAbsorptionModel: MultiChannelGrid does not fit " + mat);
  					doesNotFit = true;
  				}
  			}
  		}
  	}
  
  
  	@Override
  	public void notifyEndOfRendering(){
  		if (debugMode) {
  			System.out.println("Rendering finished. The following materials were recorded:");
  			for (Material mat:materialChannelMap.keySet()){
  				System.out.println("Channel " + materialChannelMap.get(mat) + ": " + mat);
  			}
  		}
  	}
  
  	@Override
  	public Grid2D createDetectorGrid(int width, int height){
  		MultiChannelGrid2D grid = new MultiChannelGrid2D(width, height, numberOfMaterials);
  		grid.setChannelNames(names);
  		return grid;
  	}
  
  
  	@Override
  	public String toString() {
  		if (configured){
  			return "Material Path Length Detector (" + numberOfMaterials + " materials)";
  		} 
  		return "Material Path Length Detector";
  	}
  
  	/**
  	 * @return the numberOfMaterials
  	 */
  	public int getNumberOfMaterials() {
  		return numberOfMaterials;
  	}
  
  	/**
  	 * @param numberOfMaterials the numberOfMaterials to set
  	 */
  	public void setNumberOfMaterials(int numberOfMaterials) {
  		this.numberOfMaterials = numberOfMaterials;
  	}
  
  	/**
  	 * @return the materialChannelMap
  	 */
  	public HashMap<Material, Integer> getMaterialChannelMap() {
  		return materialChannelMap;
  	}
  
  	/**
  	 * @param materialChannelMap the materialChannelMap to set
  	 */
  	public void setMaterialChannelMap(HashMap<Material, Integer> materialChannelMap) {
  		this.materialChannelMap = materialChannelMap;
  	}
  
  	/**
  	 * @return the doesNotFit
  	 */
  	public boolean isDoesNotFit() {
  		return doesNotFit;
  	}
  
  	/**
  	 * @param doesNotFit the doesNotFit to set
  	 */
  	public void setDoesNotFit(boolean doesNotFit) {
  		this.doesNotFit = doesNotFit;
  	}
  
  	/**
  	 * @return the names
  	 */
  	public String[] getNames() {
  		return names;
  	}
  
  	/**
  	 * @param names the names to set
  	 */
  	public void setNames(String[] names) {
  		this.names = names;
  	}
  
  
  }
  