/**
  * Procedure required by the CDOInterface. This function is only supposed to be called by the JCFL
  * library
  */
 public void endObject(String objectType) {
   logger.debug("END: " + objectType);
   if (objectType.equals("Molecule")) {
     eventReader.fireFrameRead();
     clearData();
   } else if (objectType.equals("Atom")) {
     currentMolecule.addAtom(currentAtom);
   } else if (objectType.equals("Bond")) {
     logger.debug("Bond(" + bond_id + "): " + bond_a1 + ", " + bond_a2 + ", " + bond_order);
     if (bond_a1 > currentMolecule.getAtomCount() || bond_a2 > currentMolecule.getAtomCount()) {
       logger.error(
           "Cannot add bond between at least one non-existant atom: "
               + bond_a1
               + " and "
               + bond_a2);
     } else {
       IAtom a1 = currentMolecule.getAtom(bond_a1);
       IAtom a2 = currentMolecule.getAtom(bond_a2);
       IBond b = builder.newBond(a1, a2, bond_order);
       if (bond_id != null) b.setID(bond_id);
       if (bond_stereo != -99) {
         b.setStereo(bond_stereo);
       }
       currentMolecule.addBond(b);
     }
   }
 }
 public Object clone() throws CloneNotSupportedException {
   Object clone = null;
   try {
     clone = super.clone();
   } catch (Exception exception) {
     logger.error("Could not clone DebugAtomContainer: " + exception.getMessage(), exception);
     logger.debug(exception);
   }
   return clone;
 }
  private IChemFile readChemFile() throws CDKException {
    IChemSequence seq = file.getBuilder().newChemSequence();
    IChemModel model = file.getBuilder().newChemModel();
    IMoleculeSet containerSet = file.getBuilder().newMoleculeSet();
    IMolecule container = file.getBuilder().newMolecule();

    int lineNumber = 0;

    try {
      String line = input.readLine();
      while (input.ready() && line != null) {
        logger.debug((lineNumber++) + ": ", line);
        String command = null;
        if (isCommand(line)) {
          command = getCommand(line);
          int lineCount = getContentLinesCount(line);
          if ("ATOMS".equals(command)) {
            processAtomsBlock(lineCount, container);
          } else if ("BONDS".equals(command)) {
            processBondsBlock(lineCount, container);
          } else if ("IDENT".equals(command)) {
            processIdentBlock(lineCount, container);
          } else if ("NAME".equals(command)) {
            processNameBlock(lineCount, container);
          } else {
            // skip lines
            logger.warn("Dropping block: ", command);
            for (int i = 0; i < lineCount; i++) input.readLine();
          }
        } else {
          logger.warn("Unexpected content at line: ", lineNumber);
        }
        line = input.readLine();
      }
      containerSet.addAtomContainer(container);
      model.setMoleculeSet(containerSet);
      seq.addChemModel(model);
      file.addChemSequence(seq);
    } catch (Exception exception) {
      String message = "Error while parsing CTX file: " + exception.getMessage();
      logger.error(message);
      logger.debug(exception);
      throw new CDKException(message, exception);
    }
    return file;
  }
  /**
   * Choose any possible quadruple of the set of atoms in ac and establish all of the possible
   * bonding schemes according to Faulon's equations.
   */
  public static List sample(IMolecule ac) {
    logger.debug("RandomGenerator->mutate() Start");
    List structures = new ArrayList();

    int nrOfAtoms = ac.getAtomCount();
    double a11 = 0, a12 = 0, a22 = 0, a21 = 0;
    double b11 = 0, lowerborder = 0, upperborder = 0;
    double b12 = 0;
    double b21 = 0;
    double b22 = 0;
    double[] cmax = new double[4];
    double[] cmin = new double[4];
    IAtomContainer newAc = null;

    IAtom ax1 = null, ax2 = null, ay1 = null, ay2 = null;
    IBond b1 = null, b2 = null, b3 = null, b4 = null;
    // int[] choices = new int[3];
    /* We need at least two non-zero bonds in order to be successful */
    int nonZeroBondsCounter = 0;
    for (int x1 = 0; x1 < nrOfAtoms; x1++) {
      for (int x2 = x1 + 1; x2 < nrOfAtoms; x2++) {
        for (int y1 = x2 + 1; y1 < nrOfAtoms; y1++) {
          for (int y2 = y1 + 1; y2 < nrOfAtoms; y2++) {
            nonZeroBondsCounter = 0;
            ax1 = ac.getAtom(x1);
            ay1 = ac.getAtom(y1);
            ax2 = ac.getAtom(x2);
            ay2 = ac.getAtom(y2);

            /* Get four bonds for these four atoms */

            b1 = ac.getBond(ax1, ay1);
            if (b1 != null) {
              a11 = BondManipulator.destroyBondOrder(b1.getOrder());
              nonZeroBondsCounter++;
            } else {
              a11 = 0;
            }

            b2 = ac.getBond(ax1, ay2);
            if (b2 != null) {
              a12 = BondManipulator.destroyBondOrder(b2.getOrder());
              nonZeroBondsCounter++;
            } else {
              a12 = 0;
            }

            b3 = ac.getBond(ax2, ay1);
            if (b3 != null) {
              a21 = BondManipulator.destroyBondOrder(b3.getOrder());
              nonZeroBondsCounter++;
            } else {
              a21 = 0;
            }

            b4 = ac.getBond(ax2, ay2);
            if (b4 != null) {
              a22 = BondManipulator.destroyBondOrder(b4.getOrder());
              nonZeroBondsCounter++;
            } else {
              a22 = 0;
            }
            if (nonZeroBondsCounter > 1) {
              /* Compute the range for b11 (see Faulons formulae for details) */

              cmax[0] = 0;
              cmax[1] = a11 - a22;
              cmax[2] = a11 + a12 - 3;
              cmax[3] = a11 + a21 - 3;
              cmin[0] = 3;
              cmin[1] = a11 + a12;
              cmin[2] = a11 + a21;
              cmin[3] = a11 - a22 + 3;
              lowerborder = MathTools.max(cmax);
              upperborder = MathTools.min(cmin);
              for (b11 = lowerborder; b11 <= upperborder; b11++) {
                if (b11 != a11) {

                  b12 = a11 + a12 - b11;
                  b21 = a11 + a21 - b11;
                  b22 = a22 - a11 + b11;
                  logger.debug("Trying atom combination : " + x1 + ":" + x2 + ":" + y1 + ":" + y2);
                  try {
                    newAc = (IAtomContainer) ac.clone();
                    change(newAc, x1, y1, x2, y2, b11, b12, b21, b22);
                    if (ConnectivityChecker.isConnected(newAc)) {
                      structures.add(newAc);
                    } else {
                      logger.debug("not connected");
                    }
                  } catch (CloneNotSupportedException e) {
                    logger.error("Cloning exception: " + e.getMessage());
                    logger.debug(e);
                  }
                }
              }
            }
          }
        }
      }
    }
    return structures;
  }
  /**
   * Procedure required by the CDOInterface. This function is only supposed to be called by the JCFL
   * library
   */
  public void setObjectProperty(String objectType, String propertyType, String propertyValue) {
    logger.debug("objectType: " + objectType);
    logger.debug("propType: " + propertyType);
    logger.debug("property: " + propertyValue);

    if (objectType == null) {
      logger.error("Cannot add property for null object");
      return;
    }
    if (propertyType == null) {
      logger.error("Cannot add property for null property type");
      return;
    }
    if (propertyValue == null) {
      logger.warn("Will not add null property");
      return;
    }

    if (objectType.equals("Molecule")) {
      if (propertyType.equals("id")) {
        currentMolecule.setID(propertyValue);
      } else if (propertyType.equals("inchi")) {
        currentMolecule.setProperty("iupac.nist.chemical.identifier", propertyValue);
      }
    } else if (objectType.equals("PseudoAtom")) {
      if (propertyType.equals("label")) {
        if (!(currentAtom instanceof IPseudoAtom)) {
          currentAtom = builder.newPseudoAtom(currentAtom);
        }
        ((IPseudoAtom) currentAtom).setLabel(propertyValue);
      }
    } else if (objectType.equals("Atom")) {
      if (propertyType.equals("type")) {
        if (propertyValue.equals("R") && !(currentAtom instanceof IPseudoAtom)) {
          currentAtom = builder.newPseudoAtom(currentAtom);
        }
        currentAtom.setSymbol(propertyValue);
      } else if (propertyType.equals("x2")) {
        Point2d coord = currentAtom.getPoint2d();
        if (coord == null) coord = new Point2d();
        coord.x = Double.parseDouble(propertyValue);
        currentAtom.setPoint2d(coord);
      } else if (propertyType.equals("y2")) {
        Point2d coord = currentAtom.getPoint2d();
        if (coord == null) coord = new Point2d();
        coord.y = Double.parseDouble(propertyValue);
        currentAtom.setPoint2d(coord);
      } else if (propertyType.equals("x3")) {
        Point3d coord = currentAtom.getPoint3d();
        if (coord == null) coord = new Point3d();
        coord.x = Double.parseDouble(propertyValue);
        currentAtom.setPoint3d(coord);
      } else if (propertyType.equals("y3")) {
        Point3d coord = currentAtom.getPoint3d();
        if (coord == null) coord = new Point3d();
        coord.y = Double.parseDouble(propertyValue);
        currentAtom.setPoint3d(coord);
      } else if (propertyType.equals("z3")) {
        Point3d coord = currentAtom.getPoint3d();
        if (coord == null) coord = new Point3d();
        coord.z = Double.parseDouble(propertyValue);
        currentAtom.setPoint3d(coord);
      } else if (propertyType.equals("xFract")) {
        Point3d coord = currentAtom.getFractionalPoint3d();
        if (coord == null) coord = new Point3d();
        coord.x = Double.parseDouble(propertyValue);
        currentAtom.setFractionalPoint3d(coord);
      } else if (propertyType.equals("yFract")) {
        Point3d coord = currentAtom.getFractionalPoint3d();
        if (coord == null) coord = new Point3d();
        coord.y = Double.parseDouble(propertyValue);
        currentAtom.setFractionalPoint3d(coord);
      } else if (propertyType.equals("zFract")) {
        Point3d coord = currentAtom.getFractionalPoint3d();
        if (coord == null) coord = new Point3d();
        coord.z = Double.parseDouble(propertyValue);
        currentAtom.setFractionalPoint3d(coord);
      } else if (propertyType.equals("formalCharge")) {
        currentAtom.setFormalCharge(Integer.parseInt(propertyValue));
      } else if (propertyType.equals("charge") || propertyType.equals("partialCharge")) {
        currentAtom.setCharge(Double.parseDouble(propertyValue));
      } else if (propertyType.equals("hydrogenCount")) {
        currentAtom.setHydrogenCount(Integer.parseInt(propertyValue));
      } else if (propertyType.equals("dictRef")) {
        currentAtom.setProperty("org.openscience.cdk.dict", propertyValue);
      } else if (propertyType.equals("atomicNumber")) {
        currentAtom.setAtomicNumber(Integer.parseInt(propertyValue));
      } else if (propertyType.equals("massNumber")) {
        currentAtom.setMassNumber((int) Double.parseDouble(propertyValue));
      } else if (propertyType.equals("id")) {
        logger.debug("id: ", propertyValue);
        currentAtom.setID(propertyValue);
        atomEnumeration.put(propertyValue, numberOfAtoms);
      }
    } else if (objectType.equals("Bond")) {
      if (propertyType.equals("atom1")) {
        bond_a1 = Integer.parseInt(propertyValue);
      } else if (propertyType.equals("atom2")) {
        bond_a2 = Integer.parseInt(propertyValue);
      } else if (propertyType.equals("id")) {
        logger.debug("id: " + propertyValue);
        bond_id = propertyValue;
      } else if (propertyType.equals("order")) {
        try {
          Double order = Double.parseDouble(propertyValue);
          if (order == 1.0) {
            bond_order = IBond.Order.SINGLE;
          } else if (order == 2.0) {
            bond_order = IBond.Order.DOUBLE;
          } else if (order == 3.0) {
            bond_order = IBond.Order.TRIPLE;
          } else if (order == 4.0) {
            bond_order = IBond.Order.QUADRUPLE;
          } else {
            bond_order = IBond.Order.SINGLE;
          }
        } catch (Exception e) {
          logger.error("Cannot convert to double: " + propertyValue);
          bond_order = IBond.Order.SINGLE;
        }
      } else if (propertyType.equals("stereo")) {
        if (propertyValue.equals("H")) {
          bond_stereo = CDKConstants.STEREO_BOND_DOWN;
        } else if (propertyValue.equals("W")) {
          bond_stereo = CDKConstants.STEREO_BOND_UP;
        }
      }
    }
    logger.debug("Object property set...");
  }