code: package dan2097.org.bitbucket.reactionextraction;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Map.Entry;
  
  import com.ggasoftware.indigo.IndigoObject;
  
  
  
  class ReactionStoichiometryDeterminer {
  	private final Reaction reaction;
  	private final IndigoObject indigoReaction;
  
  	ReactionStoichiometryDeterminer(Reaction reaction, IndigoObject indigoReaction) {
  		this.reaction = reaction;
  		this.indigoReaction = indigoReaction;
  	}
  
  	/**
  	 * Uses the atom mapping to determine the stoichiometry of reactants used.
  	 * The property "smiles" in the Indigo reactions is used to link the CML representation with the Indigo representation
  	 */
  	void processReactionStoichiometry() {
  		Map<Integer, IndigoObject> mappingNumberToReactant = new HashMap<Integer, IndigoObject>();
  		for (IndigoObject reactant : indigoReaction.iterateReactants()) {
  			for (IndigoObject atom : reactant.iterateAtoms()) {
  				mappingNumberToReactant.put(indigoReaction.atomMappingNumber(atom), reactant);
  			}
  		}
  		Map<Integer, Integer> mappingNumberToTimesUsed= new HashMap<Integer, Integer>();
  		for (IndigoObject product : indigoReaction.iterateProducts()) {
  			for (IndigoObject atom : product.iterateAtoms()) {
  				int number = indigoReaction.atomMappingNumber(atom);
  				if (number != 0){
  					if (mappingNumberToTimesUsed.get(number)==null){
  						mappingNumberToTimesUsed.put(number, 1);
  					}
  					else{
  						mappingNumberToTimesUsed.put(number, mappingNumberToTimesUsed.get(number) +1);
  					}
  				}
  			}
  		}
  		Map<IndigoObject, Integer> timesReactantUsed = new HashMap<IndigoObject, Integer>();
  		for (Entry<Integer, Integer> mappingNumberToTimesUsedEntry : mappingNumberToTimesUsed.entrySet()) {
  			IndigoObject reactant = mappingNumberToReactant.get(mappingNumberToTimesUsedEntry.getKey());
  			if (timesReactantUsed.get(reactant)==null){
  				timesReactantUsed.put(reactant, mappingNumberToTimesUsedEntry.getValue());
  			}
  			else{
  				int timesUsed = timesReactantUsed.get(reactant);
  				if (mappingNumberToTimesUsedEntry.getValue() > timesUsed){
  					timesReactantUsed.put(reactant, mappingNumberToTimesUsedEntry.getValue());
  				}
  			}
  		}
  		for (Entry<IndigoObject, Integer> timesReactantUsedEntry : timesReactantUsed.entrySet()) {
  			String smiles =null;
  			for (IndigoObject data : timesReactantUsedEntry.getKey().iterateDataSGroups()) {
  				if (data.description().equals("smiles")){
  					smiles = data.rawData();
  					break;
  				}
  			}
  			if (smiles ==null){
  				throw new RuntimeException("Unable to find SMILES in S-group for indigio reactant!");
  			}
  			boolean setStoichiometry = false;
  			for (Chemical reactant : reaction.getReactants()) {
  				if (smiles.equals(reactant.getSmiles())){
  					reactant.setStoichiometry(timesReactantUsedEntry.getValue());
  					setStoichiometry = true;
  					break;
  				}
  			}
  			if (!setStoichiometry){
  				throw new RuntimeException("Unable to find molecule in CML with same SMILES used to create indigo reaction!");
  			}
  		}
  	}
  
  }
  