/**
   * Returns a boolean indicating whether the neutral loss should be accounted for.
   *
   * @param neutralLosses map of expected neutral losses
   * @param neutralLoss the neutral loss of interest
   * @param ion the fragment ion of interest
   * @return boolean indicating whether the neutral loss should be considered
   */
  public boolean isAccounted(NeutralLossesMap neutralLosses, NeutralLoss neutralLoss, Ion ion) {

    if (neutralLosses == null || neutralLosses.isEmpty()) {
      return false;
    }

    for (String neutralLossName : neutralLosses.getAccountedNeutralLosses()) {

      NeutralLoss neutralLossRef = NeutralLoss.getNeutralLoss(neutralLossName);

      if (neutralLoss.isSameAs(neutralLossRef)) {
        switch (ion.getType()) {
          case PEPTIDE_FRAGMENT_ION:
            PeptideFragmentIon peptideFragmentIon = ((PeptideFragmentIon) ion);
            switch (ion.getSubType()) {
              case PeptideFragmentIon.A_ION:
              case PeptideFragmentIon.B_ION:
              case PeptideFragmentIon.C_ION:
                return neutralLosses.getForwardStart(neutralLossName)
                    <= peptideFragmentIon.getNumber();
              case PeptideFragmentIon.X_ION:
              case PeptideFragmentIon.Y_ION:
              case PeptideFragmentIon.Z_ION:
                return neutralLosses.getRewindStart(neutralLossName)
                    <= peptideFragmentIon.getNumber();
              default:
                throw new UnsupportedOperationException(
                    "Fragment ion type "
                        + ion.getSubTypeAsString()
                        + " not implemented in the spectrum annotator.");
            }
          case TAG_FRAGMENT_ION:
            TagFragmentIon tagFragmentIon = ((TagFragmentIon) ion);
            switch (ion.getSubType()) {
              case TagFragmentIon.A_ION:
              case TagFragmentIon.B_ION:
              case TagFragmentIon.C_ION:
                return neutralLosses.getForwardStart(neutralLossName) <= tagFragmentIon.getNumber();
              case TagFragmentIon.X_ION:
              case TagFragmentIon.Y_ION:
              case TagFragmentIon.Z_ION:
                return neutralLosses.getRewindStart(neutralLossName) <= tagFragmentIon.getNumber();
              default:
                throw new UnsupportedOperationException(
                    "Fragment ion type "
                        + ion.getSubTypeAsString()
                        + " not implemented in the spectrum annotator.");
            }
          default:
            return true;
        }
      }
    }
    return false;
  }
 /**
  * Returns a boolean indicating whether the given charge can be found on the given fragment ion.
  *
  * @param theoreticIon the ion of interest
  * @param charge the candidate charge
  * @param precursorCharge the precursor charge
  * @return a boolean indicating whether the given charge can be found on the given fragment ion
  */
 public boolean chargeValidated(Ion theoreticIon, int charge, int precursorCharge) {
   if (charge == 1) {
     return true;
   }
   switch (theoreticIon.getType()) {
     case IMMONIUM_ION:
     case RELATED_ION: // note: it is possible to implement higher charges but then modify
                       // IonMatch.getPeakAnnotation(boolean html) as well to see the charge
                       // displayed on the spectrum
       return false;
     case REPORTER_ION: // note: it is possible to implement higher charges but then modify
                        // IonMatch.getPeakAnnotation(boolean html) as well to see the charge
                        // displayed on the spectrum
       return false;
     case PEPTIDE_FRAGMENT_ION:
       PeptideFragmentIon peptideFragmentIon = ((PeptideFragmentIon) theoreticIon);
       return charge <= peptideFragmentIon.getNumber() && charge < precursorCharge;
     case TAG_FRAGMENT_ION:
       TagFragmentIon tagFragmentIon = ((TagFragmentIon) theoreticIon);
       return charge <= tagFragmentIon.getNumber() && charge < precursorCharge;
     case PRECURSOR_ION:
       return charge >= precursorCharge;
     default:
       throw new UnsupportedOperationException(
           "Ion type "
               + theoreticIon.getTypeAsString()
               + " not implemented in the spectrum annotator.");
   }
 }