/* $RCSfile: $
* $Author$
* $Date$
* $Revision$
*
* Copyright (C) 2006-2007 Egon Willighagen <egonw@users.sf.net>
*
* 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 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.CTXFormat;
import org.openscience.cdk.io.formats.IResourceFormat;
import org.openscience.cdk.tools.ILoggingTool;
import org.openscience.cdk.tools.LoggingToolFactory;
import org.openscience.cdk.tools.manipulator.BondManipulator;
import org.openscience.cdk.tools.periodictable.PeriodicTable;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
/**
* Reader that extracts information from the IDENT, NAME, ATOMS and BONDS
* blocks in CTX files.
*
* @cdk.module io
* @cdk.githash
*/
@TestClass("org.openscience.cdk.io.CTXReaderTest")
public class CTXReader extends DefaultChemObjectReader {
private BufferedReader input;
private static ILoggingTool logger =
LoggingToolFactory.createLoggingTool(CTXReader.class);
private IChemFile file;
public CTXReader() {
file = null;
}
public CTXReader(Reader input) {
this();
if (input instanceof BufferedReader) {
this.input = (BufferedReader)input;
} else {
this.input = new BufferedReader(input);
}
}
public CTXReader(InputStream input) {
this(new InputStreamReader(input));
}
@TestMethod("testGetFormat")
public IResourceFormat getFormat() {
return CTXFormat.getInstance();
}
@TestMethod("testSetReader_Reader")
public void setReader(Reader reader) throws CDKException {
if (reader instanceof BufferedReader) {
this.input = (BufferedReader)reader;
} else {
this.input = new BufferedReader(reader);
}
}
@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 (int i=0; i<interfaces.length; i++) {
if (IChemFile.class.equals(interfaces[i])) return true;
}
Class superClass = classObject.getSuperclass();
if (superClass != null) return this.accepts(superClass);
return false;
}
public IChemObject read(IChemObject object) throws CDKException {
if (object instanceof IChemFile) {
file = (IChemFile)object;
return readChemFile();
} else {
throw new CDKException("Only supported is reading of ChemFile.");
}
}
private IChemFile readChemFile() throws CDKException {
IChemSequence seq = file.getBuilder().newChemSequence();
IChemModel model = file.getBuilder().newChemModel();
IMoleculeSet containerSet = file.getBuilder().newMoleculeSet();
IMolecule container = file.getBuilder().newMolecule();
int lineNumber = 0;
try {
String line = input.readLine();
while (input.ready() && line != null) {
logger.debug((lineNumber++) + ": ", line);
String command = null;
if (isCommand(line)) {
command = getCommand(line);
int lineCount = getContentLinesCount(line);
if ("ATOMS".equals(command)) {
processAtomsBlock(lineCount, container);
} else if ("BONDS".equals(command)) {
processBondsBlock(lineCount, container);
} else if ("IDENT".equals(command)) {
processIdentBlock(lineCount, container);
} else if ("NAME".equals(command)) {
processNameBlock(lineCount, container);
} else {
// skip lines
logger.warn("Dropping block: ", command);
for (int i=0; i<lineCount; i++) input.readLine();
}
} else {
logger.warn("Unexpected content at line: ", lineNumber);
}
line = input.readLine();
}
containerSet.addAtomContainer(container);
model.setMoleculeSet(containerSet);
seq.addChemModel(model);
file.addChemSequence(seq);
} catch (Exception exception) {
String message = "Error while parsing CTX file: " + exception.getMessage();
logger.error(message);
logger.debug(exception);
throw new CDKException(message, exception);
}
return file;
}
private void processIdentBlock(int lineCount, IAtomContainer container) throws IOException {
String identifier = "";
for (int i=0; i<lineCount; i++) {
identifier = identifier + input.readLine().trim();
}
container.setID(identifier);
}
private void processNameBlock(int lineCount, IAtomContainer container) throws IOException {
String name = "";
for (int i=0; i<lineCount; i++) {
name = name + input.readLine().trim();
}
container.setProperty(CDKConstants.TITLE, name);
}
private void processAtomsBlock(int lineCount, IAtomContainer container) throws IOException {
for (int i=0; i<lineCount; i++) {
String line = input.readLine();
int atomicNumber = Integer.parseInt(line.substring(7,10).trim());
IAtom atom = container.getBuilder().newAtom();
atom.setAtomicNumber(atomicNumber);
atom.setSymbol(PeriodicTable.getSymbol(atomicNumber));
container.addAtom(atom);
}
}
private void processBondsBlock(int lineCount, IAtomContainer container) throws IOException {
for (int i=0; i<lineCount; i++) {
String line = input.readLine();
int atom1 = Integer.parseInt(line.substring(10,13).trim())-1;
int atom2 = Integer.parseInt(line.substring(16,19).trim())-1;
if (container.getBond(container.getAtom(atom1), container.getAtom(atom2)) == null) {
IBond bond = container.getBuilder().newBond(
container.getAtom(atom1),
container.getAtom(atom2)
);
int order = Integer.parseInt(line.substring(23).trim());
bond.setOrder(BondManipulator.createBondOrder((double)order));
container.addBond(bond);
} // else: bond already present; CTX store the bonds twice
}
}
private int getContentLinesCount(String line) {
return Integer.parseInt(line.substring(18,21).trim());
}
private String getCommand(String line) {
return line.substring(2,10).trim();
}
private boolean isCommand(String line) {
return (line.length() > 1 && line.charAt(0) == ' ' && line.charAt(1) == '/');
}
@TestMethod("testClose")
public void close() throws IOException {
input.close();
}
}