1 /*  Copyright (C) 1997-2007  Christoph Steinbeck
2  *
3  *  Contact: cdk-devel@lists.sourceforge.net
4  *
5  *  This program is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public License
7  *  as published by the Free Software Foundation; either version 2.1
8  *  of the License, or (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 package org.openscience.cdk.silent;
20 
21 import org.openscience.cdk.CDKConstants;
22 import org.openscience.cdk.exception.NoSuchAtomException;
23 import org.openscience.cdk.interfaces.IAtom;
24 import org.openscience.cdk.interfaces.IAtomContainer;
25 import org.openscience.cdk.interfaces.IBond;
26 import org.openscience.cdk.interfaces.IBond.Order;
27 import org.openscience.cdk.interfaces.IChemObject;
28 import org.openscience.cdk.interfaces.IChemObjectChangeEvent;
29 import org.openscience.cdk.interfaces.IChemObjectListener;
30 import org.openscience.cdk.interfaces.IElectronContainer;
31 import org.openscience.cdk.interfaces.ILonePair;
32 import org.openscience.cdk.interfaces.ISingleElectron;
33 import org.openscience.cdk.interfaces.IStereoElement;
34 import org.openscience.cdk.sgroup.Sgroup;
35 import org.openscience.cdk.tools.manipulator.SgroupManipulator;
36 
37 import java.io.Serializable;
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.Collection;
41 import java.util.Collections;
42 import java.util.HashMap;
43 import java.util.HashSet;
44 import java.util.Iterator;
45 import java.util.List;
46 import java.util.Map;
47 import java.util.NoSuchElementException;
48 import java.util.Set;
49 
50 /**
51  * Base class for all chemical objects that maintain a list of Atoms and
52  * ElectronContainers. <p>
53  * <p>
54  * Looping over all Bonds in the AtomContainer is typically done like: <pre>
55  * Iterator iter = atomContainer.bonds();
56  * while (iter.hasNext()) {
57  *   IBond aBond = (IBond) iter.next();
58  * }
59  * </pre>
60  *
61  * @author steinbeck
62  * @cdk.module silent
63  * @cdk.githash
64  * @cdk.created 2000-10-02
65  */
66 public class AtomContainer extends ChemObject implements IAtomContainer, IChemObjectListener, Serializable, Cloneable {
67 
68     private static final int DEFAULT_CAPACITY = 20;
69 
70     /**
71      * Determines if a de-serialized object is compatible with this class.
72      * <p>
73      * This value must only be changed if and only if the new version
74      * of this class is incompatible with the old version. See Sun docs
75      * for <a href=http://java.sun.com/products/jdk/1.1/docs/guide
76      * /serialization/spec/version.doc.html>details</a>.
77      */
78     private static final long serialVersionUID = 5678100348445919254L;
79 
80     /**
81      * Number of atoms contained by this object.
82      */
83     protected int atomCount;
84 
85     /**
86      * Number of bonds contained by this object.
87      */
88     protected int bondCount;
89 
90     /**
91      * Number of lone pairs contained by this object.
92      */
93     protected int lonePairCount;
94 
95     /**
96      * Number of single electrons contained by this object.
97      */
98     protected int singleElectronCount;
99 
100     /**
101      * Amount by which the bond and atom arrays grow when elements are added and
102      * the arrays are not large enough for that.
103      */
104     protected int growArraySize = 10;
105 
106     /**
107      * Internal array of atoms.
108      */
109     protected IAtom[] atoms;
110 
111     /**
112      * Internal array of bonds.
113      */
114     protected IBond[] bonds;
115 
116     /**
117      * Internal array of lone pairs.
118      */
119     protected ILonePair[] lonePairs;
120 
121     /**
122      * Internal array of single electrons.
123      */
124     protected ISingleElectron[] singleElectrons;
125 
126     /**
127      * Internal list of atom parities.
128      */
129     protected Set<IStereoElement> stereoElements;
130 
131     /**
132      * Constructs an empty AtomContainer.
133      */
AtomContainer()134     public AtomContainer() {
135         this(0, 0, 0, 0);
136     }
137 
138     /**
139      * Constructs an AtomContainer with a copy of the atoms and electronContainers
140      * of another AtomContainer (A shallow copy, i.e., with the same objects as in
141      * the original AtomContainer).
142      *
143      * @param container An AtomContainer to copy the atoms and electronContainers from
144      */
AtomContainer(IAtomContainer container)145     public AtomContainer(IAtomContainer container) {
146         this.atomCount = container.getAtomCount();
147         this.bondCount = container.getBondCount();
148         this.lonePairCount = container.getLonePairCount();
149         this.singleElectronCount = container.getSingleElectronCount();
150         this.atoms = new IAtom[this.atomCount];
151         this.bonds = new IBond[this.bondCount];
152         this.lonePairs = new ILonePair[this.lonePairCount];
153         this.singleElectrons = new ISingleElectron[this.singleElectronCount];
154 
155         stereoElements = new HashSet<IStereoElement>(atomCount / 2);
156 
157         for (IStereoElement element : container.stereoElements()) {
158             addStereoElement(element);
159         }
160 
161         for (int f = 0; f < container.getAtomCount(); f++) {
162             atoms[f] = container.getAtom(f);
163         }
164         for (int f = 0; f < this.bondCount; f++) {
165             bonds[f] = container.getBond(f);
166         }
167         for (int f = 0; f < this.lonePairCount; f++) {
168             lonePairs[f] = container.getLonePair(f);
169         }
170         for (int f = 0; f < this.singleElectronCount; f++) {
171             singleElectrons[f] = container.getSingleElectron(f);
172         }
173     }
174 
175     /**
176      * Constructs an empty AtomContainer that will contain a certain number of
177      * atoms and electronContainers. It will set the starting array lengths to the
178      * defined values, but will not create any Atom or ElectronContainer's.
179      *
180      * @param atomCount Number of atoms to be in this container
181      * @param bondCount Number of bonds to be in this container
182      * @param lpCount   Number of lone pairs to be in this container
183      * @param seCount   Number of single electrons to be in this container
184      */
AtomContainer(int atomCount, int bondCount, int lpCount, int seCount)185     public AtomContainer(int atomCount, int bondCount, int lpCount,
186                          int seCount) {
187         this.atomCount = 0;
188         this.bondCount = 0;
189         this.lonePairCount = 0;
190         this.singleElectronCount = 0;
191         atoms = new IAtom[atomCount];
192         bonds = new IBond[bondCount];
193         lonePairs = new ILonePair[lpCount];
194         singleElectrons = new ISingleElectron[seCount];
195         stereoElements = new HashSet<IStereoElement>(atomCount / 2);
196     }
197 
198     /**
199      * {@inheritDoc}
200      */
201     @Override
addStereoElement(IStereoElement element)202     public void addStereoElement(IStereoElement element) {
203         stereoElements.add(element);
204     }
205 
206     /**
207      * {@inheritDoc}
208      */
209     @Override
setStereoElements(List<IStereoElement> elements)210     public void setStereoElements(List<IStereoElement> elements) {
211         this.stereoElements = new HashSet<IStereoElement>();
212         this.stereoElements.addAll(elements);
213     }
214 
215     /**
216      * {@inheritDoc}
217      */
218     @Override
stereoElements()219     public Iterable<IStereoElement> stereoElements() {
220         return Collections.unmodifiableSet(stereoElements);
221     }
222 
223     /**
224      * {@inheritDoc}
225      */
226     @Override
setAtoms(IAtom[] newAtoms)227     public void setAtoms(IAtom[] newAtoms) {
228         ensureAtomCapacity(newAtoms.length);
229         System.arraycopy(newAtoms, 0, this.atoms, 0, newAtoms.length);
230         if (newAtoms.length < this.atoms.length)
231             Arrays.fill(atoms, newAtoms.length, this.atoms.length, null);
232         this.atomCount = newAtoms.length;
233     }
234 
235     /**
236      * {@inheritDoc}
237      */
238     @Override
setBonds(IBond[] newBonds)239     public void setBonds(IBond[] newBonds) {
240         ensureBondCapacity(newBonds.length);
241         System.arraycopy(newBonds, 0, this.bonds, 0, newBonds.length);
242         if (newBonds.length < this.bonds.length)
243             Arrays.fill(bonds, newBonds.length, this.bonds.length, null);
244         this.bondCount = newBonds.length;
245     }
246 
247     /**
248      * {@inheritDoc}
249      */
250     @Override
setAtom(int idx, IAtom atom)251     public void setAtom(int idx, IAtom atom) {
252         if (idx >= atomCount)
253             throw new IndexOutOfBoundsException("No atom at index: " + idx);
254         int aidx = indexOf(atom);
255         if (aidx >= 0)
256             throw new IllegalArgumentException("Atom already in container at index: " + idx);
257         final IAtom oldAtom = atoms[idx];
258         atoms[idx] = atom;
259 
260         // update electron containers
261         for (IBond bond : bonds()) {
262             for (int i = 0; i < bond.getAtomCount(); i++) {
263                 if (oldAtom.equals(bond.getAtom(i))) {
264                     bond.setAtom(atom, i);
265                 }
266             }
267         }
268         for (ISingleElectron ec : singleElectrons()) {
269             if (oldAtom.equals(ec.getAtom()))
270                 ec.setAtom(atom);
271         }
272         for (ILonePair lp : lonePairs()) {
273             if (oldAtom.equals(lp.getAtom()))
274                 lp.setAtom(atom);
275         }
276 
277         // update stereo
278         List<IStereoElement> oldStereo = null;
279         List<IStereoElement> newStereo = null;
280         for (IStereoElement se : stereoElements()) {
281             if (se.contains(oldAtom)) {
282                 if (oldStereo == null) {
283                     oldStereo = new ArrayList<>();
284                     newStereo = new ArrayList<>();
285                 }
286                 oldStereo.add(se);
287                 Map<IAtom, IAtom> amap = Collections.singletonMap(oldAtom, atom);
288                 Map<IBond, IBond> bmap = Collections.emptyMap();
289                 newStereo.add(se.map(amap, bmap));
290             }
291         }
292         if (oldStereo != null) {
293             stereoElements.removeAll(oldStereo);
294             stereoElements.addAll(newStereo);
295         }
296     }
297 
298     /**
299      * {@inheritDoc}
300      */
301     @Override
getAtom(int idx)302     public IAtom getAtom(int idx) {
303         if (idx < 0 || idx >= atomCount)
304             throw new IndexOutOfBoundsException("Atom index out of bounds: 0 <= " + idx + " < " + atomCount);
305         return atoms[idx];
306     }
307 
308     /**
309      * {@inheritDoc}
310      */
311     @Override
getBond(int idx)312     public IBond getBond(int idx) {
313         if (idx < 0 || idx >= bondCount)
314             throw new IndexOutOfBoundsException("Bond index out of bounds: 0 <= " + idx + " < " + bondCount);
315         return bonds[idx];
316     }
317 
318     /**
319      * {@inheritDoc}
320      */
321     @Override
getLonePair(int idx)322     public ILonePair getLonePair(int idx) {
323         if (idx < 0 || idx >= lonePairCount)
324             throw new IndexOutOfBoundsException("Lone Pair index out of bounds: 0 <= " + idx + " < " + lonePairCount);
325         return lonePairs[idx];
326     }
327 
328     /**
329      * {@inheritDoc}
330      */
331     @Override
getSingleElectron(int idx)332     public ISingleElectron getSingleElectron(int idx) {
333         if (idx < 0 || idx >= singleElectronCount)
334             throw new IndexOutOfBoundsException("Single Electrong index out of bounds: 0 <= " + idx + " < " + singleElectronCount);
335         return singleElectrons[idx];
336     }
337 
338     /**
339      * {@inheritDoc}
340      */
341     @Override
atoms()342     public Iterable<IAtom> atoms() {
343         return new Iterable<IAtom>() {
344 
345             @Override
346             public Iterator<IAtom> iterator() {
347                 return new AtomIterator();
348             }
349         };
350     }
351 
352     /**
353      * {@inheritDoc}
354      */
355     @Override
356     public Iterable<IBond> bonds() {
357         return new Iterable<IBond>() {
358 
359             @Override
360             public Iterator<IBond> iterator() {
361                 return new BondIterator();
362             }
363         };
364     }
365 
366     /**
367      * {@inheritDoc}
368      */
369     @Override
370     public Iterable<ILonePair> lonePairs() {
371         return new Iterable<ILonePair>() {
372 
373             @Override
374             public Iterator<ILonePair> iterator() {
375                 return new LonePairIterator();
376             }
377         };
378     }
379 
380     /**
381      * {@inheritDoc}
382      */
383     @Override
384     public Iterable<ISingleElectron> singleElectrons() {
385         return new Iterable<ISingleElectron>() {
386 
387             @Override
388             public Iterator<ISingleElectron> iterator() {
389                 return new SingleElectronIterator();
390             }
391         };
392     }
393 
394     /**
395      * {@inheritDoc}
396      */
397     @Override
398     public Iterable<IElectronContainer> electronContainers() {
399         return new Iterable<IElectronContainer>() {
400 
401             @Override
402             public Iterator<IElectronContainer> iterator() {
403                 return new ElectronContainerIterator();
404             }
405         };
406     }
407 
408     /**
409      * {@inheritDoc}
410      */
411     @Override
412     public IAtom getFirstAtom() {
413         return atoms[0];
414     }
415 
416     /**
417      * {@inheritDoc}
418      */
419     @Override
420     public IAtom getLastAtom() {
421         return getAtomCount() > 0 ? (IAtom) atoms[getAtomCount() - 1] : null;
422     }
423 
424     /**
425      * {@inheritDoc}
426      */
427     @Override
428     public int getAtomNumber(IAtom atom) {
429         return indexOf(atom);
430     }
431 
432     /**
433      * {@inheritDoc}
434      */
435     @Override
436     public int getBondNumber(IAtom atom1, IAtom atom2) {
437         return indexOf(getBond(atom1, atom2));
438     }
439 
440     /**
441      * {@inheritDoc}
442      */
443     @Override
444     public int getBondNumber(IBond bond) {
445         return indexOf(bond);
446     }
447 
448     /**
449      * {@inheritDoc}
450      */
451     @Override
452     public int getLonePairNumber(ILonePair lonePair) {
453         return indexOf(lonePair);
454     }
455 
456     /**
457      * {@inheritDoc}
458      */
459     @Override
460     public int getSingleElectronNumber(ISingleElectron singleElectron) {
461         return indexOf(singleElectron);
462     }
463 
464     /**
465      * {@inheritDoc}
466      */
467     @Override
468     public int indexOf(IAtom atom) {
469         for (int i = 0; i < atomCount; i++) {
470             if (atoms[i].equals(atom)) return i;
471         }
472         return -1;
473     }
474 
475     /**
476      * {@inheritDoc}
477      */
478     @Override
479     public int indexOf(IBond bond) {
480         for (int i = 0; i < bondCount; i++) {
481             if (bonds[i].equals(bond)) return i;
482         }
483         return -1;
484     }
485 
486     /**
487      * {@inheritDoc}
488      */
489     @Override
490     public int indexOf(ISingleElectron electron) {
491         for (int i = 0; i < singleElectronCount; i++) {
492             if (singleElectrons[i] == electron) return i;
493         }
494         return -1;
495     }
496 
497     /**
498      * {@inheritDoc}
499      */
500     @Override
501     public int indexOf(ILonePair pair) {
502         for (int i = 0; i < lonePairCount; i++) {
503             if (lonePairs[i] == pair) return i;
504         }
505         return -1;
506     }
507 
508     /**
509      * {@inheritDoc}
510      */
511     @Override
512     public IElectronContainer getElectronContainer(int number) {
513         if (number < this.bondCount) return bonds[number];
514         number -= this.bondCount;
515         if (number < this.lonePairCount) return lonePairs[number];
516         number -= this.lonePairCount;
517         if (number < this.singleElectronCount) return singleElectrons[number];
518         return null;
519     }
520 
521     /**
522      * {@inheritDoc}
523      */
524     @Override
525     public IBond getBond(IAtom atom1, IAtom atom2) {
526         for (int i = 0; i < getBondCount(); i++) {
527             if (bonds[i].contains(atom1) && bonds[i].getOther(atom1).equals(atom2)) {
528                 return bonds[i];
529             }
530         }
531         return null;
532     }
533 
534     /**
535      * {@inheritDoc}
536      */
537     @Override
538     public int getAtomCount() {
539         return this.atomCount;
540     }
541 
542     /**
543      * {@inheritDoc}
544      */
545     @Override
546     public int getBondCount() {
547         return this.bondCount;
548     }
549 
550     /**
551      * {@inheritDoc}
552      */
553     @Override
554     public int getLonePairCount() {
555         return this.lonePairCount;
556     }
557 
558     /**
559      * {@inheritDoc}
560      */
561     @Override
562     public int getSingleElectronCount() {
563         return this.singleElectronCount;
564     }
565 
566     /**
567      * {@inheritDoc}
568      */
569     @Override
570     public int getElectronContainerCount() {
571         return this.bondCount + this.lonePairCount + this.singleElectronCount;
572     }
573 
574     /**
575      * {@inheritDoc}
576      */
577     @Override
578     public List<IAtom> getConnectedAtomsList(IAtom atom) {
579         List<IAtom> atomsList = new ArrayList<>(4);
580         for (int i = 0; i < bondCount; i++) {
581             if (bonds[i].contains(atom))
582                 atomsList.add(bonds[i].getOther(atom));
583         }
584         if (atomsList.isEmpty() && !contains(atom))
585             throw new NoSuchAtomException("Atom does not belong to the container!");
586         return atomsList;
587     }
588 
589     /**
590      * {@inheritDoc}
591      */
592     @Override
593     public List<IBond> getConnectedBondsList(IAtom atom) {
594         List<IBond> bondsList = new ArrayList<>(4);
595         for (int i = 0; i < bondCount; i++) {
596             if (bonds[i].contains(atom))
597                 bondsList.add(bonds[i]);
598         }
599         if (bondsList.isEmpty() && !contains(atom))
600             throw new NoSuchAtomException("Atom does not belong to the container!");
601         return bondsList;
602     }
603 
604     /**
605      * {@inheritDoc}
606      */
607     @Override
608     public List<ILonePair> getConnectedLonePairsList(IAtom atom) {
609         List<ILonePair> lps = new ArrayList<>(2);
610         for (int i = 0; i < lonePairCount; i++) {
611             if (lonePairs[i].contains(atom))
612                 lps.add(lonePairs[i]);
613         }
614         if (lps.isEmpty() && !contains(atom))
615             throw new NoSuchAtomException("Atom does not belong to the container!");
616         return lps;
617     }
618 
619     /**
620      * {@inheritDoc}
621      */
622     @Override
623     public List<ISingleElectron> getConnectedSingleElectronsList(IAtom atom) {
624         List<ISingleElectron> ses = new ArrayList<>(2);
625         for (int i = 0; i < singleElectronCount; i++) {
626             if (singleElectrons[i].contains(atom))
627                 ses.add(singleElectrons[i]);
628         }
629         if (ses.isEmpty() && !contains(atom))
630             throw new NoSuchAtomException("Atom does not belong to the container!");
631         return ses;
632     }
633 
634     /**
635      * {@inheritDoc}
636      */
637     @Override
638     public List<IElectronContainer> getConnectedElectronContainersList(
639         IAtom atom) {
640         List<IElectronContainer> ecs = new ArrayList<>(4);
641         for (int i = 0; i < bondCount; i++) {
642             if (bonds[i].contains(atom)) ecs.add(bonds[i]);
643         }
644         for (int i = 0; i < lonePairCount; i++) {
645             if (lonePairs[i].contains(atom)) ecs.add(lonePairs[i]);
646         }
647         for (int i = 0; i < singleElectronCount; i++) {
648             if (singleElectrons[i].contains(atom)) ecs.add(singleElectrons[i]);
649         }
650         if (ecs.isEmpty() && !contains(atom))
651             throw new NoSuchElementException("Atom does not belong to the container!");
652         return ecs;
653     }
654 
655     /**
656      * {@inheritDoc}
657      */
658     @Override
659     public int getConnectedBondsCount(IAtom atom) {
660         int count = 0;
661         for (int i = 0; i < bondCount; i++) {
662             if (bonds[i].contains(atom)) ++count;
663         }
664         if (count == 0 && !contains(atom))
665             throw new NoSuchAtomException("Atom does not belong to the container!");
666         return count;
667     }
668 
669     /**
670      * {@inheritDoc}
671      */
672     @Override
673     public int getConnectedAtomsCount(IAtom atom) {
674         return getConnectedBondsCount(atom);
675     }
676 
677     /**
678      * {@inheritDoc}
679      */
680     @Override
681     public int getConnectedBondsCount(int idx) {
682         final IAtom atom  = getAtom(idx);
683         int         count = 0;
684         for (int i = 0; i < bondCount; i++) {
685             if (bonds[i].contains(atom)) ++count;
686         }
687         // no need to check the contains(atom) as getAtom does this already
688         return count;
689     }
690 
691     /**
692      * {@inheritDoc}
693      */
694     @Override
695     public int getConnectedLonePairsCount(IAtom atom) {
696         int count = 0;
697         for (int i = 0; i < lonePairCount; i++) {
698             if (lonePairs[i].contains(atom))
699                 ++count;
700         }
701         if (count == 0 && !contains(atom))
702             throw new NoSuchAtomException("Atom does not belong to the container!");
703         return count;
704     }
705 
706     /**
707      * {@inheritDoc}
708      */
709     @Override
710     public int getConnectedSingleElectronsCount(IAtom atom) {
711         int count = 0;
712         for (int i = 0; i < singleElectronCount; i++) {
713             if (singleElectrons[i].contains(atom)) ++count;
714         }
715         if (count == 0 && !contains(atom))
716             throw new NoSuchAtomException("Atom does not belong to the container!");
717         return count;
718     }
719 
720     /**
721      * {@inheritDoc}
722      */
723     @Override
724     public double getBondOrderSum(IAtom atom) {
725         double count = 0;
726         for (int i = 0; i < bondCount; i++) {
727             if (bonds[i].contains(atom)) {
728                 IBond.Order order = bonds[i].getOrder();
729                 if (order != null) {
730                     count += order.numeric();
731                 }
732             }
733         }
734         return count;
735     }
736 
737     /**
738      * {@inheritDoc}
739      */
740     @Override
741     public Order getMaximumBondOrder(IAtom atom) {
742         IBond.Order max = null;
743         for (IBond bond : bonds()) {
744             if (!bond.contains(atom))
745                 continue;
746             if (max == null || bond.getOrder().numeric() > max.numeric()) {
747                 max = bond.getOrder();
748             }
749         }
750         if (max == null) {
751             if (!contains(atom))
752                 throw new NoSuchAtomException("Atom does not belong to this container!");
753             if (atom.getImplicitHydrogenCount() != null &&
754                 atom.getImplicitHydrogenCount() > 0)
755                 max = Order.SINGLE;
756             else
757                 max = Order.UNSET;
758         }
759         return max;
760     }
761 
762     /**
763      * {@inheritDoc}
764      */
765     @Override
766     public Order getMinimumBondOrder(IAtom atom) {
767         IBond.Order min = null;
768         for (IBond bond : bonds()) {
769             if (!bond.contains(atom))
770                 continue;
771             if (min == null || bond.getOrder().numeric() < min.numeric()) {
772                 min = bond.getOrder();
773             }
774         }
775         if (min == null) {
776             if (!contains(atom))
777                 throw new NoSuchAtomException("Atom does not belong to this container!");
778             if (atom.getImplicitHydrogenCount() != null &&
779                 atom.getImplicitHydrogenCount() > 0)
780                 min = Order.SINGLE;
781             else
782                 min = Order.UNSET;
783         }
784         return min;
785     }
786 
787     /**
788      * {@inheritDoc}
789      */
790     @Override
791     public void add(IAtomContainer that) {
792 
793         atoms = Arrays.copyOf(atoms, atomCount + that.getAtomCount());
794         bonds = Arrays.copyOf(bonds, bondCount + that.getBondCount());
795 
796         for (IAtom atom : that.atoms())
797             atom.setFlag(CDKConstants.VISITED, false);
798         for (IBond bond : that.bonds())
799             bond.setFlag(CDKConstants.VISITED, false);
800         for (IAtom atom : this.atoms())
801             atom.setFlag(CDKConstants.VISITED, true);
802         for (IBond bond : this.bonds())
803             bond.setFlag(CDKConstants.VISITED, true);
804 
805         for (IAtom atom : that.atoms()) {
806             if (!atom.getFlag(CDKConstants.VISITED)) {
807                 atom.setFlag(CDKConstants.VISITED, true);
808                 atoms[atomCount++] = atom;
809             }
810         }
811         for (IBond bond : that.bonds()) {
812             if (!bond.getFlag(CDKConstants.VISITED)) {
813                 bond.setFlag(CDKConstants.VISITED, true);
814                 bonds[bondCount++] = bond;
815             }
816         }
817         for (ILonePair lp : that.lonePairs()) {
818             if (!contains(lp)) {
819                 addLonePair(lp);
820             }
821         }
822         for (ISingleElectron se : that.singleElectrons()) {
823             if (!contains(se)) {
824                 addSingleElectron(se);
825             }
826         }
827         for (IStereoElement se : that.stereoElements())
828             stereoElements.add(se);
829     }
830 
831     /**
832      * {@inheritDoc}
833      */
834     @Override
835     public void addAtom(IAtom atom) {
836         if (contains(atom)) {
837             return;
838         }
839         ensureAtomCapacity(atomCount + 1);
840         atoms[atomCount++] = atom;
841     }
842 
843     /**
844      * {@inheritDoc}
845      */
846     @Override
847     public void addBond(IBond bond) {
848         ensureBondCapacity(bondCount + 1);
849         bonds[bondCount++] = bond;
850     }
851 
852     /**
853      * {@inheritDoc}
854      */
855     @Override
856     public void addLonePair(ILonePair lonePair) {
857         ensureLonePairCapacity(lonePairCount + 1);
858         lonePairs[lonePairCount++] = lonePair;
859     }
860 
861     /**
862      * {@inheritDoc}
863      */
864     @Override
865     public void addSingleElectron(ISingleElectron singleElectron) {
866         ensureElectronCapacity(singleElectronCount + 1);
867         singleElectrons[singleElectronCount++] = singleElectron;
868     }
869 
870     /**
871      * {@inheritDoc}
872      */
873     @Override
874     public void addElectronContainer(IElectronContainer electronContainer) {
875         if (electronContainer instanceof IBond)
876             this.addBond((IBond) electronContainer);
877         if (electronContainer instanceof ILonePair)
878             this.addLonePair((ILonePair) electronContainer);
879         if (electronContainer instanceof ISingleElectron)
880             this.addSingleElectron((ISingleElectron) electronContainer);
881     }
882 
883     /**
884      * {@inheritDoc}
885      */
886     @Override
887     public void remove(IAtomContainer atomContainer) {
888         for (int f = 0; f < atomContainer.getAtomCount(); f++) {
889             removeAtomOnly(atomContainer.getAtom(f));
890         }
891         for (int f = 0; f < atomContainer.getBondCount(); f++) {
892             removeBond(atomContainer.getBond(f));
893         }
894         for (int f = 0; f < atomContainer.getLonePairCount(); f++) {
895             removeLonePair(atomContainer.getLonePair(f));
896         }
897         for (int f = 0; f < atomContainer.getSingleElectronCount(); f++) {
898             removeSingleElectron(atomContainer.getSingleElectron(f));
899         }
900     }
901 
902     /**
903      * {@inheritDoc}
904      */
905     @Override
906     public void removeAtomOnly(int position) {
907         for (int i = position; i < atomCount - 1; i++) {
908             atoms[i] = atoms[i + 1];
909         }
910         atoms[atomCount - 1] = null;
911         atomCount--;
912     }
913 
914     /**
915      * {@inheritDoc}
916      */
917     @Override
918     public void removeAtomOnly(IAtom atom) {
919         int position = getAtomNumber(atom);
920         if (position != -1) {
921             removeAtomOnly(position);
922         }
923     }
924 
925     /**
926      * {@inheritDoc}
927      */
928     @Override
929     public IBond removeBond(int position) {
930         IBond bond = bonds[position];
931         for (int i = position; i < bondCount - 1; i++) {
932             bonds[i] = bonds[i + 1];
933         }
934         bonds[bondCount - 1] = null;
935         bondCount--;
936         return bond;
937     }
938 
939     /**
940      * {@inheritDoc}
941      */
942     @Override
943     public IBond removeBond(IAtom atom1, IAtom atom2) {
944         int   pos  = indexOf(getBond(atom1, atom2));
945         IBond bond = null;
946         if (pos != -1) {
947             bond = bonds[pos];
948             removeBond(pos);
949         }
950         return bond;
951     }
952 
953     /**
954      * {@inheritDoc}
955      */
956     @Override
957     public void removeBond(IBond bond) {
958         int pos = getBondNumber(bond);
959         if (pos != -1) removeBond(pos);
960     }
961 
962     /**
963      * {@inheritDoc}
964      */
965     @Override
966     public ILonePair removeLonePair(int position) {
967         ILonePair lp = lonePairs[position];
968         for (int i = position; i < lonePairCount - 1; i++) {
969             lonePairs[i] = lonePairs[i + 1];
970         }
971         lonePairs[lonePairCount - 1] = null;
972         lonePairCount--;
973         return lp;
974     }
975 
976     /**
977      * {@inheritDoc}
978      */
979     @Override
980     public void removeLonePair(ILonePair lonePair) {
981         int pos = indexOf(lonePair);
982         if (pos != -1) removeLonePair(pos);
983     }
984 
985     /**
986      * {@inheritDoc}
987      */
988     @Override
989     public ISingleElectron removeSingleElectron(int position) {
990         ISingleElectron se = singleElectrons[position];
991         for (int i = position; i < singleElectronCount - 1; i++) {
992             singleElectrons[i] = singleElectrons[i + 1];
993         }
994         singleElectrons[singleElectronCount - 1] = null;
995         singleElectronCount--;
996         return se;
997     }
998 
999     /**
1000      * {@inheritDoc}
1001      */
1002     @Override
1003     public void removeSingleElectron(ISingleElectron singleElectron) {
1004         int pos = indexOf(singleElectron);
1005         if (pos != -1) removeSingleElectron(pos);
1006     }
1007 
1008     /**
1009      * {@inheritDoc}
1010      */
1011     @Override
1012     public IElectronContainer removeElectronContainer(int number) {
1013         if (number < this.bondCount) return removeBond(number);
1014         number -= this.bondCount;
1015         if (number < this.lonePairCount) return removeLonePair(number);
1016         number -= this.lonePairCount;
1017         if (number < this.singleElectronCount)
1018             return removeSingleElectron(number);
1019         return null;
1020     }
1021 
1022     /**
1023      * {@inheritDoc}
1024      */
1025     @Override
1026     public void removeElectronContainer(IElectronContainer electronContainer) {
1027         if (electronContainer instanceof IBond)
1028             removeBond((IBond) electronContainer);
1029         else if (electronContainer instanceof ILonePair)
1030             removeLonePair((ILonePair) electronContainer);
1031         else if (electronContainer instanceof ISingleElectron)
1032             removeSingleElectron((ISingleElectron) electronContainer);
1033     }
1034 
1035     /**
1036      * {@inheritDoc}
1037      */
1038     @Override
1039     @Deprecated
1040     public void removeAtomAndConnectedElectronContainers(IAtom atom) {
1041         removeAtom(atom);
1042     }
1043 
1044     /**
1045      * {@inheritDoc}
1046      */
1047     @Override
1048     public void removeAtom(IAtom atom) {
1049         int position = getAtomNumber(atom);
1050         if (position != -1) {
1051             for (int i = 0; i < bondCount; i++) {
1052                 if (bonds[i].contains(atom)) {
1053                     removeBond(i);
1054                     --i;
1055                 }
1056             }
1057             for (int i = 0; i < lonePairCount; i++) {
1058                 if (lonePairs[i].contains(atom)) {
1059                     removeLonePair(i);
1060                     --i;
1061                 }
1062             }
1063             for (int i = 0; i < singleElectronCount; i++) {
1064                 if (singleElectrons[i].contains(atom)) {
1065                     removeSingleElectron(i);
1066                     --i;
1067                 }
1068             }
1069             List<IStereoElement> atomElements = new ArrayList<IStereoElement>(3);
1070             for (IStereoElement element : stereoElements) {
1071                 if (element.contains(atom)) atomElements.add(element);
1072             }
1073             stereoElements.removeAll(atomElements);
1074             removeAtomOnly(position);
1075         }
1076     }
1077 
1078     /**
1079      * {@inheritDoc}
1080      */
1081     @Override
1082     public void removeAtom(int pos) {
1083         removeAtom(getAtom(pos));
1084     }
1085 
1086     /**
1087      * {@inheritDoc}
1088      */
1089     @Override
1090     public void removeAllElements() {
1091         removeAllElectronContainers();
1092         atoms = new IAtom[growArraySize];
1093         atomCount = 0;
1094         stereoElements.clear();
1095     }
1096 
1097     /**
1098      * {@inheritDoc}
1099      */
1100     @Override
1101     public void removeAllElectronContainers() {
1102         removeAllBonds();
1103         lonePairs = new ILonePair[growArraySize];
1104         singleElectrons = new ISingleElectron[growArraySize];
1105         lonePairCount = 0;
1106         singleElectronCount = 0;
1107     }
1108 
1109     /**
1110      * {@inheritDoc}
1111      */
1112     @Override
1113     public void removeAllBonds() {
1114         bonds = new IBond[growArraySize];
1115         bondCount = 0;
1116     }
1117 
1118     /**
1119      * {@inheritDoc}
1120      */
1121     @Override
1122     public void addBond(int atom1, int atom2, IBond.Order order,
1123                         IBond.Stereo stereo) {
1124         IBond bond = getBuilder().newInstance(IBond.class, getAtom(atom1), getAtom(atom2), order, stereo);
1125         addBond(bond);
1126     }
1127 
1128     /**
1129      * {@inheritDoc}
1130      */
1131     @Override
1132     public void addBond(int atom1, int atom2, IBond.Order order) {
1133         IBond bond = getBuilder().newInstance(IBond.class, getAtom(atom1), getAtom(atom2), order);
1134         addBond(bond);
1135     }
1136 
1137     /**
1138      * {@inheritDoc}
1139      */
1140     @Override
1141     public void addLonePair(int atomID) {
1142         ILonePair lonePair = getBuilder().newInstance(ILonePair.class, atoms[atomID]);
1143         addLonePair(lonePair);
1144     }
1145 
1146     /**
1147      * {@inheritDoc}
1148      */
1149     @Override
1150     public void addSingleElectron(int atomID) {
1151         ISingleElectron singleElectron = getBuilder().newInstance(ISingleElectron.class, atoms[atomID]);
1152         addSingleElectron(singleElectron);
1153     }
1154 
1155     /**
1156      * {@inheritDoc}
1157      */
1158     @Override
1159     public boolean contains(IAtom atom) {
1160         for (int i = 0; i < getAtomCount(); i++) {
1161             if (atoms[i].equals(atom)) return true;
1162         }
1163         return false;
1164     }
1165 
1166     /**
1167      * {@inheritDoc}
1168      */
1169     @Override
1170     public boolean contains(IBond bond) {
1171         for (int i = 0; i < getBondCount(); i++) {
1172             if (bonds[i].equals(bond)) return true;
1173         }
1174         return false;
1175     }
1176 
1177     /**
1178      * {@inheritDoc}
1179      */
1180     @Override
1181     public boolean contains(ILonePair lonePair) {
1182         for (int i = 0; i < getLonePairCount(); i++) {
1183             if (lonePair == lonePairs[i]) return true;
1184         }
1185         return false;
1186     }
1187 
1188     /**
1189      * {@inheritDoc}
1190      */
1191     @Override
1192     public boolean contains(ISingleElectron singleElectron) {
1193         for (int i = 0; i < getSingleElectronCount(); i++) {
1194             if (singleElectron == singleElectrons[i]) return true;
1195         }
1196         return false;
1197     }
1198 
1199     /**
1200      * {@inheritDoc}
1201      */
1202     @Override
1203     public boolean contains(IElectronContainer electronContainer) {
1204         if (electronContainer instanceof IBond)
1205             return contains((IBond) electronContainer);
1206         if (electronContainer instanceof ILonePair)
1207             return contains((ILonePair) electronContainer);
1208         if (electronContainer instanceof ISingleElectron)
1209             return contains((SingleElectron) electronContainer);
1210         return false;
1211     }
1212 
1213     /**
1214      * {@inheritDoc}
1215      */
1216     @Override
1217     public String toString() {
1218         StringBuffer stringContent = new StringBuffer(64);
1219         stringContent.append("AtomContainer(");
1220         stringContent.append(this.hashCode());
1221         if (getAtomCount() > 0) {
1222             stringContent.append(", #A:").append(getAtomCount());
1223             for (int i = 0; i < getAtomCount(); i++) {
1224                 stringContent.append(", ").append(getAtom(i).toString());
1225             }
1226         }
1227         if (getBondCount() > 0) {
1228             stringContent.append(", #B:").append(getBondCount());
1229             for (int i = 0; i < getBondCount(); i++) {
1230                 stringContent.append(", ").append(getBond(i).toString());
1231             }
1232         }
1233         if (getLonePairCount() > 0) {
1234             stringContent.append(", #LP:").append(getLonePairCount());
1235             for (int i = 0; i < getLonePairCount(); i++) {
1236                 stringContent.append(", ").append(getLonePair(i).toString());
1237             }
1238         }
1239         if (getSingleElectronCount() > 0) {
1240             stringContent.append(", #SE:").append(getSingleElectronCount());
1241             for (int i = 0; i < getSingleElectronCount(); i++) {
1242                 stringContent.append(", ").append(getSingleElectron(i).toString());
1243             }
1244         }
1245         if (stereoElements.size() > 0) {
1246             stringContent.append(", ST:[#").append(stereoElements.size());
1247             for (IStereoElement elements : stereoElements) {
1248                 stringContent.append(", ").append(elements.toString());
1249             }
1250             stringContent.append(']');
1251         }
1252         stringContent.append(')');
1253         return stringContent.toString();
1254     }
1255 
1256     /**
1257      * {@inheritDoc}
1258      */
1259     @Override
1260     public IAtomContainer clone() throws CloneNotSupportedException {
1261 
1262         // this is pretty wasteful as we need to delete most the data
1263         // we can't simply create an empty instance as the sub classes (e.g. AminoAcid)
1264         // would have a ClassCastException when they invoke clone
1265         IAtomContainer clone = (IAtomContainer) super.clone();
1266 
1267         // remove existing elements - we need to set the stereo elements list as list.clone() doesn't
1268         // work as expected and will also remove all elements from the original
1269         clone.setStereoElements(new ArrayList<IStereoElement>(stereoElements.size()));
1270         clone.removeAllElements();
1271 
1272         // create a mapping of the original atoms/bonds to the cloned atoms/bonds
1273         // we need this mapping to correctly clone bonds, single/paired electrons
1274         // and stereo elements
1275         // - the expected size stop the map be resized - method from Google Guava
1276         Map<IAtom, IAtom> atomMap = new HashMap<IAtom, IAtom>(atomCount >= 3 ? atomCount + atomCount / 3
1277                                                                              : atomCount + 1);
1278         Map<IBond, IBond> bondMap = new HashMap<IBond, IBond>(bondCount >= 3 ? bondCount + bondCount / 3
1279                                                                              : bondCount + 1);
1280 
1281         // clone atoms
1282         IAtom[] atoms = new IAtom[this.atomCount];
1283         for (int i = 0; i < atoms.length; i++) {
1284 
1285             atoms[i] = (IAtom) this.atoms[i].clone();
1286             atomMap.put(this.atoms[i], atoms[i]);
1287         }
1288         clone.setAtoms(atoms);
1289 
1290         // clone bonds using a the mappings from the original to the clone
1291         IBond[] bonds = new IBond[this.bondCount];
1292         for (int i = 0; i < bonds.length; i++) {
1293 
1294             IBond   original = this.bonds[i];
1295             IBond   bond     = (IBond) original.clone();
1296             int     n        = bond.getAtomCount();
1297             IAtom[] members  = new IAtom[n];
1298 
1299             for (int j = 0; j < n; j++) {
1300                 members[j] = atomMap.get(original.getAtom(j));
1301             }
1302 
1303             bond.setAtoms(members);
1304             bondMap.put(this.bonds[i], bond);
1305             bonds[i] = bond;
1306         }
1307         clone.setBonds(bonds);
1308 
1309         // clone lone pairs (we can't use an array to buffer as there is no setLonePairs())
1310         for (int i = 0; i < lonePairCount; i++) {
1311 
1312             ILonePair original = this.lonePairs[i];
1313             ILonePair pair     = (ILonePair) original.clone();
1314 
1315             if (pair.getAtom() != null)
1316                 pair.setAtom(atomMap.get(original.getAtom()));
1317 
1318             clone.addLonePair(pair);
1319         }
1320 
1321         // clone single electrons (we can't use an array to buffer as there is no setSingleElectrons())
1322         for (int i = 0; i < singleElectronCount; i++) {
1323 
1324             ISingleElectron original = this.singleElectrons[i];
1325             ISingleElectron electron = (ISingleElectron) original.clone();
1326 
1327             if (electron.getAtom() != null)
1328                 electron.setAtom(atomMap.get(original.getAtom()));
1329 
1330             clone.addSingleElectron(electron);
1331         }
1332 
1333         // map each stereo element to a new instance in the clone
1334         for (IStereoElement element : stereoElements) {
1335             clone.addStereoElement(element.map(atomMap, bondMap));
1336         }
1337 
1338         // update sgroups
1339         Collection<Sgroup> sgroups = getProperty(CDKConstants.CTAB_SGROUPS);
1340         if (sgroups != null) {
1341             Map<IChemObject,IChemObject> replace = new HashMap<>();
1342             replace.putAll(atomMap);
1343             replace.putAll(bondMap);
1344             clone.setProperty(CDKConstants.CTAB_SGROUPS,
1345                               SgroupManipulator.copy(sgroups, replace));
1346         }
1347 
1348 
1349         return clone;
1350     }
1351 
1352     /**
1353      * Generic grow function, expand an array by a varried amount to have
1354      * enough (required) space.
1355      *
1356      * @param array    the array to expand
1357      * @param required the minimum required space
1358      * @param <T>      array type
1359      * @return the expanded array
1360      */
1361     private static <T> T[] grow(T[] array, int required) {
1362         int oldCapacity = array.length;
1363         // x1.5: 20, 30, 45, 67, 100, 150, 225, 337, 505, etc
1364         int newCapacity = oldCapacity == 0 ? DEFAULT_CAPACITY
1365                                            : oldCapacity + (oldCapacity >> 1);
1366         if (newCapacity < required)
1367             newCapacity = required;
1368         return Arrays.copyOf(array, newCapacity);
1369     }
1370 
1371     /**
1372      * Ensure there is enough space to accommodate the specified number of
1373      * atoms.
1374      *
1375      * @param required total number of atoms (inc. already used)
1376      */
1377     private void ensureAtomCapacity(int required) {
1378         if (required > atoms.length)
1379             atoms = grow(atoms, required);
1380     }
1381 
1382     /**
1383      * Ensure there is enough space to accommodate the specified number of
1384      * bonds.
1385      *
1386      * @param required total number of bonds (inc. already used)
1387      */
1388     private void ensureBondCapacity(int required) {
1389         if (required > bonds.length)
1390             bonds = grow(bonds, required);
1391     }
1392 
1393     /**
1394      * Ensure there is enough space to accommodate the specified number of
1395      * electrons.
1396      *
1397      * @param required total number of electrons (inc. already used)
1398      */
1399     private void ensureElectronCapacity(int required) {
1400         if (required > singleElectrons.length)
1401             singleElectrons = grow(singleElectrons, required);
1402     }
1403 
1404     /**
1405      * Ensure there is enough space to accommodate the specified number of
1406      * lone pairs.
1407      *
1408      * @param required total number of lone pairs (inc. already used)
1409      */
1410     private void ensureLonePairCapacity(int required) {
1411         if (required > lonePairs.length)
1412             lonePairs = grow(lonePairs, required);
1413     }
1414 
1415     /**
1416      * {@inheritDoc}
1417      */
1418     @Override
1419     public void stateChanged(IChemObjectChangeEvent event) {
1420         // ignored
1421     }
1422 
1423     /**
1424      * {@inheritDoc}
1425      */
1426     @Override
1427     public boolean isEmpty() {
1428         return atomCount == 0;
1429     }
1430 
1431     /**
1432      * {@inheritDoc}
1433      */
1434     @Override
1435     public String getTitle() {
1436         return getProperty(CDKConstants.TITLE);
1437     }
1438 
1439     /**
1440      * {@inheritDoc}
1441      */
1442     @Override
1443     public void setTitle(String title) {
1444         setProperty(CDKConstants.TITLE, title);
1445     }
1446 
1447     /**
1448      * The inner AtomIterator class.
1449      */
1450     private class AtomIterator implements Iterator<IAtom> {
1451 
1452         private int pointer = 0;
1453 
1454         @Override
1455         public boolean hasNext() {
1456             return pointer < atomCount;
1457         }
1458 
1459         @Override
1460         public IAtom next() {
1461             return atoms[pointer++];
1462         }
1463 
1464         @Override
1465         public void remove() {
1466             removeAtomOnly(--pointer);
1467         }
1468 
1469     }
1470 
1471     /**
1472      * The inner BondIterator class.
1473      */
1474     private class BondIterator implements Iterator<IBond> {
1475 
1476         private int pointer = 0;
1477 
1478         @Override
1479         public boolean hasNext() {
1480             return pointer < bondCount;
1481         }
1482 
1483         @Override
1484         public IBond next() {
1485             return bonds[pointer++];
1486         }
1487 
1488         @Override
1489         public void remove() {
1490             removeBond(--pointer);
1491         }
1492 
1493     }
1494 
1495     /**
1496      * The inner LonePairIterator class.
1497      */
1498     private class LonePairIterator implements Iterator<ILonePair> {
1499 
1500         private int pointer = 0;
1501 
1502         @Override
1503         public boolean hasNext() {
1504             return pointer < lonePairCount;
1505         }
1506 
1507         @Override
1508         public ILonePair next() {
1509             return lonePairs[pointer++];
1510         }
1511 
1512         @Override
1513         public void remove() {
1514             removeLonePair(--pointer);
1515         }
1516 
1517     }
1518 
1519     /**
1520      * The inner SingleElectronIterator class.
1521      */
1522     private class SingleElectronIterator implements Iterator<ISingleElectron> {
1523 
1524         private int pointer = 0;
1525 
1526         @Override
1527         public boolean hasNext() {
1528             return pointer < singleElectronCount;
1529         }
1530 
1531         @Override
1532         public ISingleElectron next() {
1533             return singleElectrons[pointer++];
1534         }
1535 
1536         @Override
1537         public void remove() {
1538             removeSingleElectron(--pointer);
1539         }
1540 
1541     }
1542 
1543     /**
1544      * The inner ElectronContainerIterator class.
1545      */
1546     private class ElectronContainerIterator implements Iterator<IElectronContainer> {
1547 
1548         private int pointer = 0;
1549 
1550         @Override
1551         public boolean hasNext() {
1552             return pointer < (bondCount + lonePairCount + singleElectronCount);
1553         }
1554 
1555         @Override
1556         public IElectronContainer next() {
1557             if (pointer < bondCount)
1558                 return bonds[pointer++];
1559             else if (pointer < bondCount + lonePairCount)
1560                 return lonePairs[(pointer++) - bondCount];
1561             else if (pointer < bondCount + lonePairCount + singleElectronCount)
1562                 return singleElectrons[(pointer++) - bondCount - lonePairCount];
1563             return null;
1564         }
1565 
1566         @Override
1567         public void remove() {
1568             if (pointer <= bondCount)
1569                 removeBond(--pointer);
1570             else if (pointer <= bondCount + lonePairCount)
1571                 removeLonePair((--pointer) - bondCount);
1572             else if (pointer <= bondCount + lonePairCount + singleElectronCount)
1573                 removeSingleElectron((--pointer) - bondCount - lonePairCount);
1574         }
1575 
1576     }
1577 
1578 }
1579