/* $RCSfile$
* $Author$
* $Date$
* $Revision$
*
* Copyright (C) 2007 Miguel Rojasch <miguelrojasch@users.sf.net>
*
* Contact: cdk-devel@lists.sourceforge.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.openscience.cdk.formula;
import org.openscience.cdk.DefaultChemObjectBuilder;
import org.openscience.cdk.annotations.TestClass;
import org.openscience.cdk.annotations.TestMethod;
import org.openscience.cdk.interfaces.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Class defining an adduct object in a MolecularFormula. It maintains
* a list of list IMolecularFormula.<p>
*
* Examples:
* <ul>
* <li><code>[C2H4O2+Na]+</code></li>
* </ul>
*
* @cdk.module data
* @author miguelrojasch
* @cdk.created 2007-11-20
* @cdk.keyword molecular formula
*/
@TestClass("org.openscience.cdk.formula.AdductFormulaTest")
public class AdductFormula implements Iterable<IMolecularFormula>, IAdductFormula, Cloneable{
/**
* Determines if a de-serialized object is compatible with this class.
*
* This value must only be changed if and only if the new version
* of this class is incompatible with the old version. See Sun docs
* for <a href=http://java.sun.com/products/jdk/1.1/docs/guide
* /serialization/spec/version.doc.html>details</a>.
*/
private static final long serialVersionUID = -811384981700039389L;
/** Internal List of IMolecularFormula. */
private List<IMolecularFormula> components;
/**
* Constructs an empty AdductFormula.
*
* @see #AdductFormula(IMolecularFormula)
*/
public AdductFormula() {
components = new ArrayList<IMolecularFormula>();
}
/**
* Constructs an AdductFormula with a copy AdductFormula of another
* AdductFormula (A shallow copy, i.e., with the same objects as in
* the original AdductFormula).
*
* @param formula An MolecularFormula to copy from
* @see #AdductFormula()
*/
public AdductFormula(IMolecularFormula formula) {
components = new ArrayList<IMolecularFormula>();
components.add(0, formula);
}
/**
* Adds an molecularFormula to this chemObject.
*
* @param formula The molecularFormula to be added to this chemObject
*/
@TestMethod("testAddMolecularFormula_IMolecularFormula")
public void addMolecularFormula(IMolecularFormula formula) {
components.add(formula);
}
/**
* Adds all molecularFormulas in the AdductFormula to this chemObject.
*
* @param formulaSet The MolecularFormulaSet
*/
@TestMethod("testAdd_IMolecularFormulaSet")
public void add(IMolecularFormulaSet formulaSet) {
for (IMolecularFormula mf : formulaSet.molecularFormulas()){
addMolecularFormula(mf);
}
/*
* notifyChanged() is called by addAtomContainer()
*/
}
/**
* True, if the AdductFormula contains the given IIsotope object and not
* the instance. The method looks for other isotopes which has the same
* symbol, natural abundance and exact mass.
*
* @param isotope The IIsotope this AdductFormula is searched for
* @return True, if the AdductFormula contains the given isotope object
*/
@TestMethod("testContains_IIsotope")
public boolean contains(IIsotope isotope) {
for(Iterator<IIsotope> it = isotopes().iterator(); it.hasNext(); ) {
IIsotope thisIsotope = it.next();
if(isTheSame(thisIsotope, isotope)){
return true;
}
}
return false;
}
/**
* Returns the partial charge of this Adduct. If the charge
* has not been set the return value is Double.NaN.
*
* @return the charge of this Adduct
*
* @see #setCharge
*/
@TestMethod("testGetCharge")
public Integer getCharge() {
Integer charge = 0;
Iterator<IMolecularFormula> componentIterator = components.iterator();
while (componentIterator.hasNext()) {
charge += componentIterator.next().getCharge();
}
return charge;
}
/**
* Checks a set of Nodes for the occurrence of the isotope in the
* adduct formula from a particular isotope. It returns 0 if the does not exist.
*
* @param isotope The IIsotope to look for
* @return The occurrence of this isotope in this adduct
* @see #getIsotopeCount()
*/
@TestMethod("testGetIsotopeCount_IIsotope")
public int getIsotopeCount(IIsotope isotope) {
int count = 0;
Iterator<IMolecularFormula> componentIterator = components.iterator();
while (componentIterator.hasNext()) {
count += componentIterator.next().getIsotopeCount(isotope);
}
return count;
}
/**
* Checks a set of Nodes for the number of different isotopes in the
* adduct formula.
*
* @return The the number of different isotopes in this adduct formula
* @see #getIsotopeCount(IIsotope)
*/
@TestMethod("testGetIsotopeCount")
public int getIsotopeCount() {
return isotopesList().size();
}
/**
* Returns an Iterator for looping over all isotopes in this adduct formula.
*
* @return An Iterator with the isotopes in this adduct formula
*/
@TestMethod("testIsotopes")
public Iterable<IIsotope> isotopes() {
return new Iterable() {
public Iterator iterator() {
return isotopesList().iterator();
}
};
}
/**
* Returns a List for looping over all isotopes in this adduct formula.
*
* @return A List with the isotopes in this adduct formula
*/
private List<IIsotope> isotopesList() {
List<IIsotope> isotopes = new ArrayList<IIsotope>();
Iterator<IMolecularFormula> componentIterator = components.iterator();
while (componentIterator.hasNext()) {
Iterator<IIsotope> compIsotopes = componentIterator.next().isotopes().iterator();
while (compIsotopes.hasNext()) {
IIsotope isotope = compIsotopes.next();
if (!isotopes.contains(isotope)) {
isotopes.add(isotope);
}
}
}
return isotopes;
}
/**
* No use this method. The charge is defined in each
* IMolecularFormula.
*
* @param charge The partial charge
* @deprecated
*
* @see #getCharge
*/
@TestMethod("testSetCharge")
public void setCharge(Integer charge) {
throw new java.lang.IllegalAccessError();
}
/**
* Returns an Iterable for looping over all IMolecularFormula
* in this adduct formula.
*
* @return An Iterable with the IMolecularFormula in this adduct formula
*/
@TestMethod("testMolecularFormulas")
public Iterable<IMolecularFormula> molecularFormulas() {
return components;
}
/**
* Returns an Iterator for looping over all IMolecularFormula
* in this adduct formula.
*
* @return An Iterator with the IMolecularFormula in this adduct formula
*/
@TestMethod("testIterator")
public Iterator<IMolecularFormula> iterator() {
return components.iterator();
}
/**
* Returns the number of MolecularFormulas in this AdductFormula.
*
* @return The number of MolecularFormulas in this AdductFormula
*/
@TestMethod("testSize")
public int size() {
return components.size();
}
/**
* True, if the AdductFormula contains the given IMolecularFormula object.
*
* @param formula The IMolecularFormula this AdductFormula is searched for
* @return True, if the AdductFormula contains the given IMolecularFormula object
*/
@TestMethod("testContains_IMolecularFormula")
public boolean contains(IMolecularFormula formula) {
return components.contains(formula);
}
/**
*
* Returns the MolecularFormula at position <code>number</code> in the
* chemObject.
*
* @param position The position of the IMolecularFormula to be returned.
* @return The IMolecularFormula at position <code>number</code> .
*/
@TestMethod("testGetMolecularFormulas_int")
public IMolecularFormula getMolecularFormula(int position) {
return components.get(position);
}
/**
* Removes all IMolecularFormula from this chemObject.
*/
@TestMethod("testRemoveAllMolecularFormulas")
public void removeAllMolecularFormulas() {
components.clear();
}
/**
* Removes an IMolecularFormula from this chemObject.
*
* @param formula The IMolecularFormula to be removed from this chemObject
*/
@TestMethod("testRemoveMolecularFormula_IMolecularFormula")
public void removeMolecularFormula(IMolecularFormula formula) {
components.remove(formula);
}
/**
* Removes an MolecularFormula from this chemObject.
*
* @param position The position of the MolecularFormula to be removed from this chemObject
*/
@TestMethod("testRemoveMolecularFormula_int")
public void removeMolecularFormula(int position) {
components.remove(position);
}
/**
* Clones this AdductFormula object and its content.
*
* @return The cloned object
*/
@TestMethod("testClone")
public Object clone() throws CloneNotSupportedException {
// /* it is not a super class of chemObject */
// AdductFormula clone = (AdductFormula) super.clone();
// // start from scratch
// clone.removeAllMolecularFormulas();
// // clone all molecularFormulas
// Iterator<IMolecularFormula> iterForm = this.molecularFormulas();
// while(iterForm.hasNext()){
// clone.addMolecularFormula((IMolecularFormula) iterForm.next().clone());
// }
AdductFormula clone = new AdductFormula();
for(IMolecularFormula form: this.molecularFormulas()){
clone.addMolecularFormula((IMolecularFormula) form.clone());
}
return clone;
}
/**
* Compare to IIsotope. The method doesn't compare instance but if they
* have the same symbol, natural abundance and exact mass.
*
* @param isotopeOne The first Isotope to compare
* @param isotopeTwo The second Isotope to compare
* @return True, if both isotope are the same
*/
private boolean isTheSame(IIsotope isotopeOne, IIsotope isotopeTwo) {
if(isotopeOne.getSymbol() != isotopeTwo.getSymbol() )
return false;
if(isotopeOne.getNaturalAbundance() != isotopeTwo.getNaturalAbundance() )
return false;
if(isotopeOne.getExactMass() != isotopeTwo.getExactMass() )
return false;
return true;
}
public IChemObjectBuilder getBuilder() {
return DefaultChemObjectBuilder.getInstance();
}
}