content: package edu.stanford.rsl.conrad.phantom.forbild;
  
  import java.io.File;
  import java.io.FileNotFoundException;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Scanner;
  
  import edu.stanford.rsl.conrad.geometry.AbstractShape;
  import edu.stanford.rsl.conrad.physics.PhysicalObject;
  import edu.stanford.rsl.conrad.physics.materials.database.MaterialsDB;
  import edu.stanford.rsl.conrad.rendering.AbstractScene;
  import edu.stanford.rsl.conrad.rendering.PrioritizableScene;
  import edu.stanford.rsl.conrad.utils.parsers.SceneFileParser;
  
  /**
   * <p>This class adds objects defined in <a href = "http://www.imp.uni-erlangen.de/forbild/">forbild</a> format into a scene that can be used to create a phantom. </p>
   *
   * @author Rotimi X Ojo
   */
  public class ForbildParser implements SceneFileParser {
  
  	private String directoryPath;
  	private ArrayList<String> objectDefs = new ArrayList<String>();
  	private HashMap<String,ArrayList<String>> templatePlaceholders = new HashMap<String, ArrayList<String>>();
  	private AbstractScene scene = new PrioritizableScene();
  
  	public ForbildParser(File file) {
  		this(file, null);
  	}
  
  	public ForbildParser(File file, HashMap<String,String> placeHoldersMap) {
  		try {
  			directoryPath = file.getParent() + "\\";
  			preProcessing(new Scanner(file), placeHoldersMap);
  		} catch (Exception e) {
  			e.printStackTrace();
  		}		
  		createObjects();
  	}
  
  	private void preProcessing(Scanner scanner, HashMap<String,String> placeHoldersMap)
  			throws FileNotFoundException {
  		while (scanner.hasNextLine()) {
  			parseLine(scanner.nextLine().trim(), placeHoldersMap);
  		}
  	}
  	private String lastObjectName = "";
  	private void parseLine(String currLine, HashMap<String,String> varMap) throws FileNotFoundException {
  		if(currLine == null || currLine.isEmpty()|| (currLine.indexOf("//")==0)){
  			return;
  		}
  		currLine=currLine.trim();
  		if (currLine.substring(0, currLine.indexOf(" ")).equals("#Prototype")) {
  			String name = currLine.substring(currLine.indexOf(" "),	currLine.indexOf('(')).trim();
  			templatePlaceholders.put(name, getTemplatePlaceHolders(currLine));
  		} else if (currLine.substring(0, currLine.indexOf(" ")).equals(	"Phantom")) {
  			scene.setName(currLine.substring(currLine.indexOf('"') + 1, currLine.length()-1));
  		} else if(currLine.contains("Object ")){
  			lastObjectName = currLine.substring(currLine.indexOf(" ") + 1).trim();
  		}else if (currLine.charAt(0) == '{') {	
              currLine = lastObjectName + ";" + currLine.substring(1,currLine.length()-1);
  			objectDefs.add(replacePlaceHolders(currLine,varMap));
  		} else if (currLine.substring(0, currLine.indexOf(" ")).equals("#include")
  				&& currLine.contains(".pha")) {
  			String filename = currLine.substring(currLine.indexOf('"')+1,	currLine.length() - 1);
  			scene.addAll((new ForbildParser(new File(directoryPath + filename))	.getScene()));
  		} else if (currLine.substring(0, currLine.indexOf(" ")).equals("func")) {
  			String name = currLine.substring(currLine.indexOf(" "),	currLine.indexOf('(')).trim();
  			String fileName = name + ".pha";
  			HashMap<String, String> buff = new HashMap<String, String>();
  			ArrayList<String> placeHolders = templatePlaceholders.get(name);
  			ArrayList<String> parameters = getFunctionParameters(currLine);
  			for(int i =0; i < placeHolders.size();i++){
  				buff.put(placeHolders.get(i), parameters.get(i));
  			}
  			scene.addAll(new ForbildParser(new File(directoryPath + fileName.trim()),buff).getScene());
  		}
  	}
  
  	private ArrayList<String> getTemplatePlaceHolders(String currLine) {
  		return getFunctionParameters(currLine);
  	}
  
  	private void createObjects() {
  		Iterator<String> it = objectDefs.iterator();
  		Scanner sc;
  		int textLine = 0;
  		while (it.hasNext()) {
  			String line = it.next();
  			textLine++;
  			PhysicalObject basicobj = new PhysicalObject();
  			if(line.contains("[") && line.contains("]")){
  				try{
  					AbstractShape shape = ForbildShapeFactory.getShape(line.substring(line.indexOf("["),line.indexOf("]")+ 1));
  					if (shape== null){
  						throw new RuntimeException("Error in Parsing");
  					}
  					basicobj.setShape(shape);
  				}catch (Exception e) {
  					//e.printStackTrace();
  					throw new RuntimeException("Parsing Error at line: " + textLine + "\n" + line);
  				}
  				basicobj.setNameString(line.substring(line.indexOf("[")+1, line.indexOf(":")));
  			}
  			String nline = line.substring(line.indexOf("]") + 1);
  			sc = new Scanner(nline.substring(1).trim());
  			sc.useDelimiter(";");		
  			
  			
  			while(sc.hasNext()){
  				String property = sc.next();
  				if(property.toLowerCase().contains("rho")){
  					try{
  						basicobj.setMaterial(MaterialsDB.getMaterial(property.substring(property.indexOf("=")+1)));
  					}catch (Exception e) {
  						throw new RuntimeException("Parsing Error at line: " + textLine + "\n" + line);
  					}
  				}
  			}
  			scene.add(basicobj);			
  		}
  	}
  
  	private String replacePlaceHolders(String currLine, HashMap<String, String> varMap) {
  		if (varMap == null || varMap.size() == 0) {
  			return currLine;
  		}
  		Iterator<String> pit = varMap.keySet().iterator();
  		while (pit.hasNext()) {
  			String placeHolder = pit.next();
  			String geometryDef = currLine.substring(0,currLine.indexOf(']') + 1);
  			currLine = geometryDef.replace(placeHolder, varMap.get(placeHolder))+ currLine.substring(currLine.indexOf(']') + 1);
  		}
  		return currLine;
  	}
  
  	private ArrayList<String> getFunctionParameters(String functionCall) {
  		ArrayList<String> param = new ArrayList<String>(4);
  		String parameters = functionCall.substring(functionCall.indexOf('(') +  1, functionCall.indexOf(')'));
  		Scanner temp = new Scanner(parameters);
  		temp.useDelimiter(",");
  		while (temp.hasNext()) {
  			param.add(temp.next().trim());
  		}
  		return param;
  	}
  
  	@Override
  	public AbstractScene getScene() {
  		return scene;
  	}
  
  
  }
  /*
   * Copyright (C) 2010-2014 Rotimi X Ojo
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */