/*
 * Copyright (c) 2026 University of Insubria <https://www.uninsubria.it>
 *
 * 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. All we ask is that proper credit is given
 * for our work, which includes - but is not limited to - adding the above
 * copyright notice to the beginning of your source code files, and to any
 * copyright notice that you may distribute with programs based on this work.
 *
 * 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 program; if not, write to the Free Software Foundation, Inc.
 * <https://fsf.org/>
 */

package qsardes.molecule;

import org.openscience.cdk.exception.CDKException;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.openscience.cdk.DefaultChemObjectBuilder;
import org.openscience.cdk.atomtype.CDKAtomTypeMatcher;
import org.openscience.cdk.exception.InvalidSmilesException;
import org.openscience.cdk.smiles.SmilesParser;
import org.openscience.cdk.tools.manipulator.AtomContainerManipulator;
import org.openscience.cdk.tools.manipulator.AtomTypeManipulator;

/**
 * Builds a molecular representation.
 *
 * @author Nicola Chirico
 */
public abstract class AbstractMoleculeBuilder
{
    /**
     * Constructs a molecular representation.
     *
     * @param smiles Molecular SMILES.
     *
     * @throws org.openscience.cdk.exception.InvalidSmilesException
     * @throws java.lang.Exception
     */
    public AbstractMoleculeBuilder(String smiles) throws Exception
    {
        iac = parse_smiles(smiles);
    }

    /**
     * Gets the directed graph of the molecular representation.
     *
     * @return directed graph.
     */
    public DefaultDirectedGraph<Integer, CustomEdge> get_graph()
    {
        return graph;
    }

    public int get_atom_count()
    {
        return iac.getAtomCount();
    }

    public int get_bond_count()
    {
        return iac.getBondCount();
    }

    public int get_implicit_hydrogens_count()
    {
        return AtomContainerManipulator.getImplicitHydrogenCount(iac);
    }

    /**
     * Gets a clone of the generate molecular CDK atom container.
     *
     * @return CDK atom container.
     */
    IAtomContainer clone_atom_container() throws CloneNotSupportedException
    {
        return iac.clone();
    }

    protected IAtomContainer get_atom_container()
    {
        return iac;
    }

    protected IAtomContainer set_atom_container(IAtomContainer iac)
    {
        return this.iac = iac;
    }

    protected void configure_atoms() throws CDKException
    {
        CDKAtomTypeMatcher match
                = CDKAtomTypeMatcher.getInstance(iac.getBuilder());

        for (var atom : iac.atoms()) {
            AtomTypeManipulator.configure(atom,
                    match.findMatchingAtomType(iac, atom));
        }
    }

    protected void build_graph()
    {
        for (var bond : iac.bonds()) {
            for (int i = 0, n = bond.getAtomCount() - 1; i < n; i++) {
                var atom_1 = bond.getAtom(i);
                var atom_2 = bond.getAtom(i + 1);

                Integer v1 = iac.indexOf(atom_1);
                Integer v2 = iac.indexOf(atom_2);

                graph.addVertex(v1);
                graph.addVertex(v2);

                graph.addEdge(v1, v2, new CustomEdge());
                graph.addEdge(v2, v1, new CustomEdge());
            }
        }
    }

    private IAtomContainer parse_smiles(String smiles)
            throws InvalidSmilesException, CDKException
    {
        return new SmilesParser(DefaultChemObjectBuilder.getInstance())
                .parseSmiles(smiles);
    }

    private IAtomContainer iac;

    private final DefaultDirectedGraph<Integer, CustomEdge> graph
            = new DefaultDirectedGraph<>(CustomEdge.class);
}
