/* Copyright (C) 2002-2007  The Chemistry Development Kit (CDK) project
 *
 * Contact: cdk-devel@lists.sf.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.inchi;

import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.tools.ILoggingTool;
import org.openscience.cdk.tools.LoggingToolFactory;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Tool to help process INChI 1.12beta content.
 *
 * @cdk.module extra
 * @cdk.githash
 */
@Deprecated
public class INChIContentProcessorTool {

    private static ILoggingTool logger = LoggingToolFactory.createLoggingTool(INChIContentProcessorTool.class); ;

    public INChIContentProcessorTool() {}

    /**
     * Processes the content from the formula field of the INChI.
     * Typical values look like C6H6, from INChI=1.12Beta/C6H6/c1-2-4-6-5-3-1/h1-6H.
     */
    public IAtomContainer processFormula(IAtomContainer parsedContent, String atomsEncoding) {
        logger.debug("Parsing atom data: ", atomsEncoding);

        Pattern pattern = Pattern.compile("([A-Z][a-z]?)(\\d+)?(.*)");
        String remainder = atomsEncoding;
        while (remainder.length() > 0) {
            logger.debug("Remaining: ", remainder);
            Matcher matcher = pattern.matcher(remainder);
            if (matcher.matches()) {
                String symbol = matcher.group(1);
                logger.debug("Atom symbol: ", symbol);
                if (symbol.equals("H")) {
                    // don't add explicit hydrogens
                } else {
                    String occurenceStr = matcher.group(2);
                    int occurence = 1;
                    if (occurenceStr != null) {
                        occurence = Integer.parseInt(occurenceStr);
                    }
                    logger.debug("  occurence: ", occurence);
                    for (int i = 1; i <= occurence; i++) {
                        parsedContent.addAtom(parsedContent.getBuilder().newInstance(IAtom.class, symbol));
                    }
                }
                remainder = matcher.group(3);
                if (remainder == null) remainder = "";
                logger.debug("  Remaining: ", remainder);
            } else {
                logger.error("No match found!");
                remainder = "";
            }
            logger.debug("NO atoms: ", parsedContent.getAtomCount());
        }
        return parsedContent;
    }

    /**
     * Processes the content from the connections field of the INChI.
     * Typical values look like 1-2-4-6-5-3-1, from INChI=1.12Beta/C6H6/c1-2-4-6-5-3-1/h1-6H.
     *
     * @param bondsEncoding the content of the INChI connections field
     * @param container     the atomContainer parsed from the formula field
     * @param source        the atom to build the path upon. If -1, then start new path
     *
     * @see   #processFormula
     */
    public void processConnections(String bondsEncoding, IAtomContainer container, int source) {
        logger.debug("Parsing bond data: ", bondsEncoding);

        IBond bondToAdd = null;
        /* Fixme: treatment of branching is too limited! */
        String remainder = bondsEncoding;
        while (remainder.length() > 0) {
            logger.debug("Bond part: ", remainder);
            if (remainder.charAt(0) == '(') {
                String branch = chopBranch(remainder);
                processConnections(branch, container, source);
                if (branch.length() + 2 <= remainder.length()) {
                    remainder = remainder.substring(branch.length() + 2);
                } else {
                    remainder = "";
                }
            } else {
                Pattern pattern = Pattern.compile("^(\\d+)-?(.*)");
                Matcher matcher = pattern.matcher(remainder);
                if (matcher.matches()) {
                    String targetStr = matcher.group(1);
                    int target = Integer.parseInt(targetStr);
                    logger.debug("Source atom: ", source);
                    logger.debug("Target atom: ", targetStr);
                    IAtom targetAtom = container.getAtom(target - 1);
                    if (source != -1) {
                        IAtom sourceAtom = container.getAtom(source - 1);
                        bondToAdd = container.getBuilder().newInstance(IBond.class, sourceAtom, targetAtom,
                                IBond.Order.SINGLE);
                        container.addBond(bondToAdd);
                    }
                    remainder = matcher.group(2);
                    source = target;
                    logger.debug("  remainder: ", remainder);
                } else {
                    logger.error("Could not get next bond info part");
                    return;
                }
            }
        }
    }

    /**
     * Extracts the first full branch. It extracts everything between the first
     * '(' and the corresponding ')' char.
     */
    private String chopBranch(String remainder) {
        boolean doChop = false;
        int branchLevel = 0;
        StringBuffer choppedString = new StringBuffer();
        for (int i = 0; i < remainder.length(); i++) {
            char currentChar = remainder.charAt(i);
            if (currentChar == '(') {
                if (doChop) choppedString.append(currentChar);
                doChop = true;
                branchLevel++;
            } else if (currentChar == ')') {
                branchLevel--;
                if (branchLevel == 0) {
                    doChop = false;
                    break;
                }
                if (doChop) choppedString.append(currentChar);
            } else if (doChop) {
                choppedString.append(currentChar);
            }
        }
        return choppedString.toString();
    }

}
