Logo Search packages:      
Sourcecode: cdk version File versions  Download package

SmilesGenerator.java

/*  $Revision: 9775 $ $Author: shk3 $ $Date: 2008-01-01 21:23:12 +0100 (Tue, 01 Jan 2008) $
 *  
 *  Copyright (C) 2002-2007  Oliver Horlacher
 *
 *  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.
 *  All we ask is that proper credit is given for our work, which includes
 *  - but is not limited to - adding the above copyright notice to the beginning
 *  of your source code files, and to any copyright notice that you may distribute
 *  with programs based on this work.
 *
 *  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.smiles;

import org.openscience.cdk.CDKConstants;
import org.openscience.cdk.aromaticity.HueckelAromaticityDetector;
import org.openscience.cdk.config.IsotopeFactory;
import org.openscience.cdk.exception.CDKException;
import org.openscience.cdk.geometry.BondTools;
import org.openscience.cdk.graph.ConnectivityChecker;
import org.openscience.cdk.graph.invariant.CanonicalLabeler;
import org.openscience.cdk.graph.invariant.MorganNumbersTools;
import org.openscience.cdk.interfaces.*;
import org.openscience.cdk.ringsearch.AllRingsFinder;
import org.openscience.cdk.ringsearch.RingPartitioner;
import org.openscience.cdk.tools.manipulator.RingSetManipulator;

import java.io.IOException;
import java.util.*;

/**
 * Generates SMILES strings {@cdk.cite WEI88, WEI89}. It takes into account the
 * isotope and formal charge information of the atoms. In addition to this it
 * takes stereochemistry in account for both Bond's and Atom's. Via the flag 
 * useAromaticity it can be set if only SP2-hybridized atoms shall be set to 
 * lower case (default) or atoms, which are SP2 or aromatic. IMPORTANT: The
 * aromaticity detection for this SmilesGenerator relies on AllRingsFinder,
 * which is known to take very long for some molecules with many cycles or
 * special cyclic topologies. Thus, the AllRingsFinder has a built-in timeout
 * of 5 seconds after which it aborts and throws an Exception. If you want your
 * SMILES generated at any expense, you need to create your own AllRingsFinder,
 * set the timeout to a higher value, and assign it to this SmilesGenerator. In
 * the vast majority of cases, however, the defaults will be fine.
 * If you have a set off ALL rings before, supply this via setRings to speed up generation.
 *
 * @author         Oliver Horlacher
 * @author         Stefan Kuhn (chiral smiles)
 * @cdk.created    2002-02-26
 * @cdk.keyword    SMILES, generator
 * @cdk.module     smiles
 * @cdk.bug        1257438
 * @cdk.bug        1535055
 */
00066 public class SmilesGenerator
{
      //private final static boolean debug = false;

      /**
       *  The number of rings that have been opened
       */
00073       private int ringMarker = 0;

      /**
       *  Collection of all the bonds that were broken
       */
00078       private Vector brokenBonds = new Vector();

      /**
       *  The isotope factory which is used to write the mass is needed
       */
00083       private IsotopeFactory isotopeFactory;

      AllRingsFinder ringFinder;

      /**
      * RingSet that holds all rings of the molecule
      */
00090       private IRingSet rings = null; 
      
      /**
       *  The canonical labler
       */
00095       private CanonicalLabeler canLabler = new CanonicalLabeler();
      private final String RING_CONFIG = "stereoconfig";
      private final String UP = "up";
      private final String DOWN = "down";
      private boolean useAromaticityFlag=false;

      /**
       *  Create the SMILES generator.
       */
00104       public SmilesGenerator() {}

      /**
       *  Tells if a certain bond is center of a valid double bond configuration.
       *
       *@param  container  The atomcontainer.
       *@param  bond       The bond.
       *@return            true=is a potential configuration, false=is not.
       */
00113       public boolean isValidDoubleBondConfiguration(IAtomContainer container, IBond bond)
      {
            IAtom atom0 = bond.getAtom(0);
            IAtom atom1 = bond.getAtom(1);
            java.util.List connectedAtoms = container.getConnectedAtomsList(atom0);
            org.openscience.cdk.interfaces.IAtom from = null;
            for (int i = 0; i < connectedAtoms.size(); i++)
            {
                  if ((IAtom)connectedAtoms.get(i) != atom1)
                  {
                        from = (IAtom)connectedAtoms.get(i);
                  }
            }
        boolean[] array = new boolean[container.getBondCount()];
            for (int i = 0; i < array.length; i++)
            {
                  array[i] = true;
            }
            if (isStartOfDoubleBond(container, atom0, from, array) && isEndOfDoubleBond(container, atom1, atom0, array) && !bond.getFlag(CDKConstants.ISAROMATIC))
            {
                  return (true);
            } else
            {
                  return (false);
            }
      }

      /**
       * Provide a reference to a RingSet that holds ALL rings of the molecule.<BR>
       * During creation of a SMILES the aromaticity of the molecule has to be detected.
       * This, in turn, requires the dermination of all rings of the molecule. If this
       * computationally expensive calculation has been done beforehand, a RingSet can
       * be handed over to the SmilesGenerator to save the effort of another all-rings-
       * calculation.
       *
       * @param  rings  RingSet that holds ALL rings of the molecule
       * @return        reference to the SmilesGenerator object this method was called for
       */
00151       public SmilesGenerator setRings(IRingSet rings)
      {
        this.rings = rings;
        return this;
      } 

      /**
       *  Generate canonical SMILES from the <code>molecule</code>. This method
       *  canonicaly lables the molecule but does not perform any checks on the
       *  chemical validity of the molecule.
       *  IMPORTANT: A precomputed Set of All Rings (SAR) can be passed to this 
       *  SmilesGenerator in order to avoid recomputing it. Use setRings() to 
       *  assign the SAR.
       *
       *@param  molecule  The molecule to evaluate
       *@see              org.openscience.cdk.graph.invariant.CanonicalLabeler#canonLabel(IAtomContainer)
       */
00168       public synchronized String createSMILES(IMolecule molecule)
      {
            try
            {
                  return (createSMILES(molecule, false, new boolean[molecule.getBondCount()]));
            } catch (CDKException exception)
            {
                  // This exception can only happen if a chiral smiles is requested
                  return ("");
            }
      }


      /**
       *  Generate a SMILES for the given <code>Reaction</code>.
       */
00184       public synchronized String createSMILES(IReaction reaction) throws CDKException
      {
            StringBuffer reactionSMILES = new StringBuffer();
            IMoleculeSet reactants = reaction.getReactants();
            for (int i = 0; i < reactants.getAtomContainerCount(); i++)
            {
                  reactionSMILES.append(createSMILES(reactants.getMolecule(i)));
                  if (i + 1 < reactants.getAtomContainerCount())
                  {
                        reactionSMILES.append('.');
                  }
            }
            reactionSMILES.append('>');
            IMoleculeSet agents = reaction.getAgents();
            for (int i = 0; i < agents.getAtomContainerCount(); i++)
            {
                  reactionSMILES.append(createSMILES(agents.getMolecule(i)));
                  if (i + 1 < agents.getAtomContainerCount())
                  {
                        reactionSMILES.append('.');
                  }
            }
            reactionSMILES.append('>');
            IMoleculeSet products = reaction.getProducts();
            for (int i = 0; i < products.getAtomContainerCount(); i++)
            {
                  reactionSMILES.append(createSMILES(products.getMolecule(i)));
                  if (i + 1 < products.getAtomContainerCount())
                  {
                        reactionSMILES.append('.');
                  }
            }
            return reactionSMILES.toString();
      }


      /**
       *  Generate canonical and chiral SMILES from the <code>molecule</code>. This
       *  method canonicaly lables the molecule but dose not perform any checks on
       *  the chemical validity of the molecule. The chiral smiles is done like in
       *  the <a href="http://www.daylight.com/dayhtml/doc/theory/theory.smiles.html">
       *  daylight theory manual</a> . I did not find rules for canonical and chiral
       *  smiles, therefore there is no guarantee that the smiles complies to any
       *  externeal rules, but it is canonical compared to other smiles produced by
       *  this method. The method checks if there are 2D coordinates but does not
       *  check if coordinates make sense. Invalid stereo configurations are ignored;
       *  if there are no valid stereo configuration the smiles will be the same as
       *  the non-chiral one. Note that often stereo configurations are only complete
       *  and can be converted to a smiles if explicit Hs are given.
       *  IMPORTANT: A precomputed Set of All Rings (SAR) can be passed to this 
       *  SmilesGenerator in order to avoid recomputing it. Use setRings() to 
       *  assign the SAR.
       *
       *@param  molecule                 The molecule to evaluate
       *@exception  CDKException         At least one atom has no Point2D;
       *      coordinates are needed for creating the chiral smiles.
       *@see                             org.openscience.cdk.graph.invariant.CanonicalLabeler#canonLabel(IAtomContainer)
       */
00242       public synchronized String createChiralSMILES(IMolecule molecule, boolean[] doubleBondConfiguration) throws CDKException
      {
            return (createSMILES(molecule, true, doubleBondConfiguration));
      }


      /**
       *  Generate canonical SMILES from the <code>molecule</code>. This method
       *  canonicaly lables the molecule but dose not perform any checks on the
       *  chemical validity of the molecule. This method also takes care of multiple
       *  molecules.
       *  IMPORTANT: A precomputed Set of All Rings (SAR) can be passed to this 
       *  SmilesGenerator in order to avoid recomputing it. Use setRings() to 
       *  assign the SAR.
       *
       *@param  molecule                 The molecule to evaluate
       *@param  chiral                   true=SMILES will be chiral, false=SMILES
       *      will not be chiral.
       *@exception  CDKException         At least one atom has no Point2D;
       *      coordinates are needed for crating the chiral smiles. This excpetion
       *      can only be thrown if chiral smiles is created, ignore it if you want a
       *      non-chiral smiles (createSMILES(AtomContainer) does not throw an
       *      exception).
       *@see                             org.openscience.cdk.graph.invariant.CanonicalLabeler#canonLabel(IAtomContainer)
       */
00267       public synchronized String createSMILES(IMolecule molecule, boolean chiral, boolean doubleBondConfiguration[]) throws CDKException
      {
            IMoleculeSet moleculeSet = ConnectivityChecker.partitionIntoMolecules(molecule);
            if (moleculeSet.getMoleculeCount() > 1)
            {
                  StringBuffer fullSMILES = new StringBuffer();
                  for (int i = 0; i < moleculeSet.getAtomContainerCount(); i++)
                  {
                        IMolecule molPart = moleculeSet.getMolecule(i);
                        fullSMILES.append(createSMILESWithoutCheckForMultipleMolecules(molPart, chiral, doubleBondConfiguration));
                        if (i < (moleculeSet.getAtomContainerCount() - 1))
                        {
                              // are there more molecules?
                              fullSMILES.append('.');
                        }
                  }
                  return fullSMILES.toString();
            } else
            {
                  return (createSMILESWithoutCheckForMultipleMolecules(molecule, chiral, doubleBondConfiguration));
            }
      }


      /**
       *  Generate canonical SMILES from the <code>molecule</code>. This method
       *  canonicaly lables the molecule but dose not perform any checks on the
       *  chemical validity of the molecule. Does not care about multiple molecules.
       *  IMPORTANT: A precomputed Set of All Rings (SAR) can be passed to this 
       *  SmilesGenerator in order to avoid recomputing it. Use setRings() to 
       *  assign the SAR.
       *
       *@param  molecule                 The molecule to evaluate
       *@param  chiral                   true=SMILES will be chiral, false=SMILES
       *      will not be chiral.
       *@exception  CDKException         At least one atom has no Point2D;
       *      coordinates are needed for creating the chiral smiles. This excpetion
       *      can only be thrown if chiral smiles is created, ignore it if you want a
       *      non-chiral smiles (createSMILES(AtomContainer) does not throw an
       *      exception).
       *@see                             org.openscience.cdk.graph.invariant.CanonicalLabeler#canonLabel(IAtomContainer)
       */
00309       public synchronized String createSMILESWithoutCheckForMultipleMolecules(IMolecule molecule, boolean chiral, boolean doubleBondConfiguration[]) throws CDKException
      {
            if (molecule.getAtomCount() == 0)
            {
                  return "";
            }
            canLabler.canonLabel(molecule);
            brokenBonds.clear();
            ringMarker = 0;
            org.openscience.cdk.interfaces.IAtom start = null;
            for (int i = 0; i < molecule.getAtomCount(); i++)
            {
                  org.openscience.cdk.interfaces.IAtom atom = molecule.getAtom(i);
                  if (chiral && atom.getPoint2d() == null)
                  {
                        throw new CDKException("Atom number " + i + " has no 2D coordinates, but 2D coordinates are needed for creating chiral smiles");
                  }
                  //logger.debug("Setting all VISITED flags to false");
                  atom.setFlag(CDKConstants.VISITED, false);
                  if (((Long) atom.getProperty("CanonicalLable")).longValue() == 1)
                  {
                        start = atom;
                  }
            }

            //detect aromaticity
            if(rings == null)
            {
                  if (ringFinder == null)
                  {
                        ringFinder = new AllRingsFinder();
                  }
                  rings = ringFinder.findAllRings(molecule);
            }
            HueckelAromaticityDetector.detectAromaticity(molecule, rings, false);
            if (chiral && rings.getAtomContainerCount() > 0)
            {
                  List v = RingPartitioner.partitionRings(rings);
                  //logger.debug("RingSystems: " + v.size());
                  for (int i = 0; i < v.size(); i++)
                  {
                        int counter = 0;
                        Iterator containers = RingSetManipulator.getAllAtomContainers((IRingSet) v.get(i)).iterator();
                        while (containers.hasNext()) {
                              IAtomContainer allrings = (IAtomContainer) containers.next();
                              for (int k = 0; k < allrings.getAtomCount(); k++)
                              {
                                    if (!BondTools.isStereo(molecule, allrings.getAtom(k)) && hasWedges(molecule, allrings.getAtom(k)) != null)
                                    {
                                          IBond bond = molecule.getBond(allrings.getAtom(k), hasWedges(molecule, allrings.getAtom(k)));
                                          if (bond.getStereo() == CDKConstants.STEREO_BOND_UP)
                                          {
                                                allrings.getAtom(k).setProperty(RING_CONFIG, UP);
                                          } else
                                          {
                                                allrings.getAtom(k).setProperty(RING_CONFIG, DOWN);
                                          }
                                          counter++;
                                    }
                              }
                              if (counter == 1)
                              {
                                    for (int k = 0; k < allrings.getAtomCount(); k++)
                                    {
                                          IBond bond = molecule.getBond(allrings.getAtom(k), hasWedges(molecule, allrings.getAtom(k)));
                                          if(bond!=null){
                                                if (bond.getStereo() == CDKConstants.STEREO_BOND_UP)
                                                {
                                                      allrings.getAtom(k).setProperty(RING_CONFIG, UP);
                                                } else
                                                {
                                                      allrings.getAtom(k).setProperty(RING_CONFIG, DOWN);
                                                }
                                          }
                                    }
                              }
                        }
                  }
            }

            StringBuffer l = new StringBuffer();
            createSMILES(start, l, molecule, chiral, doubleBondConfiguration,useAromaticityFlag);
            rings = null;
            
            // remove all CanonicalLable/InvariancePair props
            for (int k = 0; k < molecule.getAtomCount(); k++) {
                  molecule.getAtom(k).removeProperty("CanonicalLable");
                  molecule.getAtom(k).removeProperty("InvariancePair");
            }
            
            return l.toString();
      }

      private org.openscience.cdk.interfaces.IAtom hasWedges(IAtomContainer ac, org.openscience.cdk.interfaces.IAtom a)
      {
            List atoms = ac.getConnectedAtomsList(a);
            IAtom atomi = null;
//          for (int i = 0; i < atoms.size(); i++)
//          {
//                atomi = (IAtom)atoms.get(i);
//                if (ac.getBond(a, atomi).getStereo() != CDKConstants.STEREO_BOND_NONE && !atomi.getSymbol().equals("H"))
//                {
//                      return (atomi);
//                }
//          }
            for (int i = 0; i < atoms.size(); i++)
            {
                  atomi = (IAtom)atoms.get(i);
                  if (ac.getBond(a, atomi).getStereo() != CDKConstants.STEREO_BOND_NONE)
                  {
                        return (atomi);
                  }
            }
            return (null);
      }


      /**
       *  Says if an atom is the end of a double bond configuration
       *
       *@param  atom                     The atom which is the end of configuration
       *@param  container                The atomContainer the atom is in
       *@param  parent                   The atom we came from
       *@param  doubleBondConfiguration  The array indicating where double bond
       *      configurations are specified (this method ensures that there is
       *      actually the possibility of a double bond configuration)
       *@return                          false=is not end of configuration, true=is
       */
00437       private boolean isEndOfDoubleBond(IAtomContainer container, org.openscience.cdk.interfaces.IAtom atom, org.openscience.cdk.interfaces.IAtom parent, boolean[] doubleBondConfiguration)
      {
            if (container.getBondNumber(atom, parent) == -1 || doubleBondConfiguration.length <= container.getBondNumber(atom, parent) || !doubleBondConfiguration[container.getBondNumber(atom, parent)])
            {
                  return false;
            }
            // TO-DO: We make the silent assumption of unset hydrogen count equals zero hydrogen count here.
            int lengthAtom = container.getConnectedAtomsCount(atom) + ((atom.getHydrogenCount() == CDKConstants.UNSET) ? 0 : atom.getHydrogenCount());
            // TO-DO: We make the silent assumption of unset hydrogen count equals zero hydrogen count here.
            int lengthParent = container.getConnectedAtomsCount(parent) + ((parent.getHydrogenCount() == CDKConstants.UNSET) ? 0 : parent.getHydrogenCount());
            if (container.getBond(atom, parent) != null)
            {
                  if (container.getBond(atom, parent).getOrder() == CDKConstants.BONDORDER_DOUBLE && (lengthAtom == 3 || (lengthAtom == 2 && atom.getSymbol().equals("N"))) && (lengthParent == 3 || (lengthParent == 2 && parent.getSymbol().equals("N"))))
                  {
                        List atoms = container.getConnectedAtomsList(atom);
                        org.openscience.cdk.interfaces.IAtom one = null;
                        org.openscience.cdk.interfaces.IAtom two = null;
                        IAtom atomi = null;
                        for (int i = 0; i < atoms.size(); i++)
                        {
                              atomi = (IAtom)container.getAtom(i);
                              if (atomi != parent && one == null)
                              {
                                    one = atomi;
                              } else if (atomi != parent && one != null)
                              {
                                    two = atomi;
                              }
                        }
                        String[] morgannumbers = MorganNumbersTools.getMorganNumbersWithElementSymbol(container);
                        if ((one != null && two == null && atom.getSymbol().equals("N") && Math.abs(BondTools.giveAngleBothMethods(parent, atom, one, true)) > Math.PI / 10) || (!atom.getSymbol().equals("N") && one != null && two != null && !morgannumbers[container.getAtomNumber(one)].equals(morgannumbers[container.getAtomNumber(two)])))
                        {
                              return (true);
                        } else
                        {
                              return (false);
                        }
                  }
            }
            return (false);
      }


      /**
       *  Says if an atom is the start of a double bond configuration
       *
       *@param  a                        The atom which is the start of configuration
       *@param  container                The atomContainer the atom is in
       *@param  parent                   The atom we came from
       *@param  doubleBondConfiguration  The array indicating where double bond
       *      configurations are specified (this method ensures that there is
       *      actually the possibility of a double bond configuration)
       *@return                          false=is not start of configuration, true=is
       */
00491       private boolean isStartOfDoubleBond(IAtomContainer container, org.openscience.cdk.interfaces.IAtom a, org.openscience.cdk.interfaces.IAtom parent, boolean[] doubleBondConfiguration)
      {
            // TO-DO: We make the silent assumption of unset hydrogen count equals zero hydrogen count here.
            int lengthAtom = container.getConnectedAtomsCount(a) + ((a.getHydrogenCount() == CDKConstants.UNSET) ? 0 : a.getHydrogenCount());
            if (lengthAtom != 3 && (lengthAtom != 2 && a.getSymbol() != ("N")))
            {
                  return (false);
            }
            List atoms = container.getConnectedAtomsList(a);
            org.openscience.cdk.interfaces.IAtom one = null;
            org.openscience.cdk.interfaces.IAtom two = null;
            boolean doubleBond = false;
            org.openscience.cdk.interfaces.IAtom nextAtom = null;
            IAtom atomi = null;
            for (int i = 0; i < atoms.size(); i++)
            {
                  atomi = (IAtom)atoms.get(i);
                  if (atomi != parent && container.getBond(atomi, a).getOrder() == CDKConstants.BONDORDER_DOUBLE && isEndOfDoubleBond(container, atomi, a, doubleBondConfiguration))
                  {
                        doubleBond = true;
                        nextAtom = atomi;
                  }
                  if (atomi != nextAtom && one == null)
                  {
                        one = atomi;
                  } else if (atomi != nextAtom && one != null)
                  {
                        two = atomi;
                  }
            }
            String[] morgannumbers = MorganNumbersTools.getMorganNumbersWithElementSymbol(container);
            if (one != null && ((!a.getSymbol().equals("N") && two != null && !morgannumbers[container.getAtomNumber(one)].equals(morgannumbers[container.getAtomNumber(two)]) && doubleBond && doubleBondConfiguration[container.getBondNumber(a, nextAtom)]) || (doubleBond && a.getSymbol().equals("N") && Math.abs(BondTools.giveAngleBothMethods(nextAtom, a, parent, true)) > Math.PI / 10)))
            {
                  return (true);
            } else
            {
                  return (false);
            }
      }


      /**
       *  Gets the bondBroken attribute of the SmilesGenerator object
       */
00535       private boolean isBondBroken(IAtom a1, IAtom a2)
      {
            Iterator it = brokenBonds.iterator();
            while (it.hasNext())
            {
                  BrokenBond bond = ((BrokenBond) it.next());
                  if ((bond.getA1().equals(a1) || bond.getA1().equals(a2)) && (bond.getA2().equals(a1) || bond.getA2().equals(a2)))
                  {
                        return (true);
                  }
            }
            return false;
      }


      /**
       *  Determines if the atom <code>a</code> is a atom with a ring marker.
       *
       *@param  a  the atom to test
       *@return    true if the atom participates in a bond that was broken in the
       *      first pass.
       */
//    private boolean isRingOpening(IAtom a)
//    {
//          Iterator it = brokenBonds.iterator();
//          while (it.hasNext())
//          {
//                BrokenBond bond = (BrokenBond) it.next();
//                if (bond.getA1().equals(a) || bond.getA2().equals(a))
//                {
//                      return true;
//                }
//          }
//          return false;
//    }


      /**
       *  Determines if the atom <code>a</code> is a atom with a ring marker.
     *
       *@return     true if the atom participates in a bond that was broken in the
       *      first pass.
       */
00578       private boolean isRingOpening(IAtom a1, Vector v)
      {
            Iterator it = brokenBonds.iterator();
            while (it.hasNext())
            {
                  BrokenBond bond = (BrokenBond) it.next();
                  for (int i = 0; i < v.size(); i++)
                  {
                        if ((bond.getA1().equals(a1) && bond.getA2().equals((IAtom) v.get(i))) || (bond.getA1().equals((IAtom) v.get(i)) && bond.getA2().equals(a1)))
                        {
                              return true;
                        }
                  }
            }
            return false;
      }


      /**
       *  Return the neighbours of atom <code>a</code> in canonical order with the
       *  atoms that have high bond order at the front.
       *
       *@param  a          the atom whose neighbours are to be found.
       *@param  container  the AtomContainer that is being parsed.
       *@return            Vector of atoms in canonical oreder.
       */
00604       private List getCanNeigh(final org.openscience.cdk.interfaces.IAtom a, final IAtomContainer container)
      {
            List v = container.getConnectedAtomsList(a);
            if (v.size() > 1)
            {
                  Collections.sort(v,
                        new Comparator()
                        {
                              public int compare(Object o1, Object o2)
                              {
                                    return (int) (((Long) ((IAtom) o1).getProperty("CanonicalLable")).longValue() - ((Long) ((IAtom) o2).getProperty("CanonicalLable")).longValue());
                              }
                        });
            }
            return v;
      }


      /**
       *  Gets the ringOpenings attribute of the SmilesGenerator object
       */
00625       private Vector getRingOpenings(IAtom a, Vector vbonds)
      {
            Iterator it = brokenBonds.iterator();
            Vector v = new Vector(10);
            while (it.hasNext())
            {
                  BrokenBond bond = (BrokenBond) it.next();
                  if (bond.getA1().equals(a) || bond.getA2().equals(a))
                  {
                        v.add(new Integer(bond.getMarker()));
                        if (vbonds != null)
                        {
                              vbonds.add(bond.getA1().equals(a) ? bond.getA2() : bond.getA1());
                        }
                  }
            }
            Collections.sort(v);
            return v;
      }


      /**
       *  Returns true if the <code>atom</code> in the <code>container</code> has
       *  been marked as a chiral center by the user.
       */
//    private boolean isChiralCenter(IAtom atom, IAtomContainer container)
//    {
//          IBond[] bonds = container.getConnectedBonds(atom);
//          for (int i = 0; i < bonds.length; i++)
//          {
//                IBond bond = bonds[i];
//                int stereo = bond.getStereo();
//                if (stereo == CDKConstants.STEREO_BOND_DOWN ||
//                            stereo == CDKConstants.STEREO_BOND_UP)
//                {
//                      return true;
//                }
//          }
//          return false;
//    }


      /**
       *  Gets the last atom object (not Vector) in a Vector as created by
       *  createDSFTree.
       *
       *@param  v       The Vector
       *@param  result  The feature to be added to the Atoms attribute
       */
00674       private void addAtoms(Vector v, Vector result)
      {
            for (int i = 0; i < v.size(); i++)
            {
                  if (v.get(i) instanceof IAtom)
                  {
                        result.add((IAtom) v.get(i));
                  } else
                  {
                        addAtoms((Vector) v.get(i), result);
                  }
            }
      }
      
      /**
       *  Performes a DFS search on the <code>atomContainer</code>. Then parses the
       *  resulting tree to create the SMILES string.
       *
       *@param  a                        the atom to start the search at.
       *@param  line                     the StringBuffer that the SMILES is to be
       *      appended to.
       *@param  chiral                   true=SMILES will be chiral, false=SMILES
       *      will not be chiral.
       *@param  atomContainer            the AtomContainer that the SMILES string is
       *      generated for.
       *@param useAromaticity                   true=aromaticity or sp2 will trigger lower case letters, wrong=only sp2
       */
00701       private void createSMILES(org.openscience.cdk.interfaces.IAtom a, StringBuffer line, IAtomContainer atomContainer, boolean chiral, boolean[] doubleBondConfiguration, boolean useAromaticity)
      {
            Vector tree = new Vector();
            
            // set all ISVISITED labels to FALSE
            Iterator atoms = atomContainer.atoms();
            while (atoms.hasNext()) ((IAtom)atoms.next()).setFlag(CDKConstants.VISITED, false);
            
            createDFSTree(a, tree, null, atomContainer);
            //logger.debug("Done with tree");
            
            parseChain(tree, line, atomContainer, null, chiral, doubleBondConfiguration, new Vector(), useAromaticity);
      }


      /**
       *  Recursively perform a DFS search on the <code>container</code> placing
       *  atoms and branches in the vector <code>tree</code>.
       *
       *@param  a          the atom being visited.
       *@param  tree       vector holding the tree.
       *@param  parent     the atom we came from.
       *@param  container  the AtomContainer that we are parsing.
       */
00725       private void createDFSTree(org.openscience.cdk.interfaces.IAtom a, Vector tree, org.openscience.cdk.interfaces.IAtom parent, IAtomContainer container)
      {
            tree.add(a);
            List neighbours = getCanNeigh(a, container);
            neighbours.remove(parent);
            IAtom next;
            a.setFlag(CDKConstants.VISITED, true);
            //logger.debug("Starting with DFSTree and AtomContainer of size " + container.getAtomCount());
            //logger.debug("Current Atom has " + neighbours.size() + " neighbours");
            Iterator iter = neighbours.iterator();
            while (iter.hasNext()) {
                  next = (IAtom)iter.next();
                  if (!next.getFlag(CDKConstants.VISITED))
                  {
                        if (!iter.hasNext())
                        {
                              //Last neighbour therefore in this chain
                              createDFSTree(next, tree, a, container);
                        } else
                        {
                              Vector branch = new Vector();
                              tree.add(branch);
                              //logger.debug("adding branch");
                              createDFSTree(next, branch, a, container);
                        }
                  } else
                  {
                        //Found ring closure between next and a
                        //logger.debug("found ringclosure in DFTTreeCreation");
                        ringMarker++;
                        BrokenBond bond = new BrokenBond(a, next, ringMarker);
                        if (!brokenBonds.contains(bond))
                        {
                              brokenBonds.add(bond);
                        } else
                        {
                              ringMarker--;
                        }
                  }
            }
      }


      /**
       *  Parse a branch
       */
00771       private void parseChain(Vector v, StringBuffer buffer, IAtomContainer container, IAtom parent, boolean chiral, boolean[] doubleBondConfiguration, Vector atomsInOrderOfSmiles, boolean useAromaticity)
      {
            int positionInVector = 0;
            IAtom atom;
            //logger.debug("in parse chain. Size of tree: " + v.size());
            for (int h = 0; h < v.size(); h++)
            {
                  Object o = v.get(h);
                  if (o instanceof IAtom)
                  {
                        atom = (IAtom) o;
                        if (parent != null)
                        {
                              parseBond(buffer, atom, parent, container, useAromaticity);
                        } else
                        {
                              if (chiral && BondTools.isStereo(container, atom))
                              {
                                    parent = (IAtom) ((Vector) v.get(1)).get(0);
                              }
                        }
                        parseAtom(atom, buffer, container, chiral, doubleBondConfiguration, parent, atomsInOrderOfSmiles, v, useAromaticity);
                        //logger.debug("in parseChain after parseAtom()");
                        /*
                         *  The principle of making chiral smiles is quite simple, although the code is
                         *  pretty uggly. The Atoms connected to the chiral center are put in sorted[] in the
                         *  order they have to appear in the smiles. Then the Vector v is rearranged according
                         *  to sorted[]
                         */
                        if (chiral && BondTools.isStereo(container, atom) && container.getBond(parent, atom) != null)
                        {
                              //logger.debug("in parseChain in isChiral");
                              IAtom[] sorted = null;
                              List chiralNeighbours = container.getConnectedAtomsList(atom);
                              if (BondTools.isTetrahedral(container, atom,false) > 0)
                              {
                                    sorted = new IAtom[3];
                              }
                              if (BondTools.isTetrahedral(container, atom,false) == 1)
                              {
                                    if (container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_DOWN)
                                    {
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent)
                                                {
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == 0 && BondTools.isLeft(((IAtom) chiralNeighbours.get(i)), parent, atom) && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[2] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == 0 && !BondTools.isLeft(((IAtom) chiralNeighbours.get(i)), parent, atom) && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[1] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_UP && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[0] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                }
                                          }
                                    }
                                    if (container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_UP)
                                    {
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent)
                                                {
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == 0 && BondTools.isLeft(((IAtom) chiralNeighbours.get(i)), parent, atom) && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[1] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == 0 && !BondTools.isLeft(((IAtom) chiralNeighbours.get(i)), parent, atom) && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[2] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_DOWN && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[0] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                }
                                          }
                                    }
                                    if (container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_UNDEFINED || container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_NONE)
                                    {
                                          boolean normalBindingIsLeft = false;
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent)
                                                {
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == 0)
                                                      {
                                                            if (BondTools.isLeft(((IAtom) chiralNeighbours.get(i)), parent, atom))
                                                            {
                                                                  normalBindingIsLeft = true;
                                                                  break;
                                                            }
                                                      }
                                                }
                                          }
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent)
                                                {
                                                      if (normalBindingIsLeft)
                                                      {
                                                            if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == 0)
                                                            {
                                                                  sorted[0] = (IAtom) chiralNeighbours.get(i);
                                                            }
                                                            if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_UP)
                                                            {
                                                                  sorted[2] = (IAtom) chiralNeighbours.get(i);
                                                            }
                                                            if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_DOWN)
                                                            {
                                                                  sorted[1] = (IAtom) chiralNeighbours.get(i);
                                                            }
                                                      } else
                                                      {
                                                            if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_UP)
                                                            {
                                                                  sorted[1] = (IAtom) chiralNeighbours.get(i);
                                                            }
                                                            if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == 0)
                                                            {
                                                                  sorted[0] = (IAtom) chiralNeighbours.get(i);
                                                            }
                                                            if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_DOWN)
                                                            {
                                                                  sorted[2] = (IAtom) chiralNeighbours.get(i);
                                                            }
                                                      }
                                                }
                                          }
                                    }
                              }
                              if (BondTools.isTetrahedral(container, atom,false) == 2)
                              {
                                    if (container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_UP)
                                    {
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent)
                                                {
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_DOWN && BondTools.isLeft(((IAtom) chiralNeighbours.get(i)), parent, atom) && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[1] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_DOWN && !BondTools.isLeft(((IAtom) chiralNeighbours.get(i)), parent, atom) && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[2] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_UP && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[0] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                }
                                          }
                                    }
                                    if (container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_DOWN)
                                    {
                                          double angle1 = 0;
                                          double angle2 = 0;
                                          IAtom atom1 = null;
                                          IAtom atom2 = null;
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent)
                                                {
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_UP && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            if (angle1 == 0)
                                                            {
                                                                  angle1 = BondTools.giveAngle(atom, parent, (IAtom) chiralNeighbours.get(i));
                                                                  atom1 = (IAtom) chiralNeighbours.get(i);
                                                            } else
                                                            {
                                                                  angle2 = BondTools.giveAngle(atom, parent, (IAtom) chiralNeighbours.get(i));
                                                                  atom2 = (IAtom) chiralNeighbours.get(i);
                                                            }
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_DOWN && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[1] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                }
                                          }
                                          if (angle1 < angle2)
                                          {
                                                sorted[0] = atom2;
                                                sorted[2] = atom1;
                                          } else
                                          {
                                                sorted[0] = atom1;
                                                sorted[2] = atom2;
                                          }
                                    }
                              }
                              if (BondTools.isTetrahedral(container, atom,false) == 3)
                              {
                                    if (container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_UP)
                                    {
                                          TreeMap hm = new TreeMap();
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                {
                                                      hm.put(new Double(BondTools.giveAngle(atom, parent, ((IAtom) chiralNeighbours.get(i)))), new Integer(i));
                                                }
                                          }
                                          Object[] ohere = hm.values().toArray();
                                          for (int i = ohere.length - 1; i > -1; i--)
                                          {
                                                sorted[i] = ((IAtom) chiralNeighbours.get(((Integer) ohere[i]).intValue()));
                                          }
                                    }
                                    if (container.getBond(parent, atom).getStereo() == 0)
                                    {
                                          double angle1 = 0;
                                          double angle2 = 0;
                                          IAtom atom1 = null;
                                          IAtom atom2 = null;
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent)
                                                {
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == 0 && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            if (angle1 == 0)
                                                            {
                                                                  angle1 = BondTools.giveAngle(atom, parent, (IAtom) chiralNeighbours.get(i));
                                                                  atom1 = (IAtom) chiralNeighbours.get(i);
                                                            } else
                                                            {
                                                                  angle2 = BondTools.giveAngle(atom, parent, (IAtom) chiralNeighbours.get(i));
                                                                  atom2 = (IAtom) chiralNeighbours.get(i);
                                                            }
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_UP && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[0] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                }
                                          }
                                          if (angle1 < angle2)
                                          {
                                                sorted[1] = atom2;
                                                sorted[2] = atom1;
                                          } else
                                          {
                                                sorted[1] = atom1;
                                                sorted[2] = atom2;
                                          }
                                    }
                              }
                              if (BondTools.isTetrahedral(container, atom,false) == 4)
                              {
                                    if (container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_DOWN)
                                    {
                                          TreeMap hm = new TreeMap();
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                {
                                                      hm.put(new Double(BondTools.giveAngle(atom, parent, ((IAtom) chiralNeighbours.get(i)))), new Integer(i));
                                                }
                                          }
                                          Object[] ohere = hm.values().toArray();
                                          for (int i = ohere.length - 1; i > -1; i--)
                                          {
                                                sorted[i] = ((IAtom) chiralNeighbours.get(((Integer) ohere[i]).intValue()));
                                          }
                                    }
                                    if (container.getBond(parent, atom).getStereo() == 0)
                                    {
                                          double angle1 = 0;
                                          double angle2 = 0;
                                          IAtom atom1 = null;
                                          IAtom atom2 = null;
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent)
                                                {
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == 0 && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            if (angle1 == 0)
                                                            {
                                                                  angle1 = BondTools.giveAngle(atom, parent, (IAtom) chiralNeighbours.get(i));
                                                                  atom1 = (IAtom) chiralNeighbours.get(i);
                                                            } else
                                                            {
                                                                  angle2 = BondTools.giveAngle(atom, parent, (IAtom) chiralNeighbours.get(i));
                                                                  atom2 = (IAtom) chiralNeighbours.get(i);
                                                            }
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_DOWN && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[2] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                }
                                          }
                                          if (angle1 < angle2)
                                          {
                                                sorted[1] = atom2;
                                                sorted[0] = atom1;
                                          } else
                                          {
                                                sorted[1] = atom1;
                                                sorted[0] = atom2;
                                          }
                                    }
                              }
                              if (BondTools.isTetrahedral(container, atom,false) == 5)
                              {
                                    if (container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_DOWN)
                                    {
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent)
                                                {
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_UP)
                                                      {
                                                            sorted[0] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == 0)
                                                      {
                                                            sorted[2] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_DOWN)
                                                      {
                                                            sorted[1] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                }
                                          }
                                    }
                                    if (container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_UP)
                                    {
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent)
                                                {
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_DOWN && BondTools.isLeft(((IAtom) chiralNeighbours.get(i)), parent, atom) && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[0] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_DOWN && !BondTools.isLeft(((IAtom) chiralNeighbours.get(i)), parent, atom) && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[2] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == 0)
                                                      {
                                                            sorted[1] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                }
                                          }
                                    }
                                    if (container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_UNDEFINED || container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_NONE)
                                    {
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent)
                                                {
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_DOWN && BondTools.isLeft(((IAtom) chiralNeighbours.get(i)), parent, atom) && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[0] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_DOWN && !BondTools.isLeft(((IAtom) chiralNeighbours.get(i)), parent, atom) && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[2] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_UP)
                                                      {
                                                            sorted[1] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                }
                                          }
                                    }
                              }
                              if (BondTools.isTetrahedral(container, atom,false) == 6)
                              {
                                    if (container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_UP)
                                    {
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent)
                                                {
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_UP)
                                                      {
                                                            sorted[0] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == 0)
                                                      {
                                                            sorted[2] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_DOWN)
                                                      {
                                                            sorted[1] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                }
                                          }
                                    }
                                    if (container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_DOWN)
                                    {
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent)
                                                {
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_UP && BondTools.isLeft(((IAtom) chiralNeighbours.get(i)), parent, atom) && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[2] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_UP && !BondTools.isLeft(((IAtom) chiralNeighbours.get(i)), parent, atom) && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[0] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == 0)
                                                      {
                                                            sorted[1] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                }
                                          }
                                    }
                                    if (container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_UNDEFINED || container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_NONE)
                                    {
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent)
                                                {
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_UP && BondTools.isLeft(((IAtom) chiralNeighbours.get(i)), parent, atom) && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[2] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_UP && !BondTools.isLeft(((IAtom) chiralNeighbours.get(i)), parent, atom) && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                                      {
                                                            sorted[0] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond((IAtom) chiralNeighbours.get(i), atom).getStereo() == CDKConstants.STEREO_BOND_DOWN)
                                                      {
                                                            sorted[1] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                }
                                          }
                                    }
                              }
                              if (BondTools.isSquarePlanar(container, atom))
                              {
                                    sorted = new IAtom[3];
                                    //This produces a U=SP1 order in every case
                                    TreeMap hm = new TreeMap();
                                    for (int i = 0; i < chiralNeighbours.size(); i++)
                                    {
                                          if (chiralNeighbours.get(i) != parent && !isBondBroken((IAtom) chiralNeighbours.get(i), atom))
                                          {
                                                hm.put(new Double(BondTools.giveAngle(atom, parent, ((IAtom) chiralNeighbours.get(i)))), new Integer(i));
                                          }
                                    }
                                    Object[] ohere = hm.values().toArray();
                                    for (int i = 0; i < ohere.length; i++)
                                    {
                                          sorted[i] = ((IAtom) chiralNeighbours.get(((Integer) ohere[i]).intValue()));
                                    }
                              }
                              if (BondTools.isTrigonalBipyramidalOrOctahedral(container, atom)!=0)
                              {
                                    sorted = new IAtom[container.getConnectedAtomsCount(atom) - 1];
                                    TreeMap hm = new TreeMap();
                                    if (container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_UP)
                                    {
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (container.getBond(atom, (IAtom) chiralNeighbours.get(i)).getStereo() == 0)
                                                {
                                                      hm.put(new Double(BondTools.giveAngle(atom, parent, ((IAtom) chiralNeighbours.get(i)))), new Integer(i));
                                                }
                                                if (container.getBond(atom, (IAtom) chiralNeighbours.get(i)).getStereo() == CDKConstants.STEREO_BOND_DOWN)
                                                {
                                                      sorted[sorted.length - 1] = (IAtom) chiralNeighbours.get(i);
                                                }
                                          }
                                          Object[] ohere = hm.values().toArray();
                                          for (int i = 0; i < ohere.length; i++)
                                          {
                                                sorted[i] = ((IAtom) chiralNeighbours.get(((Integer) ohere[i]).intValue()));
                                          }
                                    }
                                    if (container.getBond(parent, atom).getStereo() == CDKConstants.STEREO_BOND_DOWN)
                                    {
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (container.getBond(atom, (IAtom) chiralNeighbours.get(i)).getStereo() == 0)
                                                {
                                                      hm.put(new Double(BondTools.giveAngle(atom, parent, ((IAtom) chiralNeighbours.get(i)))), new Integer(i));
                                                }
                                                if (container.getBond(atom, (IAtom) chiralNeighbours.get(i)).getStereo() == CDKConstants.STEREO_BOND_UP)
                                                {
                                                      sorted[sorted.length - 1] = (IAtom) chiralNeighbours.get(i);
                                                }
                                          }
                                          Object[] ohere = hm.values().toArray();
                                          for (int i = 0; i < ohere.length; i++)
                                          {
                                                sorted[i] = ((IAtom) chiralNeighbours.get(((Integer) ohere[i]).intValue()));
                                          }
                                    }
                                    if (container.getBond(parent, atom).getStereo() == 0)
                                    {
                                          for (int i = 0; i < chiralNeighbours.size(); i++)
                                          {
                                                if (chiralNeighbours.get(i) != parent)
                                                {
                                                      if (container.getBond(atom, (IAtom) chiralNeighbours.get(i)).getStereo() == 0)
                                                      {
                                                            hm.put(new Double((BondTools.giveAngleFromMiddle(atom, parent, ((IAtom) chiralNeighbours.get(i))))), new Integer(i));
                                                      }
                                                      if (container.getBond(atom, (IAtom) chiralNeighbours.get(i)).getStereo() == CDKConstants.STEREO_BOND_UP)
                                                      {
                                                            sorted[0] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                      if (container.getBond(atom, (IAtom) chiralNeighbours.get(i)).getStereo() == CDKConstants.STEREO_BOND_DOWN)
                                                      {
                                                            sorted[sorted.length - 2] = (IAtom) chiralNeighbours.get(i);
                                                      }
                                                }
                                          }
                                          Object[] ohere = hm.values().toArray();
                                          sorted[sorted.length - 1] = ((IAtom) chiralNeighbours.get(((Integer) ohere[ohere.length - 1]).intValue()));
                                          if (ohere.length == 2)
                                          {
                                                sorted[sorted.length - 3] = ((IAtom) chiralNeighbours.get(((Integer) ohere[0]).intValue()));
                                                if (BondTools.giveAngleFromMiddle(atom, parent, ((IAtom) chiralNeighbours.get(((Integer) ohere[1]).intValue()))) < 0)
                                                {
                                                      IAtom dummy = sorted[sorted.length - 2];
                                                      sorted[sorted.length - 2] = sorted[0];
                                                      sorted[0] = dummy;
                                                }
                                          }
                                          if (ohere.length == 3)
                                          {
                                                sorted[sorted.length - 3] = sorted[sorted.length - 2];
                                                sorted[sorted.length - 2] = ((IAtom) chiralNeighbours.get(((Integer) ohere[ohere.length - 2]).intValue()));
                                                sorted[sorted.length - 4] = ((IAtom) chiralNeighbours.get(((Integer) ohere[ohere.length - 3]).intValue()));
                                          }
                                    }
                              }
                              //This builds an onew[] containing the objects after the center of the chirality in the order given by sorted[]
                              if (sorted != null)
                              {
                                    int numberOfAtoms = 3;
                                    if (BondTools.isTrigonalBipyramidalOrOctahedral(container, atom)!=0)
                                    {
                                          numberOfAtoms = container.getConnectedAtomsCount(atom) - 1;
                                    }
                                    Object[] omy = new Object[numberOfAtoms];
                                    Object[] onew = new Object[numberOfAtoms];
                                    for (int k = getRingOpenings(atom, null).size(); k < numberOfAtoms; k++)
                                    {
                                          if (positionInVector + 1 + k - getRingOpenings(atom, null).size() < v.size())
                                          {
                                                omy[k] = v.get(positionInVector + 1 + k - getRingOpenings(atom, null).size());
                                          }
                                    }
                                    for (int k = 0; k < sorted.length; k++)
                                    {
                                          if (sorted[k] != null)
                                          {
                                                for (int m = 0; m < omy.length; m++)
                                                {
                                                      if (omy[m] instanceof IAtom)
                                                      {
                                                            if (omy[m] == sorted[k])
                                                            {
                                                                  onew[k] = omy[m];
                                                            }
                                                      } else
                                                      {
                                                            if (omy[m] == null)
                                                            {
                                                                  onew[k] = null;
                                                            } else
                                                            {
                                                                  if (((Vector) omy[m]).get(0) == sorted[k])
                                                                  {
                                                                        onew[k] = omy[m];
                                                                  }
                                                            }
                                                      }
                                                }
                                          } else
                                          {
                                                onew[k] = null;
                                          }
                                    }
                                    //This is a workaround for 3624.MOL.2 I don't have a better solution currently
                                    boolean doubleentry = false;
                                    for (int m = 0; m < onew.length; m++)
                                    {
                                          for (int k = 0; k < onew.length; k++)
                                          {
                                                if (m != k && onew[k] == onew[m])
                                                {
                                                      doubleentry = true;
                                                }
                                          }
                                    }
                                    if (!doubleentry)
                                    {
                                          //Make sure that the first atom in onew is the first one in the original smiles order. This is important to have a canonical smiles.
                                          if (positionInVector + 1 < v.size())
                                          {
                                                Object atomAfterCenterInOriginalSmiles = v.get(positionInVector + 1);
                                                int l = 0;
                                                while (onew[0] != atomAfterCenterInOriginalSmiles)
                                                {
                                                      Object placeholder = onew[onew.length - 1];
                                                      for (int k = onew.length - 2; k > -1; k--)
                                                      {
                                                            onew[k + 1] = onew[k];
                                                      }
                                                      onew[0] = placeholder;
                                                      l++;
                                                      if (l > onew.length)
                                                      {
                                                            break;
                                                      }
                                                }
                                          }
                                          //This cares about ring openings. Here the ring closure (represendted by a figure) must be the first atom. In onew the closure is null.
                                          if (getRingOpenings(atom, null).size() > 0)
                                          {
                                                int l = 0;
                                                while (onew[0] != null)
                                                {
                                                      Object placeholder = onew[0];
                                                      for (int k = 1; k < onew.length; k++)
                                                      {
                                                            onew[k - 1] = onew[k];
                                                      }
                                                      onew[onew.length - 1] = placeholder;
                                                      l++;
                                                      if (l > onew.length)
                                                      {
                                                            break;
                                                      }
                                                }
                                          }
                                          //The last in onew is a vector: This means we need to exchange the rest of the original smiles with the rest of this vector.
                                          if (onew[numberOfAtoms - 1] instanceof Vector)
                                          {
                                                for (int i = 0; i < numberOfAtoms; i++)
                                                {
                                                      if (onew[i] instanceof IAtom)
                                                      {
                                                            Vector vtemp = new Vector();
                                                            vtemp.add(onew[i]);
                                                            for (int k = positionInVector + 1 + numberOfAtoms; k < v.size(); k++)
                                                            {
                                                                  vtemp.add(v.get(k));
                                                            }
                                                            onew[i] = vtemp;
                                                            for (int k = v.size() - 1; k > positionInVector + 1 + numberOfAtoms - 1; k--)
                                                            {
                                                                  v.remove(k);
                                                            }
                                                            for (int k = 1; k < ((Vector) onew[numberOfAtoms - 1]).size(); k++)
                                                            {
                                                                  v.add(((Vector) onew[numberOfAtoms - 1]).get(k));
                                                            }
                                                            onew[numberOfAtoms - 1] = ((Vector) onew[numberOfAtoms - 1]).get(0);
                                                            break;
                                                      }
                                                }
                                          }
                                          //Put the onew objects in the original Vector
                                          int k = 0;
                                          for (int m = 0; m < onew.length; m++)
                                          {
                                                if (onew[m] != null)
                                                {
                                                      v.set(positionInVector + 1 + k, onew[m]);
                                                      k++;
                                                }
                                          }
                                    }
                              }
                        }
                        parent = atom;
                  } else
                  {
                        //Have Vector
                        //logger.debug("in parseChain after else");
                        boolean brackets = true;
                        Vector result = new Vector();
                        addAtoms((Vector) o, result);
                        if (isRingOpening(parent, result) && container.getConnectedBondsCount(parent) < 4)
                        {
                              brackets = false;
                        }
                        if (brackets)
                        {
                              buffer.append('(');
                        }
                        parseChain((Vector) o, buffer, container, parent, chiral, doubleBondConfiguration, atomsInOrderOfSmiles, useAromaticity);
                        if (brackets)
                        {
                              buffer.append(')');
                        }
                  }

                  positionInVector++;
                  //logger.debug("in parseChain after positionVector++");
            }
      }


      /**
       *  Append the symbol for the bond order between <code>a1</code> and <code>a2</code>
       *  to the <code>line</code>.
       *
       *@param  line           the StringBuffer that the bond symbol is appended to.
       *@param  a1             Atom participating in the bond.
       *@param  a2             Atom participating in the bond.
       *@param  atomContainer  the AtomContainer that the SMILES string is generated
       *      for.
       *@param useAromaticity                   true=aromaticity or sp2 will trigger lower case letters, wrong=only sp2
       */
01496       private void parseBond(StringBuffer line, IAtom a1, IAtom a2, IAtomContainer atomContainer, boolean useAromaticity)
      {
            //logger.debug("in parseBond()");
            if (useAromaticity && a1.getFlag(CDKConstants.ISAROMATIC) && a2.getFlag(CDKConstants.ISAROMATIC))
            {
                  return;
            }
            if (atomContainer.getBond(a1, a2) == null)
            {
                  return;
            }
            int type = 0;
            type = (int) atomContainer.getBond(a1, a2).getOrder();
            if (type == 1)
            {
            } else if (type == 2)
            {
                  line.append("=");

            } else if (type == 3)
            {
                  line.append("#");
            } else
            {
                  // //logger.debug("Unknown bond type");
            }
      }


      /**
       *  Generates the SMILES string for the atom
       *
       *@param  a                        the atom to generate the SMILES for.
       *@param  buffer                   the string buffer that the atom is to be
       *      apended to.
       *@param  container                the AtomContainer to analyze.
       *@param  chiral                   is a chiral smiles wished?
       *@param  parent                   the atom we came from.
       *@param  atomsInOrderOfSmiles     a vector containing the atoms in the order
       *      they are in the smiles.
       *@param  currentChain             The chain we currently deal with.
       *@param useAromaticity                   true=aromaticity or sp2 will trigger lower case letters, wrong=only sp2
       */
01539       private void parseAtom(IAtom a, StringBuffer buffer, IAtomContainer container, boolean chiral, boolean[] doubleBondConfiguration, IAtom parent, Vector atomsInOrderOfSmiles, Vector currentChain, boolean useAromaticity)
      {
            String symbol = a.getSymbol();
            boolean stereo = BondTools.isStereo(container, a);
            boolean brackets = symbol.equals("B") || symbol.equals("C") || symbol.equals("N") || symbol.equals("O") || symbol.equals("P") || symbol.equals("S") || symbol.equals("F") || symbol.equals("Br") || symbol.equals("I") || symbol.equals("Cl");
            brackets = !brackets;
            //logger.debug("in parseAtom()");
            //Deal with the start of a double bond configuration
            if (isStartOfDoubleBond(container, a, parent, doubleBondConfiguration))
            {
                  buffer.append('/');
            }

            if (a instanceof IPseudoAtom)
            {
                  buffer.append("[*]");
            } else
            {
                  String mass = generateMassString(a);
                  brackets = brackets | !mass.equals("");

                  String charge = generateChargeString(a);
                  brackets = brackets | !charge.equals("");

                  if (chiral && stereo && (BondTools.isTrigonalBipyramidalOrOctahedral(container, a)!=0 || BondTools.isSquarePlanar(container, a) || BondTools.isTetrahedral(container, a,false) != 0 || BondTools.isSquarePlanar(container, a)))
                  {
                        brackets = true;
                  }
                  if (brackets)
                  {
                        buffer.append('[');
                  }
                  buffer.append(mass);
                  if ((useAromaticity && a.getFlag(CDKConstants.ISAROMATIC)) || (a.getHybridization() != CDKConstants.UNSET && a.getHybridization() == CDKConstants.HYBRIDIZATION_SP2))
                  {
                        buffer.append(a.getSymbol().toLowerCase());
                  } else
                  {
                        buffer.append(symbol);
                  }
                  if (a.getProperty(RING_CONFIG) != null && a.getProperty(RING_CONFIG).equals(UP))
                  {
                        buffer.append('/');
                  }
                  if (a.getProperty(RING_CONFIG) != null && a.getProperty(RING_CONFIG).equals(DOWN))
                  {
                        buffer.append('\\');
                  }
                  if (chiral && stereo && (BondTools.isTrigonalBipyramidalOrOctahedral(container, a)!=0 || BondTools.isSquarePlanar(container, a) || BondTools.isTetrahedral(container, a,false) != 0))
                  {
                        buffer.append('@');
                  }
                  if (chiral && stereo && BondTools.isSquarePlanar(container, a))
                  {
                        buffer.append("SP1");
                  }
                  //chiral
                  //hcount
                  buffer.append(charge);
                  if (brackets)
                  {
                        buffer.append(']');
                  }
            }
            //logger.debug("in parseAtom() after dealing with Pseudoatom or not");
            //Deal with the end of a double bond configuration
            if (isEndOfDoubleBond(container, a, parent, doubleBondConfiguration))
            {
                  IAtom viewFrom = null;
                  for (int i = 0; i < currentChain.size(); i++)
                  {
                        if (currentChain.get(i) == parent)
                        {
                              int k = i - 1;
                              while (k > -1)
                              {
                                    if (currentChain.get(k) instanceof IAtom)
                                    {
                                          viewFrom = (IAtom) currentChain.get(k);
                                          break;
                                    }
                                    k--;
                              }
                        }
                  }
                  if (viewFrom == null)
                  {
                        for (int i = 0; i < atomsInOrderOfSmiles.size(); i++)
                        {
                              if (atomsInOrderOfSmiles.get(i) == parent)
                              {
                                    viewFrom = (IAtom) atomsInOrderOfSmiles.get(i - 1);
                              }
                        }
                  }
                  boolean afterThisAtom = false;
                  IAtom viewTo = null;
                  for (int i = 0; i < currentChain.size(); i++)
                  {
                        if (afterThisAtom && currentChain.get(i) instanceof IAtom)
                        {
                              viewTo = (IAtom) currentChain.get(i);
                              break;
                        }
                        if (afterThisAtom && currentChain.get(i) instanceof Vector)
                        {
                              viewTo = (IAtom) ((Vector) currentChain.get(i)).get(0);
                              break;
                        }
                        if (a == currentChain.get(i))
                        {
                              afterThisAtom = true;
                        }
                  }
      try{
        if (BondTools.isCisTrans(viewFrom,a,parent,viewTo,container))
        {
          buffer.append('\\');
        } else
        {
          buffer.append('/');
        }
      }catch(CDKException ex){
        //If the user wants a double bond configuration, where there is none, we ignore this.
      }
            }
            Vector v = new Vector();
            Iterator it = getRingOpenings(a, v).iterator();
            Iterator it2 = v.iterator();
            //logger.debug("in parseAtom() after checking for Ring openings");
            while (it.hasNext())
            {
                  Integer integer = (Integer) it.next();
                  IAtom a2=(IAtom) it2.next();
                  IBond b = container.getBond(a2, a);
                  int type = (int) b.getOrder();
                  if (!(useAromaticity && a.getFlag(CDKConstants.ISAROMATIC) && a2.getFlag(CDKConstants.ISAROMATIC))){
                        if (type == 2) {
                              buffer.append("=");
                        } else if (type == 3) {
                              buffer.append("#");
                        }
                  }
                  buffer.append(integer);
            }
            atomsInOrderOfSmiles.add(a);
            //logger.debug("End of parseAtom()");
      }


      /**
       *  Creates a string for the charge of atom <code>a</code>. If the charge is 1
       *  + is returned if it is -1 - is returned. The positive values all have + in
       *  front of them.
       *
       *@return    string representing the charge on <code>a</code>
       */
01696       private String generateChargeString(IAtom a)
      {
            int charge = a.getFormalCharge();
            StringBuffer buffer = new StringBuffer(3);
            if (charge > 0)
            {
                  //Positive
                  buffer.append('+');
                  if (charge > 1)
                  {
                        buffer.append(charge);
                  }
            } else if (charge < 0)
            {
                  //Negative
                  if (charge == -1)
                  {
                        buffer.append('-');
                  } else
                  {
                        buffer.append(charge);
                  }
            }
            return buffer.toString();
      }


      /**
       *  Creates a string containing the mass of the atom <code>a</code>. If the
       *  mass is the same as the majour isotope an empty string is returned.
       *
       *@param  a  the atom to create the mass
       */
01729       private String generateMassString(IAtom a)
      {
            if (isotopeFactory == null) setupIsotopeFactory(a.getBuilder());

        if (a instanceof IPseudoAtom) return Integer.toString(a.getMassNumber());

        IIsotope majorIsotope = isotopeFactory.getMajorIsotope(a.getSymbol());
            if (majorIsotope.getMassNumber() == a.getMassNumber())
            {
                  return "";
            } else if (a.getMassNumber() == 0)
            {
                  return "";
            } else
            {
                  return Integer.toString(a.getMassNumber());
            }
      }


      private void setupIsotopeFactory(IChemObjectBuilder builder) {
            try {
                  isotopeFactory = IsotopeFactory.getInstance(builder);
            } catch (IOException e) {
                  e.printStackTrace();
            }
    }


      class BrokenBond
      {

            /**
             *  The atoms which close the ring
             */
            private org.openscience.cdk.interfaces.IAtom a1, a2;

            /**
             *  The number of the marker
             */
            private int marker;


            /**
             *  Construct a BrokenBond between <code>a1</code> and <code>a2</code> with
             *  the marker <code>marker</code>.
             *
             *@param  marker  the ring closure marker. (Great comment!)
             */
            BrokenBond(org.openscience.cdk.interfaces.IAtom a1, org.openscience.cdk.interfaces.IAtom a2, int marker)
            {
                  this.a1 = a1;
                  this.a2 = a2;
                  this.marker = marker;
            }


            /**
             *  Getter method for a1 property
             *
             *@return    The a1 value
             */
            public org.openscience.cdk.interfaces.IAtom getA1()
            {
                  return a1;
            }


            /**
             *  Getter method for a2 property
             *
             *@return    The a2 value
             */
            public org.openscience.cdk.interfaces.IAtom getA2()
            {
                  return a2;
            }


            /**
             *  Getter method for marker property
             *
             *@return    The marker value
             */
            public int getMarker()
            {
                  return marker;
            }


            public String toString()
            {
                  return Integer.toString(marker);
            }


            public boolean equals(Object o)
            {
                  if (!(o instanceof BrokenBond))
                  {
                        return false;
                  }
                  BrokenBond bond = (BrokenBond) o;
                  return (a1.equals(bond.getA1()) && a2.equals(bond.getA2())) || (a1.equals(bond.getA2()) && a2.equals(bond.getA1()));
            }
      }


      /**
       *  Returns the current AllRingsFinder instance
       *
       *@return   the current AllRingsFinder instance
       */
01842       public AllRingsFinder getRingFinder()
      {
            return ringFinder;
      }


      /**
       *  Sets the current AllRingsFinder instance
       * Use this if you want to customize the timeout for 
       * the AllRingsFinder. AllRingsFinder is stopping its 
       * quest to find all rings after a default of 5 seconds.
       *
       * @see org.openscience.cdk.ringsearch.AllRingsFinder
       * 
       * @param  ringFinder  The value to assign ringFinder.
       */
01858       public void setRingFinder(AllRingsFinder ringFinder)
      {
            this.ringFinder = ringFinder;
      }

      /**
       * @param false=only SP2-hybridized atoms will be lower case (default), true=SP2 or aromaticity trigger lower case 
       */
01866       public void setUseAromaticityFlag(boolean useAromaticityFlag) {
            this.useAromaticityFlag = useAromaticityFlag;
      }

}



Generated by  Doxygen 1.6.0   Back to index