/**
   * Returns the theoretical m/z for this annotation.
   *
   * @return the theoretical m/z for this annotation.
   */
  public double calcTheoreticalMz() {

    double isotopeDelta;
    GlycanMassCalculator glycanMassCalculator =
        Lookup.getDefault().lookup(GlycanMassCalculator.class);

    if (isotopeComposition.isEmpty()) {
      isotopeDelta = 0;
    } else {
      isotopeDelta = MassCalculator.calcIsotopeDelta(isotopeComposition);
    }

    return glycanMassCalculator.calculateMz(
            fragment.calculateMolecularMass(), charge, fragment.getFragmentType())
        + (isotopeDelta + neutralLoss.getMolecularMass()) / charge;
  }
 @Override
 public int hashCode() {
   int result = isotopeComposition.hashCode();
   result = 31 * result + charge;
   result = 31 * result + fragment.hashCode();
   result = 31 * result + neutralLoss.hashCode();
   return result;
 }
  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof GlycanFragAnnotation)) return false;

    GlycanFragAnnotation that = (GlycanFragAnnotation) o;

    if (charge != that.charge) return false;
    if (!fragment.equals(that.fragment)) return false;
    if (!isotopeComposition.equals(that.isotopeComposition)) return false;
    return neutralLoss.equals(that.neutralLoss);
  }