content: /*
   * Copyright (c) 1997 - 2016
   * Actelion Pharmaceuticals Ltd.
   * Gewerbestrasse 16
   * CH-4123 Allschwil, Switzerland
   *
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are met:
   *
   * 1. Redistributions of source code must retain the above copyright notice, this
   *    list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright notice,
   *    this list of conditions and the following disclaimer in the documentation
   *    and/or other materials provided with the distribution.
   * 3. Neither the name of the the copyright holder nor the
   *    names of its contributors may be used to endorse or promote products
   *    derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  package com.actelion.research.chem;
  
  import java.util.*;
  
  public class Molecule3D extends StereoMolecule implements Comparable<Molecule3D> {
  	public static final int RIGID					= 0x00000001;
  	public static final int LIGAND					= 0x00000002;
  	public static final int BACKBONE				= 0x00000004;
  	public static final int FLAG1					= 0x00000008; //Flag used for different purpose
  	public static final int IMPORTANT				= 0x00000010;
  	public static final int PREOPTIMIZED			= 0x00000020;
  	public static final int ATTACHED_HYDROGEN_COUNT = 0x000003C0; // explicitly known hydrogens without coordinates
  	public static final int ATTACHED_HYDROGEN_COUNT_SHIFT = 6;
  
  	public static final int INFO_DESCRIPTION = 0;
  	public static final int INFO_ATOMSEQUENCE = 1;
  	public static final int INFO_INTERACTION_ATOM_TYPE = 2;
  	public static final int INFO_ATOMNAME = 3;
  	public static final int INFO_AMINO = 4;
  	public static final int INFO_PPP = 5;
  	public static final int INFO_CHAINID = 6;
  	public static final int INFO_BFACTOR = 7;
  	public static final int INFO_RESSEQUENCE = 8;
  
  	private static final int MAX_INFOS = 9;
  
  	//Molecule information
  	private int nMovables = -1;
  	private final Map<String, Object> auxiliaryInfos = new HashMap<String, Object>();
  
  	//Atom information
  	private int[] atomFlags;
  	private Object[][] infos;
  	private double[] partialCharges;
  	private boolean isCovalentLigand;
  
  	//Molecule properties (calculated during the first call at getRings)
  	//private List<Integer>[] mAtomToRings = null;
  
  
  	public Molecule3D(Molecule3D mol) {
  		super(mol);
  
  		auxiliaryInfos.putAll(mol.auxiliaryInfos);
  
  		atomFlags = new int[mol.getMaxAtoms()];
  		partialCharges = new double[mol.getMaxAtoms()];
  		infos = new Object[mol.getMaxAtoms()][MAX_INFOS];
  
  		for(int atom=0; atom<mol.getAllAtoms(); atom++) {
  			atomFlags[atom] = mol.atomFlags[atom];
  			partialCharges[atom] = mol.partialCharges[atom];
  			for (int i=0; i<MAX_INFOS; i++)
  				infos[atom][i] = mol.infos[atom][i];
  		}
  	}
  	
  	public Molecule3D(StereoMolecule mol) {
  		super(mol);
  		atomFlags = new int[mol.getMaxAtoms()];
  		partialCharges = new double[mol.getMaxAtoms()];
  		infos = new Object[mol.getMaxAtoms()][MAX_INFOS];
  	}
  
  	public Molecule3D() {
  		this(5, 5);
  	}
  
  	public Molecule3D(int a, int b) {
  		super(a, b);
  
  		setName("Molecule");
  		atomFlags   = new int[a];
  		partialCharges = new double[a];
  		infos = new Object[a][MAX_INFOS];
  //		mm2AtomTypes = new int[a];
  //		mmffAtomTypes = new int[a];
  //		classIds = new int[a];
  	}
  
  	@Override
  	public int getOccupiedValence(int atom) {
  		return super.getOccupiedValence(atom) + getAttachedHydrogenCount(atom);
  	}
  
  	public int getAttachedHydrogenCount(int atom) {
  		return (atomFlags[atom] & ATTACHED_HYDROGEN_COUNT) >> ATTACHED_HYDROGEN_COUNT_SHIFT;
  	}
  
  	/**
  	 * Defines a number of attached hydrogens without known 3D-coordinates
  	 * @param atom
  	 * @param value 0 to 3
  	 */
  	public void setAttachedHydrogenCount(int atom, int value) {
  		atomFlags[atom] |= (value << ATTACHED_HYDROGEN_COUNT_SHIFT);
  	}
  
  		@Override
  	public String toString() {
  		return (getName() !=null ? getName() : "");
  	}
  
  	public void clear() {
  		super.deleteMolecule();
  	}
  
  	public final void setAtomFlag(int atm, int flag, boolean value) {
  		nMovables = -1;
  		if(value) atomFlags[atm] |= flag;
  		else atomFlags[atm] &= ~flag;
  	}
  
  	public final boolean isAtomFlag(int atm, int flag) {
  		return (atomFlags[atm] & flag) != 0;
  	}
  	public final int getAtomFlags(int atm) {
  		return atomFlags[atm];
  	}
  	public final void setAtomFlags(int atm, int flags) {
  		nMovables = -1;
  		atomFlags[atm] = flags;
  	}
  	public final void setAllAtomFlag(int flag, boolean value) {
  		nMovables = -1;
  		for (int i = 0; i < getAllAtoms(); i++) setAtomFlag(i, flag, value);
  	}
  
  	/**
  	 * This method will append a Molecule3D to the end.
  	 * @param m2
  	 * @return the index dividing the 2 molecules
  	 */
  	public int fusion(Molecule3D m2) {
  		if(m2==this) throw new IllegalArgumentException("Cannot fusion a molecule with itself");
  		int index = getAllAtoms();
  		int[] oldToNew = new int[m2.getAllAtoms()];
  		for(int i=0; i<m2.getAllAtoms(); i++) {
  			oldToNew[i] = addAtom(m2, i);
  		}
  		for(int i=0; i<m2.getAllBonds(); i++) {
  			addBond(oldToNew[m2.getBondAtom(0, i)], oldToNew[m2.getBondAtom(1, i)], m2.getBondOrder(i));
  		}
  		return index;
  	}
  
  /*	public int fusionKeepCoordinatesObjects(Molecule3D m2) {
  		int i = getAllAtoms();
  		int res = fusion(m2);
  		System.arraycopy(m2.getCoordinates(), 0, getCoordinates(), i, m2.getAllAtoms());
  		return res;
  
  	}*/
  
  	public void setBondOrder(int bond, int order) {
  		if (order == 1)
  			super.setBondType(bond, Molecule.cBondTypeSingle);
  		else if (order == 2)
  			super.setBondType(bond, Molecule.cBondTypeDouble);
  		else if (order == 3)
  			super.setBondType(bond, Molecule.cBondTypeTriple);
  		else
  			System.out.println("ERROR: Unusual bond order:"+order);
  	}
  
  	public final void setAtomDescription(int atm, String s) {
  		infos[atm][INFO_DESCRIPTION] = s;
  	}
  
  	public final String getAtomDescription(int atm) {
  		return (String) infos[atm][INFO_DESCRIPTION];
  	}
  
  	public final void setPPP(int atm, int[] a) {
  		infos[atm][INFO_PPP] = a;
  	}
  
  	public final int[] getPPP(int atm) {
  		return (int[]) infos[atm][INFO_PPP];
  	}
  	public final void setAtomSequence(int atm, int a) {
  		infos[atm][INFO_ATOMSEQUENCE] = a;
  	}
  	
  	public void setResSequence(int atm, int a) {
  		infos[atm][INFO_RESSEQUENCE] = a;
  	}
  
  	public final int getResSequence(int atm) {
  		return infos[atm][INFO_RESSEQUENCE]==null?-1 : (Integer) infos[atm][INFO_RESSEQUENCE];
  	}
  	
  	public final int getAtomSequence(int atm) {
  		return infos[atm][INFO_ATOMSEQUENCE]==null?-1 : (Integer) infos[atm][INFO_ATOMSEQUENCE];
  	}
  
  	public final void setAtomChainId(int atm, String a) {
  		infos[atm][INFO_CHAINID] = a;
  	}
  
  	public final String getAtomChainId(int atm) {
  		return (String) infos[atm][INFO_CHAINID];
  	}
  
  	public final void setAtomName(int atm, String a) {
  		infos[atm][INFO_ATOMNAME] = a;
  	}
  	
  
  	public final String getAtomName(int atm) {
  		return (String) infos[atm][INFO_ATOMNAME];
  	}
  
  	public final void setAtomAmino(int atm, String a) {
  		infos[atm][INFO_AMINO] = a;
  	}
  
  	public final String getAtomAmino(int atm) {
  		return (String) infos[atm][INFO_AMINO];
  	}
  	
  	public boolean isCovalentLigand() {
  		return isCovalentLigand;
  	}
  
  	public void setCovalentLigand(boolean b) {
  		isCovalentLigand = b;
  	}
  
  	public final double getAtomBfactor(int atm) {
  		return (double) infos[atm][INFO_BFACTOR];
  	}
  	
  	public final void setAtomBfactor(int atm, double bfactor) {
  		infos[atm][INFO_BFACTOR] = bfactor;
  	}
  
  	public final int getBond(int a1, int a2) {
  		for(int connBond=0; connBond<getAllConnAtomsPlusMetalBonds(a1); connBond++) {
  			if(getConnAtom(a1, connBond)==a2) return getConnBond(a1, connBond);
  		}
  		return -1;
  
  	}
  
  
  	////////////////////////////// UTILITIES ////////////////////////////////////////
  
  
  	public final Coordinates[] getCoordinates() {
  
  		Coordinates [] coords = new Coordinates[getAtoms()];
  
  		for (int i = 0; i < getAtoms(); i++) {
  			coords[i]= getAtomCoordinates(i);
  		}
  
  		return coords;
  	}
  
  
  	public final void deleteAtoms(List<Integer> atomsToBeDeleted) {
  		Collections.sort(atomsToBeDeleted);
  		for (int i = atomsToBeDeleted.size()-1; i>=0; i--) {
  			deleteAtom(atomsToBeDeleted.get(i));
  		}
  	}
  
  	public String getName() {
  		String name = super.getName();
  		return name == null ? "" : name;
  	}
  
  	public String getShortName() {
  		String name = getName();
  		if(name.indexOf(' ')>0) name = name.substring(0, name.indexOf(' '));
  		if(name.length()>12) name = name.substring(0, 12);
  		return name;
  	}
  
  	public Map<String, Object> getAuxiliaryInfos() {
  		return auxiliaryInfos;
  	}
  	public Object getAuxiliaryInfo(String name) {
  		return auxiliaryInfos.get(name);
  	}
  	public void setAuxiliaryInfo(String name, Object value) {
  		if(value==null) {
  			System.err.println("Attempt to set "+name+" to null");
  			auxiliaryInfos.remove(name);
  		} else {
  			auxiliaryInfos.put(name, value);
  		}
  	}
  
  	@Override
  	public boolean equals(Object obj) {
  		return obj==this;
  	}
  
  	public final void setInteractionAtomType(int atm, int type) {
  		infos[atm][INFO_INTERACTION_ATOM_TYPE] = type;
  	}
  	
  	public final int getInteractionAtomType(int atm) {
  		return (int) infos[atm][INFO_INTERACTION_ATOM_TYPE];
  	}
  
  	@Override
  	public void setMaxAtoms(int v) {
  		super.setMaxAtoms(v);
  		int u = atomFlags.length;
  		atomFlags = Arrays.copyOf(atomFlags, v);
  		partialCharges = Arrays.copyOf(partialCharges, v);
  		infos = Arrays.copyOf(infos, v);
  		for (int i=u; i<v; i++)
  			infos[i] = new Object[MAX_INFOS];
  	}
  
  	@Override
  	public int copyAtom(Molecule destMol, int sourceAtom, int esrGroupOffsetAND, int esrGroupOffsetOR) {
  		int destAtom = super.copyAtom(destMol, sourceAtom, esrGroupOffsetAND, esrGroupOffsetOR);
  		if (destMol instanceof Molecule3D) {
  
  			//
  			// If copy atom is called via the copy constructor the following arrays are not initialized.
  			// They are filled later in the constructor.
  			//
  			if(((Molecule3D) destMol).atomFlags!=null) {
  				((Molecule3D) destMol).atomFlags[destAtom] = atomFlags[sourceAtom];
  			}
  
  			if(((Molecule3D) destMol).partialCharges!=null){
  				((Molecule3D) destMol).partialCharges[destAtom] = partialCharges[sourceAtom];
  			}
  
  			if(((Molecule3D) destMol).infos!=null) {
  				((Molecule3D) destMol).infos[destAtom] = new Object[MAX_INFOS];//;= infos[sourceAtom];// = new Object[MAX_INFOS];
  				for (int i = 0; i < infos[sourceAtom].length; i++) {
  					((Molecule3D) destMol).infos[destAtom][i] = clone(infos[sourceAtom][i]);
  				}
  			}
  		}
  		return destAtom;
  	}
  
  	private Object clone(Object o) {	// since Object.clone() has protected access
  		Object newObject = null;
  		if(o!=null) {
  		
  			//System.out.println(o.getClass());
  /*		if (o instanceof Cloneable) {	causes thousands of warning during obfuscation
  			try {
  				return o.getClass().getMethod("clone").invoke(o);
  			} catch (Exception e) {}
  		}*/
  
  			if (o instanceof String)
  				newObject = o;
  			else if(o instanceof Integer)
  				newObject = Integer.valueOf((Integer)o);
  			else if(o instanceof Double)
  				newObject = Double.valueOf((Double)o);
  			else {
  				System.out.println("ERROR: unexpected Object type. Add support for new type: "+o);
  			}
  		}
  		return newObject;
  	}
  
  	public void compact() {
  		setMaxAtoms(getAllAtoms());
  		setMaxBonds(getAllBonds());
  	}
  
  	@Override
  	public void swapAtoms(int atom1, int atom2) {
  		super.swapAtoms(atom1, atom2);
  		int tempi = atomFlags[atom1];
  		atomFlags[atom1] = atomFlags[atom2];
  		atomFlags[atom2] = tempi;
  		double tempd = partialCharges[atom1];
  		partialCharges[atom1] = partialCharges[atom2];
  		partialCharges[atom2] = tempd;
  		Object[] tempo = infos[atom1];
  		infos[atom1] = infos[atom2];
  		infos[atom2] = tempo;
  	}
  
  	/**
  	 * Add an atom with the given atomicNo
  	 */
  	public int addAtom(int atomicNo) {
  		if(mAllAtoms > mMaxAtoms){
  			setMaxAtoms(mMaxAtoms*2);
  		}
  
  		int atom = super.addAtom(atomicNo);
  
  		atomFlags[atom] = 0;
  		partialCharges[atom] = 0;
  		infos[atom] = new Object[MAX_INFOS];
  
  		/* TODO
  		mm2AtomTypes[atom] = -1;
  		mmffAtomTypes[atom] = -1;
  		classIds[atom] = -1;
  		*/
  
  		return atom;
  	}
  
  	/**
  	 * Add an atom by copying its properties from the given Molecule3D
  	 * This has to be overriden by subclasses
  	 * @param m
  	 * @param i
  	 * @return
  	 */
  	public int addAtom(Molecule3D m, int i) {
  		int a = addAtom(m.getAtomicNo(i));
  		atomFlags[a] = m.getAtomFlags(i);
  		partialCharges[a] = m.getPartialCharge(i);
  		infos[a] = m.infos[i].clone();
  		setAtomX(i, getAtomX(i));
  		setAtomY(i, getAtomY(i));
  		setAtomZ(i, getAtomZ(i));
  //		mm2AtomTypes[a] = m.getMM2AtomType(i);
  //		mmffAtomTypes[a] = m.getMMFFAtomType(i);
  //		classIds[a] = m.getAtomInteractionClass(i);
  //		nMovables = -1;
  		return a;
  	}
  	
  	/**
  	 * High level function for constructing a molecule.
  	 * After the deletion the original order of atom and bond indexes is retained.
  	 * @param atom
  	 */
  	@Override
  	public void deleteAtom(int atom) {
  		super.deleteAtom(atom);
  		compressMolTable();
  		mValidHelperArrays = cHelperNone;
  		}
  	
  	@Override 
  	
  	protected int[] compressMolTable() {
  		// neutralize charges, if after deletion of a bi-polar bond one atom remains
  		for (int bnd=0; bnd<mAllBonds; bnd++) {
  			if (mBondType[bnd] == cBondTypeDeleted) {
  				int atom1 = mBondAtom[0][bnd];
  				int atom2 = mBondAtom[1][bnd];
  				if (mAtomicNo[atom1] == -1
  				  ^ mAtomicNo[atom2] == -1) {
  					if (mAtomCharge[atom1] != 0
  					 && mAtomCharge[atom2] != 0) {
  						if (mAtomCharge[atom1] < 0
  						  ^ mAtomCharge[atom2] < 0) {
  							if (mAtomCharge[atom1] < 0) {
  								mAtomCharge[atom1]++;
  								mAtomCharge[atom2]--;
  								}
  							else {
  								mAtomCharge[atom1]--;
  								mAtomCharge[atom2]++;
  								}
  							}
  						}
  					}
  				}
  			}
  		
  		int newAtmNo[] = new int[mAllAtoms];
  		int atomDest = 0;
  		for (int atom=0; atom<mAllAtoms; atom++) {
  			if (mAtomicNo[atom] == -1) {
  				newAtmNo[atom] = -1;
  				continue;
  				}
  			if (atomDest < atom) {
  				mAtomicNo[atomDest] = mAtomicNo[atom];
  				mAtomCharge[atomDest] = mAtomCharge[atom];
  				mAtomMass[atomDest] = mAtomMass[atom];
  				mAtomFlags[atomDest] = mAtomFlags[atom];
  				mAtomQueryFeatures[atomDest] = mAtomQueryFeatures[atom];
  				mAtomMapNo[atomDest] = mAtomMapNo[atom];
  				mCoordinates[atomDest].set(mCoordinates[atom]);
  				atomFlags[atomDest] = atomFlags[atom];
  				if(infos[atomDest]==null) {
  					infos[atomDest] = new Object[MAX_INFOS];
  				}
  				for (int i = 0; i < infos[atom].length; i++) {
  					infos[atomDest][i] = clone(infos[atom][i]);
  				}
  				partialCharges[atomDest] = partialCharges[atom];
  				if (mAtomList != null)
  					mAtomList[atomDest] = mAtomList[atom];
  				if (mAtomCustomLabel != null)
  					mAtomCustomLabel[atomDest] = mAtomCustomLabel[atom];
  				}
  			newAtmNo[atom] = atomDest;
  			atomDest++;
  			}
  		mAllAtoms = atomDest;
  
  		int bondDest = 0;
  		for (int bnd=0; bnd<mAllBonds; bnd++) {
  			if (mBondType[bnd] == cBondTypeDeleted) continue;
  			mBondType[bondDest] = mBondType[bnd];
  			mBondFlags[bondDest] = mBondFlags[bnd];
  			mBondQueryFeatures[bondDest] = mBondQueryFeatures[bnd];
  			mBondAtom[0][bondDest] = newAtmNo[mBondAtom[0][bnd]];
  			mBondAtom[1][bondDest] = newAtmNo[mBondAtom[1][bnd]];
  			bondDest++;
  			}
  		mAllBonds = bondDest;
  
  		return newAtmNo;
  		}
  
  	///////////////////// UTILITY FUNCTIONS ////////////////////////////////////
  	/**
  	 * Reorganizes atom indexes, so that moveable atoms are first
  	 * @return the number of moveable atoms
  	 */
  	public boolean reorderAtoms() {
  		boolean changed = false;
  		int N = getAllAtoms();
  		int i = 0; 	 //index of the first moveable atom
  		int j = N-1; //index of the last non-moveable atom
  
  		if(N==0) {
  			nMovables = 0;
  			return false;
  		}
  
  		while(i<j) {
  			//Move i to the first non-moveable atom
  			while(i<j && !isAtomFlag(i, RIGID)) i++;
  
  			//Move j to the last moveable atom
  			while(i<j && isAtomFlag(j, RIGID)) j--;
  			if(isAtomFlag(i, RIGID) && !isAtomFlag(j, RIGID)) {
  				swapAtoms(i, j);
  				changed = true;
  			}
  		}
  		nMovables = isAtomFlag(i, RIGID)? i: i+1;
  
  		return changed;
  	}
  
  
  	public void setCoordinates(int atom, Coordinates c){
  
  		setAtomX(atom, c.x);
  		setAtomY(atom, c.y);
  		setAtomZ(atom, c.z);
  	}
  
  	/*
  	@Override
  	public void ensureHelperArrays(int level) {
  		boolean doRings = (level & Molecule.cHelperBitRings) != 0 && (mValidHelperArrays & Molecule.cHelperBitRings) == 0;
  		super.ensureHelperArrays(level);
  		if (doRings) {
  			RingCollection ringSet = getRingSet();
  			mAtomToRings = new ArrayList[getAtoms()];
  			for (int r=0; r<ringSet.getSize(); r++) {
  				int[] ringAtom = ringSet.getRingAtoms(r);
  				for (int atom:ringAtom) {
  					if (mAtomToRings[atom] == null)
  						mAtomToRings[atom] = new ArrayList();
  					mAtomToRings[atom].add(r);
  				}
  			}
  		}
  	}
  
  	public List<Integer>[] getAtomToRings() {
  		return mAtomToRings;
  	}
  	*/
  
  	/**
  	 * @return the number of movable atoms (after reorderatoms has been called)
  	 */
  	public int getNMovables() {
  		if(nMovables<0 || (getAllAtoms()>0 && !isAtomFlag(0, LIGAND))) reorderAtoms();
  		return nMovables;
  	}
  	public boolean isMoleculeInOrder() {
  		return reorderAtoms()==false;
  	}
  
  	public double getPartialCharge(int a) {
  		return partialCharges[a];
  	}
  	public void setPartialCharge(int a, double v) {
  		partialCharges[a] = v;
  	}
  
  	@Override
  	public int compareTo(Molecule3D o) {
  		return o==null? 1: getName().compareTo(o.getName());
  	}
  
  /*	@Override
  	public int hashCode() {
  		return name==null? 0 : name.hashCode();
  	}*/
  
  	/**
  	 * Returns the Interaction Atom Type
  	 * @param atm
  	 * @param id
  	 *
  	public final void setAtomInteractionClass(int atm, int id) {
  		classIds[atm] = id;
  	}*/
  
  	/**
  	 * Set the MMFF atom type
  	 * @param atm
  	 * @param atomType
  	 *
  	public final void setMMFFAtomType(int atm, int atomType) {
  		mmffAtomTypes[atm] = atomType;
  	}*/
  
  	/**
  	 * Returns the MMFF Atom Type
  	 * @param atm
  	 * @return
  	 *
  	public final int getMMFFAtomType(int atm) {
  		return mmffAtomTypes[atm];
  	}*/
  
  	/**
  	 * Returns the MM2 Atom Type
  	 * @param atm
  	 * @return
  	 *
  	public final int getMM2AtomType(int atm) {
  		return mm2AtomTypes[atm];
  	}*/
  
  	/**
  	 * Set the MM2 atom type
  	 * @param atm
  	 * @param atomType
  	 *
  	public final void setMM2AtomType(int atm, int atomType) {
  		mm2AtomTypes[atm] = atomType;
  	}*/
  
  
  /*	public final String getMM2AtomDescription(int atm) {
  		return (String) infos[atm][INFO_MM2ATOMDESCRIPTION];
  	}
  
  	public final int getAtomInteractionClass(int atm) {
  		return classIds[atm];
  	}
  
  
  	public void setMmffRingAtoms(Boolean[] ringAtoms) {
  		this.mmffRingAtoms = ringAtoms;
  	}
  */
  
  	/**
  	 * Determine if a ring is aromatic according to MMFF criteria. Only
  	 * designed to work with rings of size 5 and 6. Returns the cached value.
  	 *  @param r The ring index in the molecule.
  	 *  @return True if the ring is aromatic, false otherwise.
  	 *
  	public boolean ringIsMMFFAromatic(int r) {
  		return mmffRingAtoms[r] == Boolean.TRUE;
  	}*/
  
  	/**
  	 * Returns true if the given ring has had its MMFF aromaticity flag set.
  	 *  @param r The ring index in the molecule.
  	 *  @return True if the ring has had its flag set, false otherwise.
  	 *
  	public boolean isSetRingMMFFAromaticity(int r) {
  		return mmffRingAtoms[r] != null;
  	}*/
  
  }
  