class GasteigerMarsiliPartialCharges implements IChargeCalculator {

    public IAtomContainer assignGasteigerMarsiliSigmaPartialCharges(IAtomContainer ac, boolean setCharge)
            throws Exception {

        //		if (setCharge) {
        //			atomTypeCharges.setCharges(ac); // not necessary initial charge
        //		}
        /* add the initial charge to 0. According results of Gasteiger */
        for (int i = 0; i < ac.getAtomCount(); i++)
            ac.getAtom(i).setCharge(0.0);
        double[] gasteigerFactors = assignGasteigerSigmaMarsiliFactors(ac);//a,b,c,deoc,chi,q
        double alpha = 1.0;
        double q;
        double deoc;

        IAtom[] atoms = null;
        int atom1 = 0;
        int atom2 = 0;

        double[] q_old = new double[ac.getAtomCount()];
        for (int i = 0; i < q_old.length; i++)
            q_old[0] = 20.0;

        out: for (int i = 0; i < MX_ITERATIONS; i++) {
            alpha *= MX_DAMP;
            boolean isDifferent = false;
            for (int j = 0; j < ac.getAtomCount(); j++) {
                q = gasteigerFactors[STEP_SIZE * j + j + 5];
                double difference = Math.abs(q_old[j]) - Math.abs(q);
                if (Math.abs(difference) > 0.001) isDifferent = true;
                q_old[j] = q;

                gasteigerFactors[STEP_SIZE * j + j + 4] = gasteigerFactors[STEP_SIZE * j + j + 2] * q * q
                        + gasteigerFactors[STEP_SIZE * j + j + 1] * q + gasteigerFactors[STEP_SIZE * j + j];
                //				logger.debug("g4: "+gasteigerFactors[STEP_SIZE * j + j + 4]);
            }
            if (!isDifferent) /* automatically break the maximum iterations */
            break out;

            //            bonds = ac.getBonds();
            Iterator<IBond> bonds = ac.bonds().iterator();
            while (bonds.hasNext()) {
                IBond bond = (IBond) bonds.next();

                atom1 = ac.indexOf(bond.getBegin());
                atom2 = ac.indexOf(bond.getEnd());

                if (gasteigerFactors[STEP_SIZE * atom1 + atom1 + 4] >= gasteigerFactors[STEP_SIZE * atom2 + atom2 + 4]) {
                    if (ac.getAtom(atom2).getSymbol().equals("H")) {
                        deoc = DEOC_HYDROGEN;
                    } else {
                        deoc = gasteigerFactors[STEP_SIZE * atom2 + atom2 + 3];
                    }
                } else {
                    if (ac.getAtom(atom1).getSymbol().equals("H")) {
                        deoc = DEOC_HYDROGEN;
                    } else {
                        deoc = gasteigerFactors[STEP_SIZE * atom1 + atom1 + 3];
                    }
                }

                q = (gasteigerFactors[STEP_SIZE * atom1 + atom1 + 4] - gasteigerFactors[STEP_SIZE * atom2 + atom2 + 4])
                        / deoc;
                //				logger.debug("qq: "+q);
                gasteigerFactors[STEP_SIZE * atom1 + atom1 + 5] -= (q * alpha);
                gasteigerFactors[STEP_SIZE * atom2 + atom2 + 5] += (q * alpha);
            }
        }

        for (int i = 0; i < ac.getAtomCount(); i++) {
            ac.getAtom(i).setCharge(gasteigerFactors[STEP_SIZE * i + i + 5]);
        }
        return ac;
    }

    public  GasteigerMarsiliPartialCharges();

}