content: package edu.stanford.rsl.conrad.physics.materials.database;
  
  import java.io.BufferedReader;
  import java.io.InputStreamReader;
  import java.io.OutputStreamWriter;
  import java.io.UnsupportedEncodingException;
  import java.net.URL;
  import java.net.URLConnection;
  import java.net.URLEncoder;
  import java.text.NumberFormat;
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.Scanner;
  import java.util.Set;
  import java.util.TreeMap;
  
  import edu.stanford.rsl.conrad.numerics.mathexpressions.Evaluator;
  import edu.stanford.rsl.conrad.physics.materials.utils.AttenuationType;
  import edu.stanford.rsl.conrad.physics.materials.utils.WeightedAtomicComposition;
  import edu.stanford.rsl.conrad.utils.interpolation.NumberInterpolatingTreeMap;
  
  
  /**
   * <p>This class provides access to NIST XCOM Database. 
   * <br/>This can be used to retrieve the energy dependent mass attenuation of elements, and arbitrary combination of elements.
   * <br/>The NIST database supports energies between 1 keV - 100 GeV;</p>
   * @author Rotimi X Ojo
   */
  public class OnlineMassAttenuationDB {
  
  	private static String nistDBUrl = "http://physics.nist.gov";
  
  	public static double getMassAttenuationData(WeightedAtomicComposition comp,
  			double energy, AttenuationType attType) {
  		ArrayList<AttenuationType> ty = new ArrayList<AttenuationType>();
  		ty.add(attType);
  		return getMassAttenuationData(comp, energy + ";", ty, false).get(attType).firstEntry().getValue().doubleValue();
  	}
  
  	/**
  	 * Retrieves energy dependent mass attenuation data from NIST XCOM database
  	 * @param comp is atomic composition by weight of material to be retrieved
  	 * @param energies is semi-colon seperated list  of energies(MEV) of interest.
  	 * @return energy dependent mass attenuation of supplied energies including K-Edges
  	 */
  	public static TreeMap<AttenuationType, NumberInterpolatingTreeMap> getMassAttenuationData(
  			WeightedAtomicComposition comp, String energies, ArrayList<AttenuationType> att, boolean useDefaultEnergies) {		
  		return getMassAttenuationDataFromNIST(getCompositionAsString(comp),energies, att,useDefaultEnergies);	
  	}
  
  	private static String buildURLLiteral(String composition, String energies, ArrayList<AttenuationType> att, boolean useDefaultEnergies) {
  		String data = "";
  		composition= composition.trim();
  
  		try {
  			data  = URLEncoder.encode("WindowXmin", "UTF-8") + "=" + URLEncoder.encode(0.001 + "", "UTF-8");
  			data += "&" + URLEncoder.encode("WindowXmax", "UTF-8") + "=" + URLEncoder.encode(100000 + "", "UTF-8"); 
  			data += "&" + URLEncoder.encode("Formulae", "UTF-8") + "=" + URLEncoder.encode(composition, "UTF-8");	
  			data += "&" + URLEncoder.encode("Method", "UTF-8") + "=" + URLEncoder.encode("3", "UTF-8");
  			data += "&" + URLEncoder.encode("NumAdd", "UTF-8") + "=" + URLEncoder.encode("1", "UTF-8");
  			data += "&" + URLEncoder.encode("Energies", "UTF-8") + "=" + URLEncoder.encode(energies, "UTF-8");
  			if(useDefaultEnergies){
  				data += "&" + URLEncoder.encode("Output", "UTF-8") + "=" + URLEncoder.encode("on", "UTF-8");	
  			}else{
  				data += "&" + URLEncoder.encode("Output", "UTF-8") + "=" + URLEncoder.encode("", "UTF-8");	
  			}
  
  			for(AttenuationType type:att){
  				data += "&" + URLEncoder.encode(type.getName(), "UTF-8") + "=" + URLEncoder.encode("on", "UTF-8");
  			}
  
  		} catch (UnsupportedEncodingException e1) {
  			e1.printStackTrace();
  		} 	
  		return data;
  	}
  
  	/**
  	 * Retrieves Mass attenuation data from the NIST XCOM Database
  	 * @param composition is space separated list of atomic composition of material of interest
  	 * @param energies is semi-colon separated list of energies
  	 * @param att is array list containing the types of attenuation the developer is interested in retrieving
  	 * @return Mass attenuation data from the NIST XCOM Database
  	 */
  	private static TreeMap<AttenuationType, NumberInterpolatingTreeMap>getMassAttenuationDataFromNIST(String composition, String energies, ArrayList<AttenuationType> att, boolean useDefaultEnergies){
  		String urlSpec = buildURLLiteral(composition, energies, att, useDefaultEnergies);
  		TreeMap<AttenuationType, NumberInterpolatingTreeMap> table = new TreeMap<AttenuationType, NumberInterpolatingTreeMap>();
  		table.put(AttenuationType.COHERENT_ATTENUATION, new NumberInterpolatingTreeMap());
  		table.put(AttenuationType.INCOHERENT_ATTENUATION, new NumberInterpolatingTreeMap());
  		table.put(AttenuationType.PHOTOELECTRIC_ABSORPTION, new NumberInterpolatingTreeMap());
  		table.put(AttenuationType.ELECTRON_FIELD_PAIRPRODUCTION, new NumberInterpolatingTreeMap());
  		table.put(AttenuationType.NUCLEAR_FIELD_PAIRPRODUCTION, new NumberInterpolatingTreeMap());
  		table.put(AttenuationType.TOTAL_WITH_COHERENT_ATTENUATION, new NumberInterpolatingTreeMap());
  		table.put(AttenuationType.TOTAL_WITHOUT_COHERENT_ATTENUATION, new NumberInterpolatingTreeMap());
  
  		try {
  			URL url = new URL(nistDBUrl + "/cgi-bin/Xcom/data.pl"); 
  			URLConnection conn = url.openConnection(); 
  			conn.setDoOutput(true); 
  			OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream()); 
  			wr.write(urlSpec); 
  			wr.flush(); 
  			BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream())); 
  			String line;
  
  			while(true){
  				line = rd.readLine();
  				if (line != null) {
  					if (line.length()> 0) {
  						String substr = line.substring(0,1);
  						if (substr != null){
  							if(line.length()> 0 && line.substring(0,1).matches("\\p{Digit}+")){
  								break;
  							}
  
  						}
  					}
  				} else {
  					System.out.println("No attenuation coefficients found for "+ composition);
  					return null;
  				}
  			}			
  			do{
  				addEntryToMap(table,line, att);
  			}while ((line = rd.readLine()) != null); 
  
  		} catch (Exception e) {
  			e.printStackTrace();
  			return null;
  		} 
  		return table;
  	}
  
  
  
  	private static String getCompositionAsString(
  			WeightedAtomicComposition comp) {
  		TreeMap<String, Double> table = comp.getCompositionTable();
  		String composition = "";
  		Set<String> keys = table.keySet();
  		Iterator<String> it =keys.iterator();	
  
  		NumberFormat f = NumberFormat.getInstance();  
  		f.setGroupingUsed(false);  
  		while(it.hasNext()){
  			String text = it.next();
  			text += ("  " + f.format(table.get(text))+ " ");
  			composition+=text;
  		}	
  		return composition;
  	}
  
  
  
  	private static void addEntryToMap(
  			TreeMap<AttenuationType, NumberInterpolatingTreeMap> table, String line, ArrayList<AttenuationType> att) {
  		Scanner s = new Scanner(line);
  		double energy = Evaluator.getValue(s.next().trim());
  		NumberInterpolatingTreeMap mp;
  		if(att.contains(AttenuationType.COHERENT_ATTENUATION)){
  			mp = table.get(AttenuationType.COHERENT_ATTENUATION);
  			mp.put(energy, Evaluator.getValue(s.next().trim()));
  		}
  		if(att.contains(AttenuationType.INCOHERENT_ATTENUATION)){
  			mp = table.get(AttenuationType.INCOHERENT_ATTENUATION);
  			mp.put(energy, Evaluator.getValue(s.next().trim()));
  		}
  		if(att.contains(AttenuationType.PHOTOELECTRIC_ABSORPTION)){
  			mp = table.get(AttenuationType.PHOTOELECTRIC_ABSORPTION);
  			mp.put(energy, Evaluator.getValue(s.next().trim()));
  		}
  		if(att.contains(AttenuationType.NUCLEAR_FIELD_PAIRPRODUCTION)){
  			mp = table.get(AttenuationType.NUCLEAR_FIELD_PAIRPRODUCTION);
  			mp.put(energy, Evaluator.getValue(s.next().trim()));
  		}
  		if(att.contains(AttenuationType.ELECTRON_FIELD_PAIRPRODUCTION)){
  			mp = table.get(AttenuationType.ELECTRON_FIELD_PAIRPRODUCTION);
  			mp.put(energy, Evaluator.getValue(s.next().trim()));
  		}
  		if(att.contains(AttenuationType.TOTAL_WITH_COHERENT_ATTENUATION)){
  			mp = table.get(AttenuationType.TOTAL_WITH_COHERENT_ATTENUATION);
  			mp.put(energy, Evaluator.getValue(s.next().trim()));
  		}
  		if(att.contains(AttenuationType.TOTAL_WITHOUT_COHERENT_ATTENUATION)){
  			mp = table.get(AttenuationType.TOTAL_WITHOUT_COHERENT_ATTENUATION);
  			mp.put(energy, Evaluator.getValue(s.next().trim()));
  		}
  
  	}
  
  
  
  
  
  
  }
  /*
   * Copyright (C) 2010-2014 Rotimi X Ojo
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */