/*
 * 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.descriptor.qsarme;

import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IAtomType;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IChemObject;
import qsardes.descriptor.DescriptorExtendedTopochemIndex;

/**
 * Extended topochemical index descriptors (QSAR-ME Profiler 2025).
 * <BR><BR>
 * Calculates extended topochemical index descriptors.
 * <BR><BR>
 * Returns
 * <BR><BR>
 * ETA_Alpha - Sum of alpha values of molecule non-hydrogen vertices.
 * <BR>
 * ETA_AlphaP - Sum of alpha values of molecule non-hydrogen vertices
 * relative to molecular size.
 * <BR>
 * ETA_dAlpha_A - A measure of count of non-hydrogen heteroatoms.
 * <BR>
 * ETA_dAlpha_B - A measure of count of hydrogen bond acceptor atoms and/or
 * polar surface area.
 * <BR>
 * ETA_Epsilon_1, ETA_Epsilon_2, ETA_Epsilon_3, ETA_Epsilon_4, ETA_Epsilon_5 -
 * A measure of electronegative atom count.
 * <BR>
 * ETA_dEpsilon_A - A measure of contribution of unsaturation and
 * electronegative atom count.
 * <BR>
 * ETA_dEpsilon_B - A measure of contribution of unsaturation.
 * <BR>
 * ETA_dEpsilon_C - A measure of contribution of electronegativity.
 * <BR>
 * ETA_dEpsilon_D - A measure of contribution of hydrogen bond donor atoms.
 * <BR>
 * ETA_Psi_1 - A measure of hydrogen bonding propensity of the molecules and/or
 * polar surface area.
 * <BR>
 * ETA_dPsi_A, ETA_dPsi_B - A measure of hydrogen bonding propensity
 * of the molecules.
 * <BR>
 * ETA_Shape_P, ETA_Shape_Y, ETA_Shape_X - Shape index P/Y/X.
 * <BR>
 * ETA_Beta - A measure of electronic features of the molecule.
 * <BR>
 * ETA_BetaP - A measure of electronic features of the molecule relative to
 * molecular size.
 * <BR>
 * ETA_Beta_s - A measure of electronegative atom count of the molecule.
 * <BR>
 * ETA_BetaP_s - A measure of electronegative atom count of the molecule
 * relative to molecular size.
 * <BR>
 * ETA_Beta_ns - A measure of electron-richness of the molecule.
 * <BR>
 * ETA_BetaP_ns - A measure of electron-richness of the molecule relative to
 * molecular size.
 * <BR>
 * ETA_dBeta - A measure of relative unsaturation content.
 * <BR>
 * ETA_dBetaP - A measure of relative unsaturation content relative to
 * molecular size.
 * <BR>
 * ETA_Beta_ns_d - A measure of lone electrons entering into resonance.
 * <BR>
 * ETA_BetaP_ns_d - A measure of lone electrons entering into resonance
 * relative to molecular size.
 * <BR>
 * ETA_Eta - Composite index Eta.
 * <BR>
 * ETA_EtaP - Composite index Eta relative to molecular size.
 * <BR>
 * ETA_Eta_R - Composite index Eta for reference alkane.
 * <BR>
 * ETA_Eta_F - Functionality index EtaF.
 * <BR>
 * ETA_EtaP_F - Functionality index EtaF relative to molecular size.
 * <BR>
 * ETA_Eta_L - Local index Eta_local.
 * <BR>
 * ETA_EtaP_L - Local index Eta_local relative to molecular size.
 * <BR>
 * ETA_Eta_R_L - Local index Eta_local for reference alkane.
 * <BR>
 * ETA_Eta_F_L - Local functionality contribution EtaF_local.
 * <BR>
 * ETA_EtaP_F_L - Local functionality contribution EtaF_local relative
 * to molecular size.
 * <BR>
 * ETA_Eta_B - Branching index EtaB.
 * <BR>
 * ETA_EtaP_B - Branching index EtaB relative to molecular size.
 * <BR>
 * ETA_Eta_B_RC - Branching index EtaB with ring correction.
 * <BR>
 * ETA_EtaP_B_RC - Branching index EtaB, with ring correction,
 * relative to molecular size.
 *
 * @author Nicola Chirico
 */
public final class QsarMEExtendedTopochemIndex
        extends DescriptorExtendedTopochemIndex
{
    public QsarMEExtendedTopochemIndex()
    {
    }

    /*
       Standardize nitro groups to N(:O):O

       Adapted from PaDEL-Descriptor version 2.21
       Author: Chun Wei Yap
       Class: PaDELStandardize
       Method: StandardizeNitro
       Availability: http://yapcwsoft.com/dd/padeldescriptor
    */
    @Override
    protected void standardize_nitro_groups()
    {
        IAtomContainer iac = get_mol().get_atom_container();

        for (var atom : iac.atoms()) {
            if (atom.getAtomicNumber() == 7) {
                var neighbours = iac.getConnectedAtomsList(atom);

                if (neighbours.size() != 3) {
                    continue;
                }

                int oxygens_count = 0;

                boolean is_OH = true;

                for (var neigh_atom : neighbours) {
                    if (neigh_atom.getAtomicNumber() == 8) {
                        oxygens_count++;

                        var neigh_list = iac.getConnectedAtomsList(neigh_atom);

                        for (var neigh_atom_1 : neigh_list) {
                            if (neigh_atom_1 != atom) {
                                if (neigh_atom_1.getAtomicNumber() != 1) {
                                    is_OH = false;
                                    break;
                                }
                            }
                        }
                    }
                }

                if ((oxygens_count != 2) || (!is_OH)) {
                    continue;
                }

                atom.setFlag(IChemObject.AROMATIC, true);
                atom.setFormalCharge(0);
                atom.setHybridization(IAtomType.Hybridization.SP2);
                atom.setImplicitHydrogenCount(0);
                atom.setAtomTypeName("N.sp2");

                for (var neigh_atom : neighbours) {
                    if (neigh_atom.getAtomicNumber() == 8) {
                        neigh_atom.setFlag(IChemObject.AROMATIC, true);
                        neigh_atom.setFormalCharge(0);
                        neigh_atom.setHybridization(
                                IAtomType.Hybridization.SP2);
                        neigh_atom.setAtomTypeName("O.sp2");
                        neigh_atom.setImplicitHydrogenCount(0);

                        var neigh_list = iac.getConnectedAtomsList(neigh_atom);

                        for (var neigh_atom_1 : neigh_list) {
                            if (neigh_atom_1 != atom) {
                                iac.removeBond(neigh_atom, neigh_atom_1);
                                iac.removeAtom(neigh_atom_1);
                            }
                        }

                        var bond = iac.getBond(atom, neigh_atom);

                        bond.setOrder(IBond.Order.SINGLE);
                        bond.setFlag(IChemObject.AROMATIC, true);
                    } else if (neigh_atom.getFlag(IChemObject.AROMATIC)) {
                        iac.getBond(atom, neigh_atom).setFlag(
                                IChemObject.AROMATIC, true);
                    }
                }
            }
        }
    }

    protected double get_eta_eta_b(int atom_count, double eta_r)
    {
        /*
           PaDEL Descriptors tests for > 3 instead of >= 3
        */
        double eta_eta_b = atom_count > 3
                ? 1.414 + ((double)(atom_count - 3.0) * 0.5) - eta_r : 0.0;
        return eta_eta_b;
    }
}
