content: package edu.stanford.rsl.conrad.physics.materials;
  
  import java.util.Iterator;
  import java.util.TreeMap;
  
  import edu.stanford.rsl.conrad.physics.materials.database.MaterialsDB;
  
  /**
   * <p>This class stores the weighted atomic composition of a material.
   * <br/>The weighted atomic composition of a material is a key-sorted map containing its constituting elements(keys) and their contribution by weight.</p>
   * <p>H2O is stored as:</p>
   * <p><H , 2 * atomic weight of hydrogen><br/>
   * <O , 1 * atomic weight of oxygen></p>
   * 
   * @author Rotimi .X. Ojo
   *
   */
  public class WeightedAtomicComposition {
  private TreeMap<String, Double> composition  = new TreeMap<String, Double>();
  	
  	public WeightedAtomicComposition(){}
  	
  	
  	public WeightedAtomicComposition(String formula){
  		add(formula, 1);
  	}
  	
  	public WeightedAtomicComposition(String formula, double proportion){
  		add(formula, proportion);
  	}	
  	
  	/**
  	 * Add an element to table.
  	 * @param formula is formula of element
  	 * @param proportion is atomic contribution by weight. For a compound, proportion = number of atoms * atomic weight;
  	 */
  	public void add(String formula, double proportion){
  		int lastIndex = 0;
  		for(int i = 1; i < formula.length(); i++){
  			String curr = formula.substring(i,i+1);
  			if(curr.toUpperCase().equals(curr) && !curr.matches("\\p{Digit}+")){					
  				addTokenToMap(formula.substring(lastIndex, i), proportion);			
  				lastIndex = i;
  			}
  		}
  		addTokenToMap(formula.substring(lastIndex).trim(), proportion);
  	}	
  	
  	/**
  	 * <p>To be used if there exists only one instance of element in formula. This method by rebuildDatabase for bootstrapping.</div>
  	 * <br>Users are encouraged to use the add method.</p>
  	 * @param formula is formula of element
  	 * @param weight is atomic weight of element
  	 */
  	public void addUniqueElement(String formula, double weight){
  		composition.put(formula.trim(), weight);
  	}
  	
  	private void addTokenToMap(String token, double proportion) {
  		int stop = indexOfDigit(token);	
  		String element = token;
  		double weight = 0;
  		if(stop == -1){
  			weight = ((Element)MaterialsDB.getMaterial(token)).getAtomicWeight()*proportion;
  		}else{
  			element = token.substring(0, stop).trim();
  			weight = Double.valueOf(token.substring(stop))*((Element)MaterialsDB.getMaterial(element)).getAtomicWeight()*proportion;
  		}
  		if (composition.containsKey(element)) {
  			weight += composition.get(element);
  		}
  		composition.put(element, weight);
  	}	
  	
  	
  
  	private int indexOfDigit(String token) {
  		for(int i = 0; i < token.length(); i++){
  			String Char = token.charAt(i)+"";
  			if(Char.matches("\\p{Digit}+")){
  				return i;
  			}
  		}
  		return -1;
  	}
  	
  	public void  setCompositionTable(TreeMap<String, Double> composition) {
  		this.composition = composition;
  	}
  
  
  	public TreeMap<String, Double> getCompositionTable() {
  		return composition;
  	}
  
  
  	public int size() {
  		return composition.size();
  	}
  
  
  	public Iterator<Double> valuesIterator() {
  		return composition.values().iterator();
  	}
  	
  	public Iterator<String> keysIterator(){
  		return composition.keySet().iterator();
  	}
  
  }
  /*
   * Copyright (C) 2010-2014 Rotimi X Ojo
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */