/**
   * This method calculates the ionization potential of an atom.
   *
   * @param atom The IAtom to ionize.
   * @param container Parameter is the IAtomContainer.
   * @return The ionization potential. Not possible the ionization.
   */
  @Override
  public DescriptorValue calculate(IAtom atom, IAtomContainer container) {
    double value = 0;
    // FIXME: for now I'll cache a few modified atomic properties, and restore them at the end of
    // this method
    String originalAtomtypeName = atom.getAtomTypeName();
    Integer originalNeighborCount = atom.getFormalNeighbourCount();
    Integer originalValency = atom.getValency();
    IAtomType.Hybridization originalHybrid = atom.getHybridization();
    Double originalBondOrderSum = atom.getBondOrderSum();
    Order originalMaxBondOrder = atom.getMaxBondOrder();

    if (!isCachedAtomContainer(container)) {
      try {
        AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(container);

        LonePairElectronChecker lpcheck = new LonePairElectronChecker();
        lpcheck.saturate(container);
      } catch (CDKException e) {
        return new DescriptorValue(
            getSpecification(),
            getParameterNames(),
            getParameters(),
            new DoubleResult(Double.NaN),
            getDescriptorNames(),
            e);
      }
    }

    try {
      value = IonizationPotentialTool.predictIP(container, atom);
    } catch (CDKException e) {
      return new DescriptorValue(
          getSpecification(),
          getParameterNames(),
          getParameters(),
          new DoubleResult(Double.NaN),
          getDescriptorNames(),
          e);
    }
    // restore original props
    atom.setAtomTypeName(originalAtomtypeName);
    atom.setFormalNeighbourCount(originalNeighborCount);
    atom.setValency(originalValency);
    atom.setHybridization(originalHybrid);
    atom.setMaxBondOrder(originalMaxBondOrder);
    atom.setBondOrderSum(originalBondOrderSum);

    return new DescriptorValue(
        getSpecification(),
        getParameterNames(),
        getParameters(),
        new DoubleResult(value),
        getDescriptorNames());
  }
  /**
   * A unit test for JUnit with C=CCCl # C=CC[Cl+*]
   *
   * @cdk.inchi InChI=1/C3H7Cl/c1-2-3-4/h2-3H2,1H3
   */
  @Test
  public void testCompareIonized() throws Exception {

    IAtomContainer molA = builder.newInstance(IAtomContainer.class);
    molA.addAtom(builder.newInstance(IAtom.class, "C"));
    molA.addAtom(builder.newInstance(IAtom.class, "C"));
    molA.addBond(0, 1, IBond.Order.SINGLE);
    molA.addAtom(builder.newInstance(IAtom.class, "C"));
    molA.addBond(1, 2, IBond.Order.SINGLE);
    molA.addAtom(builder.newInstance(IAtom.class, "Cl"));
    molA.addBond(2, 3, IBond.Order.SINGLE);

    addExplicitHydrogens(molA);
    AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(molA);
    lpcheck.saturate(molA);

    double resultA =
        ((DoubleResult) descriptor.calculate(molA.getAtom(3), molA).getValue()).doubleValue();

    IAtomContainer molB = builder.newInstance(IAtomContainer.class);
    molB.addAtom(builder.newInstance(IAtom.class, "C"));
    molB.addAtom(builder.newInstance(IAtom.class, "C"));
    molB.addBond(0, 1, IBond.Order.SINGLE);
    molB.addAtom(builder.newInstance(IAtom.class, "C"));
    molB.addBond(1, 2, IBond.Order.SINGLE);
    molB.addAtom(builder.newInstance(IAtom.class, "Cl"));
    molB.getAtom(3).setFormalCharge(1);
    molB.addSingleElectron(3);
    molB.addLonePair(3);
    molB.addLonePair(3);
    molB.addBond(2, 3, IBond.Order.SINGLE);

    addExplicitHydrogens(molB);
    AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(molB);
    lpcheck.saturate(molB);

    Assert.assertEquals(1, molB.getAtom(3).getFormalCharge(), 0.00001);
    Assert.assertEquals(1, molB.getSingleElectronCount(), 0.00001);
    Assert.assertEquals(2, molB.getLonePairCount(), 0.00001);

    double resultB =
        ((DoubleResult) descriptor.calculate(molB.getAtom(3), molB).getValue()).doubleValue();

    Assert.assertNotSame(resultA, resultB);
  }
  /**
   * A unit test for JUnit
   *
   * @throws Exception
   */
  @Test
  public void testStabilizationComparative() throws Exception {

    IAtomContainer mol1 = builder.newInstance(IAtomContainer.class);
    mol1.addAtom(builder.newInstance(IAtom.class, "C"));
    mol1.addAtom(builder.newInstance(IAtom.class, "C"));
    mol1.getAtom(1).setFormalCharge(1);
    mol1.addBond(0, 1, Order.SINGLE);
    mol1.addAtom(builder.newInstance(IAtom.class, "C"));
    mol1.addBond(1, 2, Order.SINGLE);
    mol1.addAtom(builder.newInstance(IAtom.class, "O"));
    mol1.addBond(1, 3, Order.SINGLE);
    addExplicitHydrogens(mol1);
    lpcheck.saturate(mol1);

    DoubleResult result1 = ((DoubleResult) descriptor.calculate(mol1.getAtom(1), mol1).getValue());

    IAtomContainer mol2 = builder.newInstance(IAtomContainer.class);
    mol2.addAtom(builder.newInstance(IAtom.class, "C"));
    mol2.addAtom(builder.newInstance(IAtom.class, "C"));
    mol2.getAtom(1).setFormalCharge(1);
    mol2.addBond(0, 1, Order.SINGLE);
    mol2.addAtom(builder.newInstance(IAtom.class, "O"));
    mol2.addBond(1, 2, Order.SINGLE);
    addExplicitHydrogens(mol2);
    lpcheck.saturate(mol2);

    DoubleResult result2 = ((DoubleResult) descriptor.calculate(mol2.getAtom(1), mol2).getValue());

    IAtomContainer mol3 = builder.newInstance(IAtomContainer.class);
    mol3.addAtom(builder.newInstance(IAtom.class, "C"));
    mol3.addAtom(builder.newInstance(IAtom.class, "C"));
    mol3.getAtom(1).setFormalCharge(1);
    mol3.addBond(0, 1, Order.SINGLE);
    mol3.addAtom(builder.newInstance(IAtom.class, "C"));
    mol3.addBond(1, 2, Order.SINGLE);
    addExplicitHydrogens(mol3);
    lpcheck.saturate(mol3);

    DoubleResult result3 = ((DoubleResult) descriptor.calculate(mol3.getAtom(1), mol3).getValue());

    Assert.assertTrue(result3.doubleValue() < result2.doubleValue());
    Assert.assertTrue(result2.doubleValue() < result1.doubleValue());
  }
  /**
   * Get the Ethene structure.
   *
   * @return The IMolecule
   * @throws CDKException
   */
  private IMolecule getEthene() throws Exception {
    IMolecule molecule = builder.newMolecule();
    molecule.addAtom(builder.newAtom("C"));
    molecule.addAtom(builder.newAtom("C"));
    molecule.addBond(0, 1, IBond.Order.DOUBLE);
    molecule.addAtom(builder.newAtom("H"));
    molecule.addAtom(builder.newAtom("H"));
    molecule.addAtom(builder.newAtom("H"));
    molecule.addAtom(builder.newAtom("H"));
    molecule.addBond(0, 2, IBond.Order.SINGLE);
    molecule.addBond(0, 3, IBond.Order.SINGLE);
    molecule.addBond(1, 4, IBond.Order.SINGLE);
    molecule.addBond(1, 5, IBond.Order.SINGLE);
    AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(molecule);

    LonePairElectronChecker lpcheck = new LonePairElectronChecker();
    lpcheck.saturate(molecule);
    return molecule;
  }
  @Test
  public void testNotCharged() throws Exception {

    IAtomContainer mol = builder.newInstance(IAtomContainer.class);
    mol.addAtom(builder.newInstance(IAtom.class, "C"));
    mol.getAtom(0).setFormalCharge(-1);
    mol.addAtom(builder.newInstance(IAtom.class, "C"));
    mol.addBond(0, 1, Order.DOUBLE);
    mol.addAtom(builder.newInstance(IAtom.class, "F"));
    mol.addBond(1, 2, Order.SINGLE);

    addExplicitHydrogens(mol);
    lpcheck.saturate(mol);

    DoubleResult result = ((DoubleResult) descriptor.calculate(mol.getAtom(0), mol).getValue());

    Assert.assertEquals(0.0, result.doubleValue(), 0.00001);
  }