/**
	 * Inserts a molecule into the current set, usually from Combobox or Insert
	 * field, with possible shifting of the existing set.
	 * 
	 * @param chemPaintPanel
	 * @param molecule
	 * @param generateCoordinates
	 * @param shiftPanel
	 * @throws CDKException
	 */
	public static void generateModel(
			final AbstractJChemPaintPanel chemPaintPanel,
			IAtomContainer molecule, final boolean generateCoordinates,
			final boolean shiftPasted) throws CDKException {
		if (molecule == null) {
			return;
		}

		final IChemModel chemModel = chemPaintPanel.getChemModel();
		IAtomContainerSet moleculeSet = chemModel.getMoleculeSet();
		if (moleculeSet == null) {
			moleculeSet = new AtomContainerSet();
		}

		// On copy & paste on top of an existing drawn structure, prevent the
		// pasted section to be drawn exactly on top or to far away from the
		// original by shifting it to a fixed position next to it.

		if (shiftPasted) {
			double maxXCurr = Double.NEGATIVE_INFINITY;
			double minXPaste = Double.POSITIVE_INFINITY;

			for (final IAtomContainer atc : moleculeSet.atomContainers()) {
				// Detect the right border of the current structure..
				for (final IAtom atom : atc.atoms()) {
					if (atom.getPoint2d().x > maxXCurr) {
						maxXCurr = atom.getPoint2d().x;
					}
				}
				// Detect the left border of the pasted structure..
				for (final IAtom atom : molecule.atoms()) {
					if (atom.getPoint2d().x < minXPaste) {
						minXPaste = atom.getPoint2d().x;
					}
				}
			}

			if (maxXCurr != Double.NEGATIVE_INFINITY
					&& minXPaste != Double.POSITIVE_INFINITY) {
				// Shift the pasted structure to be nicely next to the existing
				// one.
				final int MARGIN = 1;
				final double SHIFT = maxXCurr - minXPaste;
				for (final IAtom atom : molecule.atoms()) {
					atom.setPoint2d(new Point2d(atom.getPoint2d().x + MARGIN
							+ SHIFT, atom.getPoint2d().y));
				}
			}
		}

		if (generateCoordinates) {
			// now generate 2D coordinates
			final StructureDiagramGenerator sdg = new StructureDiagramGenerator();
			sdg.setTemplateHandler(new TemplateHandler(moleculeSet.getBuilder()));
			try {
				sdg.setMolecule(molecule);
				sdg.generateCoordinates(new Vector2d(0, 1));
				molecule = sdg.getMolecule();
			} catch (final Exception exc) {
				JOptionPane.showMessageDialog(chemPaintPanel,
						GT._("Structure could not be generated"));
				throw new CDKException("Cannot depict structure");
			}
		}

		if (moleculeSet.getAtomContainer(0).getAtomCount() == 0) {
			moleculeSet.getAtomContainer(0).add(molecule);
		} else {
			moleculeSet.addAtomContainer(molecule);
		}

		final IUndoRedoFactory undoRedoFactory = chemPaintPanel.get2DHub()
				.getUndoRedoFactory();
		final UndoRedoHandler undoRedoHandler = chemPaintPanel.get2DHub()
				.getUndoRedoHandler();

		if (undoRedoFactory != null) {
			final IUndoRedoable undoredo = undoRedoFactory
					.getAddAtomsAndBondsEdit(chemPaintPanel.get2DHub()
							.getIChemModel(), molecule, null, "Paste",
							chemPaintPanel.get2DHub());
			undoRedoHandler.postEdit(undoredo);
		}

		chemPaintPanel.getChemModel().setMoleculeSet(moleculeSet);
		chemPaintPanel.updateUndoRedoControls();
		chemPaintPanel.get2DHub().updateView();
	}
  /**
   * Initiates the process for the given mechanism. The atoms to apply are mapped between reactants
   * and products.
   *
   * @param atomContainerSet
   * @param atomList The list of atoms taking part in the mechanism. Only allowed two atoms. The
   *     first atom is the atom which contains the ISingleElectron and the second third is the atom
   *     which will be removed the first atom
   * @param bondList The list of bonds taking part in the mechanism. Only allowed one bond. It is
   *     the bond which is moved
   * @return The Reaction mechanism
   */
  @TestMethod(value = "testInitiate_IAtomContainerSet_ArrayList_ArrayList")
  public IReaction initiate(
      IAtomContainerSet atomContainerSet, ArrayList<IAtom> atomList, ArrayList<IBond> bondList)
      throws CDKException {
    CDKAtomTypeMatcher atMatcher = CDKAtomTypeMatcher.getInstance(atomContainerSet.getBuilder());
    if (atomContainerSet.getAtomContainerCount() != 1) {
      throw new CDKException("RadicalSiteIonizationMechanism only expects one IMolecule");
    }
    if (atomList.size() != 3) {
      throw new CDKException("RadicalSiteIonizationMechanism expects three atoms in the ArrayList");
    }
    if (bondList.size() != 2) {
      throw new CDKException(
          "RadicalSiteIonizationMechanism only expect one bond in the ArrayList");
    }
    IAtomContainer molecule = atomContainerSet.getAtomContainer(0);
    IAtomContainer reactantCloned;
    try {
      reactantCloned = (IAtomContainer) molecule.clone();
    } catch (CloneNotSupportedException e) {
      throw new CDKException("Could not clone IMolecule!", e);
    }
    IAtom atom1 = atomList.get(0); // Atom containing the ISingleElectron
    IAtom atom1C = reactantCloned.getAtom(molecule.getAtomNumber(atom1));
    IAtom atom2 = atomList.get(1); // Atom
    IAtom atom2C = reactantCloned.getAtom(molecule.getAtomNumber(atom2));
    IAtom atom3 = atomList.get(2); // Atom to be saved
    IAtom atom3C = reactantCloned.getAtom(molecule.getAtomNumber(atom3));
    IBond bond1 = bondList.get(0); // Bond to increase the order
    int posBond1 = molecule.getBondNumber(bond1);
    IBond bond2 = bondList.get(1); // Bond to remove
    int posBond2 = molecule.getBondNumber(bond2);

    BondManipulator.increaseBondOrder(reactantCloned.getBond(posBond1));
    reactantCloned.removeBond(reactantCloned.getBond(posBond2));

    List<ISingleElectron> selectron = reactantCloned.getConnectedSingleElectronsList(atom1C);
    reactantCloned.removeSingleElectron(selectron.get(selectron.size() - 1));
    atom1C.setHybridization(null);
    AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(reactantCloned);
    IAtomType type = atMatcher.findMatchingAtomType(reactantCloned, atom1C);
    if (type == null) return null;

    atom2C.setHybridization(null);
    AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(reactantCloned);
    type = atMatcher.findMatchingAtomType(reactantCloned, atom2C);
    if (type == null) return null;

    reactantCloned.addSingleElectron(new SingleElectron(atom3C));
    atom3C.setHybridization(null);
    AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(reactantCloned);
    type = atMatcher.findMatchingAtomType(reactantCloned, atom3C);
    if (type == null) return null;

    IReaction reaction = DefaultChemObjectBuilder.getInstance().newInstance(IReaction.class);
    reaction.addReactant(molecule);

    /* mapping */
    for (IAtom atom : molecule.atoms()) {
      IMapping mapping =
          DefaultChemObjectBuilder.getInstance()
              .newInstance(
                  IMapping.class, atom, reactantCloned.getAtom(molecule.getAtomNumber(atom)));
      reaction.addMapping(mapping);
    }

    IAtomContainerSet moleculeSetP = ConnectivityChecker.partitionIntoMolecules(reactantCloned);
    for (int z = 0; z < moleculeSetP.getAtomContainerCount(); z++)
      reaction.addProduct((IAtomContainer) moleculeSetP.getAtomContainer(z));

    return reaction;
  }