/* $Revision$ $Author$ $Date$ * * Copyright (C) 2004-2007 Rajarshi Guha <rajarshi@presidency.com> * * Contact: cdk-devel@lists.sourceforge.net * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.openscience.cdk.io; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import javax.vecmath.Point3d; import org.openscience.cdk.CDKConstants; import org.openscience.cdk.annotations.TestClass; import org.openscience.cdk.annotations.TestMethod; import org.openscience.cdk.exception.CDKException; import org.openscience.cdk.interfaces.IAtom; import org.openscience.cdk.interfaces.IAtomContainer; import org.openscience.cdk.interfaces.IBond; import org.openscience.cdk.interfaces.IChemFile; import org.openscience.cdk.interfaces.IChemModel; import org.openscience.cdk.interfaces.IChemObject; import org.openscience.cdk.interfaces.IChemSequence; import org.openscience.cdk.interfaces.IMolecule; import org.openscience.cdk.interfaces.IMoleculeSet; import org.openscience.cdk.io.formats.HINFormat; import org.openscience.cdk.io.formats.IResourceFormat; /** * Reads an object from HIN formated input. * * @cdk.module io * @cdk.githash * * @author Rajarshi Guha <rajarshi@presidency.com> * @cdk.created 2004-01-27 * * @cdk.keyword file format, HIN */ @TestClass("org.openscience.cdk.io.HINReaderTest") public class HINReader extends DefaultChemObjectReader { private BufferedReader input; /** * Construct a new reader from a Reader type object * * @param input reader from which input is read */ public HINReader(Reader input) { this.input = new BufferedReader(input); } public HINReader(InputStream input) { this(new InputStreamReader(input)); } public HINReader() { this(new StringReader("")); } @TestMethod("testGetFormat") public IResourceFormat getFormat() { return HINFormat.getInstance(); } @TestMethod("testClose") public void close() throws IOException { input.close(); } @TestMethod("testSetReader_Reader") public void setReader(Reader input) throws CDKException { if (input instanceof BufferedReader) { this.input = (BufferedReader)input; } else { this.input = new BufferedReader(input); } } @TestMethod("testSetReader_InputStream") public void setReader(InputStream input) throws CDKException { setReader(new InputStreamReader(input)); } @TestMethod("testAccepts") public boolean accepts(Class classObject) { Class[] interfaces = classObject.getInterfaces(); for (Class anInterface : interfaces) { if (IChemFile.class.equals(anInterface)) return true; } Class superClass = classObject.getSuperclass(); if (superClass != null) return this.accepts(superClass); return false; } /** * Reads the content from a HIN input. It can only return a * IChemObject of type ChemFile * * @param object class must be of type ChemFile * * @see org.openscience.cdk.ChemFile */ public IChemObject read(IChemObject object) throws CDKException { if (object instanceof IChemFile) { return readChemFile((IChemFile)object); } else { throw new CDKException("Only supported is reading of ChemFile objects."); } } private String getMolName( String line) { if (line == null) return(""); StringTokenizer st = new StringTokenizer(line," "); int ntok = st.countTokens(); String[] toks = new String[ ntok ]; for (int j = 0; j < ntok; j++) { toks[j] = st.nextToken(); } if (toks.length == 3) return(toks[2]); else return(""); } /** * Private method that actually parses the input to read a ChemFile * object. In its current state it is able to read all the molecules * (if more than one is present) in the specified HIN file. These are * placed in a MoleculeSet object which in turn is placed in a ChemModel * which in turn is placed in a ChemSequence object and which is finally * placed in a ChemFile object and returned to the user. * * @return A ChemFile containing the data parsed from input. */ private IChemFile readChemFile(IChemFile file) { IChemSequence chemSequence = file.getBuilder().newChemSequence(); IChemModel chemModel = file.getBuilder().newChemModel(); IMoleculeSet setOfMolecules = file.getBuilder().newMoleculeSet(); String info; StringTokenizer tokenizer; try { String line; // read in header info while (true) { line = input.readLine(); if (line.indexOf("mol ") == 0) { info = getMolName(line); break; } } // start the actual molecule data - may be multiple molecule line = input.readLine(); while(true) { if (line == null) break; // end of file if (line.indexOf(';') == 0) continue; // comment line if (line.indexOf("mol ") == 0) { info = getMolName(line); line = input.readLine(); } IMolecule m = file.getBuilder().newMolecule(); m.setProperty(CDKConstants.TITLE ,info); // Each element of cons is an ArrayList of length 3 which stores // the start and end indices and bond order of each bond // found in the HIN file. Before adding bonds we need to reduce // the number of bonds so as not to count the same bond twice List<List<Object>> cons = new ArrayList<List<Object>>(); // read data for current molecule int atomSerial = 0; while (true) { if (line.indexOf("endmol ") >= 0) { break; } if (line.indexOf(';') == 0) continue; // comment line tokenizer = new StringTokenizer(line, " "); int ntoken = tokenizer.countTokens(); String[] toks = new String[ ntoken ]; for (int i = 0; i < ntoken; i++) toks[i] = tokenizer.nextToken(); String sym = toks[3]; double charge = Double.parseDouble(toks[6]); double x = Double.parseDouble(toks[7]); double y = Double.parseDouble(toks[8]); double z = Double.parseDouble(toks[9]); int nbond = Integer.parseInt(toks[10]); IAtom atom = file.getBuilder().newAtom(sym, new Point3d(x,y,z)); atom.setCharge(charge); IBond.Order bo = IBond.Order.SINGLE; for (int j = 11; j < (11+nbond*2); j += 2) { int s = Integer.parseInt(toks[j]) - 1; // since atoms start from 1 in the file char bt = toks[j+1].charAt(0); switch(bt) { case 's': bo = IBond.Order.SINGLE; break; case 'd': bo = IBond.Order.DOUBLE; break; case 't': bo = IBond.Order.TRIPLE; break; case 'a': bo = IBond.Order.QUADRUPLE; break; } List<Object> ar = new ArrayList<Object>(3); ar.add(atomSerial); ar.add(s); ar.add(bo); cons.add( ar ); } m.addAtom(atom); atomSerial++; line = input.readLine(); } // now just store all the bonds we have for (List<Object> ar : cons) { IAtom s = m.getAtom((Integer) ar.get(0)); IAtom e = m.getAtom((Integer) ar.get(1)); IBond.Order bo = (IBond.Order) ar.get(2); if (!isConnected(m, s, e)) m.addBond(file.getBuilder().newBond(s, e, bo)); } setOfMolecules.addMolecule(m); line = input.readLine(); // read in the 'mol N' } // got all the molecule in the HIN file (hopefully!) chemModel.setMoleculeSet(setOfMolecules); chemSequence.addChemModel(chemModel); file.addChemSequence(chemSequence); } catch (IOException e) { // FIXME: should make some noise now file = null; } return file; } private boolean isConnected(IAtomContainer atomContainer, IAtom atom1, IAtom atom2) { for (IBond bond : atomContainer.bonds()) { if (bond.contains(atom1) && bond.contains(atom2)) return true; } return false; } }