1 /* 2 * Copyright (c) 2017 John Mayfield <jwmay@users.sf.net> 3 * 4 * Contact: cdk-devel@lists.sourceforge.net 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU Lesser General Public License as published by 8 * the Free Software Foundation; either version 2.1 of the License, or (at 9 * your option) any later version. All we ask is that proper credit is given 10 * for our work, which includes - but is not limited to - adding the above 11 * copyright notice to the beginning of your source code files, and to any 12 * copyright notice that you may distribute with programs based on this work. 13 * 14 * This program is distributed in the hope that it will be useful, but WITHOUT 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 17 * License for more details. 18 * 19 * You should have received a copy of the GNU Lesser General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 */ 23 24 package org.openscience.cdk.stereo; 25 26 import org.openscience.cdk.interfaces.IAtom; 27 import org.openscience.cdk.interfaces.IBond; 28 import org.openscience.cdk.interfaces.IChemObject; 29 import org.openscience.cdk.interfaces.IChemObjectBuilder; 30 import org.openscience.cdk.interfaces.IStereoElement; 31 32 import java.util.ArrayList; 33 import java.util.Collections; 34 import java.util.HashMap; 35 import java.util.List; 36 import java.util.Map; 37 38 abstract class AbstractStereo<F extends IChemObject, C extends IChemObject> 39 implements IStereoElement<F, C> { 40 41 private int value; 42 private F focus; 43 private List<C> carriers; 44 private IChemObjectBuilder builder; 45 numCarriers(int cfg)46 protected static int numCarriers(int cfg) { 47 return ((cfg >>> 12) & 0xf); 48 } 49 AbstractStereo(F focus, C[] carriers, int value)50 AbstractStereo(F focus, C[] carriers, int value) { 51 if (focus == null) 52 throw new NullPointerException("Focus of stereochemistry can not be null!"); 53 if (carriers == null) 54 throw new NullPointerException("Carriers of the configuration can not be null!"); 55 if (carriers.length != numCarriers(value)) 56 throw new IllegalArgumentException("Unexpected number of stereo carriers! expected " + ((value >>> 12) & 0xf) + " was " + carriers.length); 57 for (C carrier : carriers) { 58 if (carrier == null) 59 throw new NullPointerException("A carrier was undefined!"); 60 } 61 this.value = value; 62 this.focus = focus; 63 this.carriers = new ArrayList<>(); 64 Collections.addAll(this.carriers, carriers); 65 } 66 67 /** 68 * {@inheritDoc} 69 */ 70 @Override getFocus()71 public F getFocus() { 72 return focus; 73 } 74 75 /** 76 * {@inheritDoc} 77 */ 78 @Override getCarriers()79 public List<C> getCarriers() { 80 return carriers; 81 } 82 83 /** 84 * {@inheritDoc} 85 */ 86 @Override getConfigClass()87 public int getConfigClass() { 88 return value & CLS_MASK; 89 } 90 91 /** 92 * {@inheritDoc} 93 */ 94 @Override getConfigOrder()95 public int getConfigOrder() { 96 return value & CFG_MASK; 97 } 98 99 /** 100 * {@inheritDoc} 101 */ 102 @Override getConfig()103 public int getConfig() { 104 return value; 105 } 106 107 /** 108 * {@inheritDoc} 109 */ 110 @Override setConfigOrder(int cfg)111 public void setConfigOrder(int cfg) { 112 value = getConfigClass() | cfg; 113 } 114 115 /** 116 * {@inheritDoc} 117 */ 118 @Override contains(IAtom atom)119 public boolean contains(IAtom atom) { 120 if (focus.equals(atom) || (focus instanceof IBond && ((IBond) focus).contains(atom))) 121 return true; 122 for (C carrier : carriers) { 123 if (carrier.equals(atom) || 124 (carrier instanceof IBond && ((IBond) carrier).contains(atom))) 125 return true; 126 } 127 return false; 128 } 129 130 /** 131 * {@inheritDoc} 132 */ 133 @Override map(Map<IAtom, IAtom> atoms, Map<IBond, IBond> bonds)134 public IStereoElement<F,C> map(Map<IAtom, IAtom> atoms, 135 Map<IBond, IBond> bonds) { 136 if (atoms == null) 137 throw new IllegalArgumentException("Atom map should be non-null"); 138 if (bonds == null) 139 throw new IllegalArgumentException("Bond map should be non-null"); 140 Map<IChemObject,IChemObject> map = new HashMap<>(atoms.size() + bonds.size()); 141 map.putAll(atoms); 142 map.putAll(bonds); 143 return map(map); 144 } 145 146 @Override 147 @SuppressWarnings("unchecked") map(Map<IChemObject, IChemObject> chemobjs)148 public IStereoElement<F, C> map(Map<IChemObject, IChemObject> chemobjs) { 149 if (chemobjs == null) 150 throw new NullPointerException("chemobj map was not provided!"); 151 F newfocus = (F) chemobjs.get(focus); 152 if (newfocus == null) 153 newfocus = focus; 154 List<C> newcarriers = carriers; 155 for (int i = 0; i < newcarriers.size(); i++) { 156 C newcarrier = (C) chemobjs.get(newcarriers.get(i)); 157 if (newcarrier != null) { 158 // make a copy if this is the first change 159 if (newcarriers == carriers) 160 newcarriers = new ArrayList<>(carriers); 161 newcarriers.set(i, newcarrier); 162 } 163 } 164 // no change, return self 165 if (newfocus == focus && newcarriers == carriers) 166 return this; 167 return create(newfocus, newcarriers, value); 168 } 169 create(F focus, List<C> carriers, int cfg)170 protected abstract IStereoElement<F,C> create(F focus, List<C> carriers, int cfg); 171 172 /** 173 *{@inheritDoc} 174 */ 175 @Override getBuilder()176 public IChemObjectBuilder getBuilder() { 177 if (builder == null) 178 throw new UnsupportedOperationException("Non-domain object!"); 179 return this.builder; 180 } 181 setBuilder(IChemObjectBuilder builder)182 protected void setBuilder(IChemObjectBuilder builder) { 183 this.builder = builder; 184 } 185 186 // labels for describing permutation 187 protected static final int A = 0, B = 1, C = 2, D = 3, E = 4, F = 5; 188 189 // apply the inverse of a permutation invapply(T[] src, int[] perm)190 protected static <T> T[] invapply(T[] src, int[] perm) { 191 T[] res = src.clone(); 192 for (int i = 0; i < src.length; i++) 193 res[i] = src[perm[i]]; 194 return res; 195 } 196 } 197