content: package edu.stanford.rsl.tutorial.mammography.inbreast;
  
  import ij.IJ;
  import ij.ImageJ;
  import ij.ImagePlus;
  import ij.gui.Roi;
  import ij.plugin.frame.RoiManager;
  
  import java.io.BufferedReader;
  import java.io.File;
  import java.io.FileNotFoundException;
  import java.io.FileReader;
  import java.io.IOException;
  import java.util.ArrayList;
  
  import javax.xml.xpath.XPathExpressionException;
  
  import edu.stanford.rsl.conrad.data.numeric.Grid2D;
  import edu.stanford.rsl.conrad.utils.ImageUtil;
  import edu.stanford.rsl.tutorial.mammography.Mammogram;
  import edu.stanford.rsl.tutorial.mammography.Mammogram.BreastDensityACR;
  import edu.stanford.rsl.tutorial.mammography.Mammogram.Findings;
  import edu.stanford.rsl.tutorial.mammography.Mammogram.MammographyView;
  import edu.stanford.rsl.tutorial.mammography.Mammogram.SideOfBody;
  
  public class ReadMammograms {
  
  	private SideOfBody readOnlySides = SideOfBody.Both;
  	private MammographyView readOnlyViews = MammographyView.Both;
  	private Findings readOnlyKind = Findings.Mass;
  	private ArrayList<Integer> queriedPatiendIds = new ArrayList<Integer>();
  	private ArrayList<Integer> patientID = new ArrayList<Integer>();
  	private ArrayList<SideOfBody> side = new ArrayList<SideOfBody>();
  	private ArrayList<MammographyView> view = new ArrayList<MammographyView>();
  	private ArrayList<BreastDensityACR> density = new ArrayList<BreastDensityACR>();
  	private ArrayList<Integer> birads = new ArrayList<Integer>();
  	private ArrayList<ArrayList<Findings>> findings = new ArrayList<ArrayList<Findings>>();
  	private ArrayList<ArrayList<Roi>> roi = new ArrayList<ArrayList<Roi>>();
  
  	private File[] listOfFiles = null;
  	private ArrayList<Mammogram> mammograms = new ArrayList<Mammogram>();
  	private int mammoCounter = 0;
  
  	//set path to Dicoms, XML and CSV file
  	private String imgDir = null;
  	private String xmlDir = null;
  	private String csvFile = null;
  	
  	private boolean initialized = false; // flag for single access operations
  
  	public static void main(String[] args) {
  
  		String imgDir =  "G:/INbreast/DataExtracted/AllDICOMs/";
  		String xmlDir =  "G:/INbreast/DataExtracted/ALLXML/";
  		String csvFile = "G:/INbreast/DataExtracted/INbreast.csv";
  		
  		ReadMammograms reader = new ReadMammograms(imgDir, xmlDir, csvFile);
  		reader.setOptions(SideOfBody.Both, MammographyView.Both, Findings.All);
  		reader.readImagesSuccessively();
  		
  		new ImageJ();
  		String selectedImage = imgDir+"22671003_f571fd4e63c718e3_MG_L_ML_ANON.dcm";
  		reader.showMammogram(selectedImage, true);
  		
  //		Mammogram m = reader.readNextMammogram();
  //		while (m != null) {
  //			// here you can do cool stuff with the images
  //			RoiManager manager = new RoiManager();
  //			m = reader.readNextMammogram();
  //			ImagePlus imp = ImageUtil.wrapGrid(m.getImage(), "Mammogram");
  //			ArrayList<Roi> rois = m.getRois();
  //			for(int i = 0; i < rois.size(); i++){
  //				manager.add(imp, rois.get(i), i+1);
  //			}
  //			imp.show();
  //			manager.runCommand("Show All");
  //			
  //			manager.close();
  //			imp.close();			
  //		}
  		System.out.println("Done.");
  	}
  
  	/**
  	 * prepares access to whole mammo database
  	 */
  	public void initMammoReading(){
  		this.readCSVdata();
  		initialized = true;
  	}
  	
  	/**
  	 * prepares access to whole mammo database with prior option selection
  	 */
  	public void initMammoReadingHelper(){
  		this.setOptions(SideOfBody.Both, MammographyView.Both, Findings.All);
  		this.readImagesSuccessively();
  		initialized = true;
  	}
  	
  	/**
  	 * setOptions sets witch parameters will be accepted 
  	 * 
  	 * @param sob SideOfBody
  	 * @param vws MammographyView
  	 * @param finding Findings
  	 */
  	public void setOptions(SideOfBody sob, MammographyView vws, Findings finding) {
  		this.readOnlySides = sob;
  		this.readOnlyViews = vws;
  		this.readOnlyKind = finding;
  	}
  	
  	/**
  	 * deprecated
  	 * all CSVdata will be read
  	 * all mammograms who satisfy setOptions will be read 
  	 * a new mammogram constructor will be set for every suitable mammogram
  	 */
  	public void readImages() {
  		readCSVdata();
  		readMammograms();
  	}
  	
  	/**
  	 * all CSVdata will be read
  	 * all mammograms who satisfy setOptions will be read, to start the constructor  
  	 * readNextMammogram has to be used
  	 */
  	public void readImagesSuccessively() {
  		readCSVdata();
  		prepReadMammograms();
  	}
  
  	public ArrayList<Mammogram> getMammograms() {
  		return mammograms;
  	}
  
  	public void setMammograms(ArrayList<Mammogram> mammograms) {
  		this.mammograms = mammograms;
  	}
  	
  	/*
  	 * deprecated
  	 */
  	private void readMammograms() {
  
  		//the path of imageFolder is given to listOfFiles, all DICOM images are now listed
  		File folder = new File(imgDir);
  		listOfFiles = folder.listFiles();
  
  		//pid = PatiendtID
  		ArrayList<Integer> pid = new ArrayList<Integer>();
  		for (int i = 0; i < listOfFiles.length; i++) {
  			//fn = filename, consist of 6 Elements, separated by a "_"
  			String fn = listOfFiles[i].getName();
  			if (fn.contains(".dcm")) {
  				String[] identifiers = fn.split("_");
  				pid.add(Integer.parseInt(identifiers[0]));
  			}
  		}
  
  		//calls method getQueriedPatientIds= only patients/images
  		//satisfying wanted SideOfBody,MammographyView and Findings are returned
  		queriedPatiendIds = getQueriedPatientIds(pid);
  
  		System.out.println("Reading " + String.valueOf(queriedPatiendIds.size()) + " mammograms.");
  
  		//all filenames will be read and checked if DICOM
  		for (int i = 0; i < listOfFiles.length; i++) {
  			String fn = listOfFiles[i].getName();
  			if (fn.contains(".dcm")) {
  				//separate patientID from filename, by splitting
  				String[] identifiers = listOfFiles[i].getName().split("_");
  				int patientId = Integer.parseInt(identifiers[0]);
  				// check if the patientID from the i-th file matches one of the queriedPatiendIds
  				// returns positiv integer if found, -1 if not found
  				int inList = getPatiendIdx(patientId, queriedPatiendIds);
  				if (inList >= 0) {
  					// get actual index from the list of  all collected patientID
  					int refIdx = getPatiendIdx(patientId, this.patientID);
  					//load the actual image as Grid2D
  					ImagePlus imgAsImp = IJ.openImage(listOfFiles[i].getAbsolutePath());
  					Grid2D img = ImageUtil.wrapImageProcessor(imgAsImp.getProcessor());
  					//collect all information of the Object of refIdx and start a constructor  
  					Mammogram mammo = new Mammogram(img, side.get(refIdx), view.get(refIdx), density.get(refIdx),
  							findings.get(refIdx), roi.get(refIdx), birads.get(refIdx));
  					//adding this mammogram to ArrayList
  					this.mammograms.add(mammo);
  				}
  			}
  		}
  		System.out.println("ReadMammograms - done.");
  	}
  
  	private void prepReadMammograms() {
  		//the path of imageFolder is given to listOfFiles, all DICOM images are now listed
  		File folder = new File(imgDir);
  		listOfFiles = folder.listFiles();
  		prepReadMammograms(listOfFiles);
  	}
  	
  	private void prepReadMammograms(File[] customListOfFiles){
  		this.mammoCounter = 0;
  		listOfFiles = customListOfFiles;
  		//pid = PatiendtID
  		ArrayList<Integer> pid = new ArrayList<Integer>();
  		for (int i = 0; i < listOfFiles.length; i++) {
  			//fn = filename, consist of 6 Elements, separated by a "_"
  			String fn = listOfFiles[i].getName();
  			if (fn.contains(".dcm")) {
  				String[] identifiers = fn.split("_");
  				pid.add(Integer.parseInt(identifiers[0]));
  			}
  		}
  		//calls method getQueriedPatientIds= only patients/images
  		//satisfying wanted SideOfBody,MammographyView and Findings are returned
  		queriedPatiendIds = getQueriedPatientIds(pid);
  	}
  
  	public Mammogram readNextMammogram() {
  		// with every checked mammogram, mammoCounter increases
  		while (mammoCounter < listOfFiles.length) {
  			String fn = listOfFiles[mammoCounter].getName();
  			// check if file is a DICOM, if not, mammoCounter++ 
  			if (fn.contains(".dcm")) {
  				// get the name of the file in identifiers[0] , rest is also stored but will not be used
  				String[] identifiers = listOfFiles[mammoCounter].getName().split("_");
  				int patientId = Integer.parseInt(identifiers[0]);
  				// check if this patientID of matches one of the queriedPatiendIds
  				int inList = getPatiendIdx(patientId, queriedPatiendIds);
  				// if patientId matches one of the queriedIds an positive integer will be returned
  				// else -1 will be returned and mammoCounter++ will be executed
  				if (inList >= 0) {
  					// get actual index of all stored patients
  					int refIdx = getPatiendIdx(patientId, this.patientID);
  					ImagePlus imgAsImp = IJ.openImage(listOfFiles[mammoCounter].getAbsolutePath());
  					Grid2D img = ImageUtil.wrapImageProcessor(imgAsImp.getProcessor());
  					//start the constructor
  					Mammogram mammo = new Mammogram(img, side.get(refIdx), view.get(refIdx), density.get(refIdx),
  							findings.get(refIdx), roi.get(refIdx), birads.get(refIdx));
  					mammoCounter++;
  					return mammo;
  				} else {
  					mammoCounter++;
  				}
  			} else {
  				mammoCounter++;
  			}
  		}
  		return null;
  	}
  /**
   * 
   * @param listOfPatients = all collected patients
   * 
   * @return ArrayList<Integer> containing patientIDs of images satisfying wanted SideOfBody, MammographyView and Findings
   * 
   */
  	private ArrayList<Integer> getQueriedPatientIds(ArrayList<Integer> listOfPatients) {
  		//list is the return value, will be filled later
  		ArrayList<Integer> list = new ArrayList<Integer>();
  		// the i-th element of patientID (all 410 patients) will be compared to
  		// the id-th element of listOfPatients () 
  		for (int i = 0; i < patientID.size(); i++) {
  			boolean isInList = false;
  			for (int id = 0; id < listOfPatients.size(); id++) {
  				if (patientID.get(i).equals(listOfPatients.get(id))) {
  					isInList = true;
  					continue;
  				}
  			}
  			if (!isInList) {
  				continue;
  			}
  			// read out, witch SideOfBody do we currently want to look up
  			String[] sides = readOnlySides.getValue();
  			boolean isCorrectSide = false;
  			for (int s = 0; s < sides.length; s++) {
  				// compare element i with the elements of SideOfBody
  				if (sides[s].equals(side.get(i).getValue()[0])) {
  					isCorrectSide = true;
  				}
  			}
  			if (!isCorrectSide) {
  				continue;
  			}
  			// read out, witch MammographyViews do we currently want to look up
  			String[] views = readOnlyViews.getValue();
  			boolean isCorrectView = false;
  			for (int s = 0; s < views.length; s++) {
  				// compare element i with the elements of the MammographyView
  				if (views[s].equals(view.get(i).getValue()[0])) {
  					isCorrectView = true;
  				}
  			}
  			if (!isCorrectView) {
  				continue;
  			}
  			// read out, witch Finding do we currently want to look up
  			String[] kind = readOnlyKind.getValue();
  			ArrayList<Findings> fndgInMammoI = findings.get(i);
  			boolean isCorrectFinding = false;
  			for (int s = 0; s < kind.length; s++) {
  				//compare element i with the elements of Findings
  				for (Findings f : fndgInMammoI) {
  					if (kind[s].equals(f.getValue()[0])) {
  						isCorrectFinding = true;
  					}
  				}
  			}
  			if (!isCorrectFinding) {
  				continue;
  			}
  			// if SideOfBody, MammographyView and Findings were matching out specification
  			// the matching patientID will now be stored in "list"
  			list.add(patientID.get(i));
  		}
  		return list;
  	}
  	
  	/**
  	 * 
  	 * @param id = patientID which could be in the idList
  	 * @param idList = all patientIDs that have been previously collected
  	 * @return index i from idList if found , returns -1 if not found
  	 */
  	private int getPatiendIdx(int id, ArrayList<Integer> idList) {
  		for (int i = 0; i < idList.size(); i++) {
  			if (idList.get(i).equals(id))
  				return i;
  		}
  		return -1;
  	}
  	
  	/**
  	 * the provided CSVdate will be read 
  	 */
  	private void readCSVdata() {
  		System.out.println("Parsing CSV file.");
  
  		BufferedReader br = null;
  		String line = "";
  		String cvsSplitBy = ";";
  
  		try {
  			//read the csvFile
  			br = new BufferedReader(new FileReader(csvFile));
  			int count = -1;
  			while ((line = br.readLine()) != null) {
  				count++;
  				//first line of csvFile: Patient; Patient age; Laterality; View; Acquisition date; File Name; ACR; Bi-Rads
  				//ignore first line, it has only labels no, patient information
  				if (count == 0)
  					continue;
  				char lastCh = line.charAt(line.length() - 1);
  				while (lastCh == ' ') {
  					line = line.substring(0, line.length() - 1);
  					lastCh = line.charAt(line.length() - 1);
  				}
  				if (line.charAt(line.length() - 1) == ';') {
  					line = line.substring(0, line.length() - 1);
  				}
  
  				// use separator to split line
  				// entry containes all information of removed, removed, SideOfBody, MammographyView, Date, FileName, ACR , Bi-Rads
  				String[] entry = line.split(cvsSplitBy);
  				// parse Side Of Body
  				if (entry[2].equals(SideOfBody.Left.getValue()[0])) {
  					this.side.add(SideOfBody.Left);
  				} else if (entry[2].equals(SideOfBody.Right.getValue()[0])) {
  					this.side.add(SideOfBody.Right);
  				} else {
  					this.side.add(SideOfBody.Unknown);
  				}
  				// parse View
  				if (entry[3].equals(MammographyView.MLO.getValue()[0])) {
  					this.view.add(MammographyView.MLO);
  				} else if (entry[3].equals(MammographyView.CC.getValue()[0])) {
  					this.view.add(MammographyView.CC);
  				} else {
  					this.view.add(MammographyView.Unknown);
  				}
  				// parse Patient ID
  				int patient = Integer.parseInt(entry[5]);
  				this.patientID.add(patient);
  
  				// parse ACR
  				int acr = -1;
  				if (entry.length > 6 && !entry[6].contains(" ")) {
  					//extract acr score and compare to the values denoted in Mammogram.java
  					acr = Integer.parseInt(entry[6]);
  				}
  				if (acr == BreastDensityACR.Fatty.getACRValue()) {
  					this.density.add(BreastDensityACR.Fatty);
  				} else if (acr == BreastDensityACR.FattyGlandular1.getACRValue()) {
  					this.density.add(BreastDensityACR.FattyGlandular1);
  				} else if (acr == BreastDensityACR.FattyGlandular2.getACRValue()) {
  					this.density.add(BreastDensityACR.FattyGlandular2);
  				} else if (acr == BreastDensityACR.Glandular.getACRValue()) {
  					this.density.add(BreastDensityACR.Glandular);
  				} else {
  					this.density.add(BreastDensityACR.Unknown);
  				}
  				// parse Birads
  				int biradsScore = 0;
  				if (entry.length > 7) {
  					biradsScore = Integer.parseInt(entry[7].substring(0, 1));
  				}
  				this.birads.add(biradsScore);
  
  				//finding with their corresponding rois are stored
  				ArrayList<Findings> fndgs = new ArrayList<Findings>();
  				ArrayList<Roi> rois = new ArrayList<Roi>();
  				String[] rawOutput = null;
  				// rawOutput contains:
  				// [0]total number of findings
  				// [1]class of nth finding
  				// [2]number of XY coordinates
  				// [3...] XY coordinates pairs as an array
  				// [1]to[3..]repeat themself for every finding
  
  				// health breast have a biradsScore of 1
  				if (biradsScore != 1) {
  					XMLparser parser = new XMLparser();
  					try{
  						parser.readXml(xmlDir + entry[5] + ".xml");
  						// entry[5] contains the name of the .xml file
  						// value is of ArrayList<String>
  						fndgs.addAll(parser.getFindings());
  						// Roi.Polygon => X/Y coordinates, width & height denotes
  						// the total XY variance
  						rois.addAll(parser.getRois());
  						this.findings.add(fndgs);
  						this.roi.add(rois);
  					}
  					catch (XPathExpressionException XPathExpExc){
  						System.err.println("Error when parsing XML, maybe no internet connection. Findings and RoIs could not be added to Mammogram object.");
  					}
  					catch (FileNotFoundException e) {
  						System.err.println("XML file not found, maybe wrong filename. Findings and RoIs could not be added to Mammogram object.");
  					}
  				} else {
  					//findings is ArrayList of ArrayList of String
  					ArrayList<Findings> healthy = new ArrayList<Findings>();
  					healthy.add(Findings.Healthy);
  					this.findings.add(healthy);
  					this.roi.add(new ArrayList<Roi>());
  				}
  			}
  
  		} catch (FileNotFoundException e) {
  			e.printStackTrace();
  		} catch (IOException e) {
  			e.printStackTrace();
  //		} catch (XPathExpressionException e) {
  //			// TODO Auto-generated catch block
  //			e.printStackTrace();
  		} finally {
  			if (br != null) {
  				try {
  					br.close();
  				} catch (IOException e) {
  					e.printStackTrace();
  				}
  			}
  		}
  		System.out.println("ReadCSVdata - Done.");
  	}
  	
  	/**
  	 * /path to scvFile and imgFolder are setted
  	 * @param imgFolder
  	 * @param csvF
  	 */
  	public ReadMammograms(String imgFolder, String xmlDir, String csvF) {
  		this.imgDir = imgFolder;
  		this.xmlDir = xmlDir;
  		this.csvFile = csvF;
  	}
  	
  	/**
  	 * prepares access to whole database
  	 * @param name : string containing 8-digit number of mammo case (INbreast only)
  	 * @param showRois : set true to show RoIs
  	 */
  	public void showMammogram(String name,boolean showRois){
  		if (!initialized)
  		{
  			initMammoReadingHelper();
  		}
  		prepReadMammograms(new File[] { new File(name) });
  		
  		RoiManager manager = new RoiManager();
  		Mammogram m = this.readNextMammogram();
  		ImagePlus imp = ImageUtil.wrapGrid(m.getImage(), "Mammogram");
  		ArrayList<Roi> rois = m.getRois();
  		for(int i = 0; i < rois.size(); i++){
  			manager.add(imp, rois.get(i), i+1);
  		}
  		imp.show();
  		manager.runCommand("Show All");
  
  //		manager.close();
  //		imp.close();			
  	}
  }