/* Copyright (C) 2006-2007  Miguel Rojas <miguel.rojas@uni-koeln.de>
 *                    2007  Egon Willighagen <egonw@users.sf.net>
 *
 * Contact: cdk-devel@lists.sourceforge.net
 *
 * This program 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 program 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 program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package org.openscience.cdk.tools;

import org.openscience.cdk.CDKConstants;
import org.openscience.cdk.config.AtomTypeFactory;
import org.openscience.cdk.exception.CDKException;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IAtomType;
import org.openscience.cdk.interfaces.ILonePair;
import org.openscience.cdk.interfaces.IChemObjectBuilder;

/**
 * Provides methods for checking whether an atoms lone pair electrons are saturated
 * with respect to a particular atom type.
 *
 * @author         Miguel Rojas
 * @cdk.githash
 * @cdk.created    2006-04-01
 *
 * @cdk.keyword    saturation
 * @cdk.keyword    atom, valency
 * @cdk.module     standard
 */
public class LonePairElectronChecker {

    private static ILoggingTool    logger = LoggingToolFactory.createLoggingTool(LonePairElectronChecker.class);
    private static AtomTypeFactory factory;

    private void createAtomTypeFactory(IChemObjectBuilder builder) {
        if (factory == null) {
            factory = AtomTypeFactory.getInstance("org/openscience/cdk/dict/data/cdk-atom-types.owl", builder);
        }
    }

    /**
     * Determines of all atoms on the AtomContainer have the
     * right number the lone pair electrons.
     */
    public boolean isSaturated(IAtomContainer container) throws CDKException {
        return allSaturated(container);
    }

    /**
     * Determines of all atoms on the AtomContainer have
     * the right number the lone pair electrons.
     */
    public boolean allSaturated(IAtomContainer ac) throws CDKException {
        logger.debug("Are all atoms saturated?");
        for (int f = 0; f < ac.getAtomCount(); f++) {
            if (!isSaturated(ac.getAtom(f), ac)) return false;
        }
        return true;
    }

    /**
     * Checks if an Atom is saturated their lone pair electrons
     * by comparing it with known AtomTypes.
     *
     * @return       True, if it's right saturated
     */
    public boolean isSaturated(IAtom atom, IAtomContainer ac) throws CDKException {
        createAtomTypeFactory(ac.getBuilder());
        IAtomType atomType = factory.getAtomType(atom.getAtomTypeName());
        int lpCount = (Integer) atomType.getProperty(CDKConstants.LONE_PAIR_COUNT);
        int foundLPCount = ac.getConnectedLonePairsCount(atom);
        return foundLPCount >= lpCount;
    }

    /**
     * Saturates a molecule by setting appropriate number lone pair electrons.
     */
    public void saturate(IAtomContainer atomContainer) throws CDKException {
        logger.info("Saturating atomContainer by adjusting lone pair electrons...");
        boolean allSaturated = allSaturated(atomContainer);
        if (!allSaturated) {
            for (int i = 0; i < atomContainer.getAtomCount(); i++) {
                saturate(atomContainer.getAtom(i), atomContainer);
            }
        }
    }

    /**
     * Saturates an IAtom by adding the appropriate number lone pairs.
     */
    public void saturate(IAtom atom, IAtomContainer ac) throws CDKException {
        logger.info("Saturating atom by adjusting lone pair electrons...");
        IAtomType atomType = factory.getAtomType(atom.getAtomTypeName());
        int lpCount = (Integer) atomType.getProperty(CDKConstants.LONE_PAIR_COUNT);
        int missingLPs = lpCount - ac.getConnectedLonePairsCount(atom);

        for (int j = 0; j < missingLPs; j++) {
            ILonePair lp = atom.getBuilder().newInstance(ILonePair.class, atom);
            ac.addLonePair(lp);
        }
    }

}
