public void clearData(boolean clearDatabaseFolder) {
    projectDetails = null;
    spectrumAnnotator = new SpectrumAnnotator();
    try {
      spectrumFactory.closeFiles();
    } catch (Exception e) {
      e.printStackTrace();
    }
    try {
      sequenceFactory.closeFile();
    } catch (Exception e) {
      e.printStackTrace();
    }
    try {
      GOFactory.getInstance().closeFiles();
    } catch (Exception e) {
      e.printStackTrace();
    }

    try {
      spectrumFactory.clearFactory();
    } catch (Exception e) {
      e.printStackTrace();
    }

    try {
      sequenceFactory.clearFactory();
    } catch (Exception e) {
      e.printStackTrace();
    }

    try {
      GOFactory.getInstance().clearFactory();
    } catch (Exception e) {
      e.printStackTrace();
    }

    identifiedModifications = null;

    if (clearDatabaseFolder) {
      clearDatabaseFolder();
    }

    resetFeatureGenerator();

    // set up the tabs/panels

    currentPSFile = null;
  }
 /**
  * Returns the desired spectrum.
  *
  * @param spectrumKey the key of the spectrum
  * @return the desired spectrum
  */
 public MSnSpectrum getSpectrum(String spectrumKey) {
   String spectrumFile = Spectrum.getSpectrumFile(spectrumKey);
   String spectrumTitle = Spectrum.getSpectrumTitle(spectrumKey);
   try {
     return (MSnSpectrum) spectrumFactory.getSpectrum(spectrumFile, spectrumTitle);
   } catch (Exception e) {
     System.out.println(e.getMessage());
     return null;
   }
 }
/**
 * A Jump To panel for use in the menu bar in the main frame.
 *
 * @author Marc Vaudel
 * @author Harald Barsnes
 */
public class JumpToPanel extends javax.swing.JPanel {

  /** Enum of the types of data to jump to. */
  public enum JumpType {
    proteinAndPeptides,
    spectrum
  }
  /** The type of data to jump to in that panel. */
  private JumpType jumpType = JumpType.proteinAndPeptides;
  /** Instance of the main GUI class. */
  private PeptideShakerGUI peptideShakerGUI;
  /** Items matching the criterion for each type. */
  private HashMap<JumpType, ArrayList<String>> possibilities =
      new HashMap<JumpType, ArrayList<String>>();
  /** Currently selected item. */
  private HashMap<JumpType, Integer> currentSelection = new HashMap<JumpType, Integer>();
  /** The text to display by default. */
  private HashMap<JumpType, String> lastInput = new HashMap<JumpType, String>();
  /** The text to display by default. */
  private HashMap<JumpType, String> lastLabel = new HashMap<JumpType, String>();
  /** Instance of the sequence factory. */
  private SequenceFactory sequenceFactory = SequenceFactory.getInstance();
  /** The text to display by default. */
  private HashMap<JumpType, String> welcomeText;
  /** The spectrum factory. */
  private SpectrumFactory spectrumFactory = SpectrumFactory.getInstance();
  /** The spectrum file inspected when jumping to spectra. */
  private String spectrumfile;
  /** Counts the number of times the users has pressed a key on the keyboard in the search field. */
  private int keyPressedCounter = 0;
  /** The time to wait between keys typed before updating the search. */
  private int waitingTime = 1000;

  /** Type of item selected. */
  private enum Type {
    PROTEIN,
    PEPTIDE,
    SPECTRUM
  }
  /** Type of each possible item. */
  private HashMap<JumpType, ArrayList<Type>> types = new HashMap<JumpType, ArrayList<Type>>();

  /**
   * Creates a new JumpToPanel.
   *
   * @param peptideShakerGUI the parent
   */
  public JumpToPanel(PeptideShakerGUI peptideShakerGUI) {
    initComponents();

    this.peptideShakerGUI = peptideShakerGUI;

    welcomeText = new HashMap<JumpType, String>();
    welcomeText.put(JumpType.proteinAndPeptides, "(protein or peptide)");
    welcomeText.put(JumpType.spectrum, "(title, m/z or RT)");
    inputTxt.setText(welcomeText.get(jumpType));
    indexLabel.setText("");
    previousButton.setEnabled(false);
    nextButton.setEnabled(false);
  }

  /** Move the focus to the Jump To text field and select all the content. */
  public void selectTextField() {
    inputTxt.requestFocus();
    inputTxt.selectAll();
  }

  /**
   * Set the color for the hits.
   *
   * @param color the color
   */
  public void setColor(Color color) {
    indexLabel.setForeground(color);
  }

  /** Updates the item selection in the selected tab. */
  public void updateSelectionInTab() {

    indexLabel.setForeground(Color.BLACK);

    if (types.get(jumpType).get(currentSelection.get(jumpType)) == Type.PROTEIN) {
      peptideShakerGUI.setSelectedItems(
          possibilities.get(jumpType).get(currentSelection.get(jumpType)),
          PeptideShakerGUI.NO_SELECTION,
          PeptideShakerGUI.NO_SELECTION);
      peptideShakerGUI.updateSelectionInCurrentTab();
    } else if (types.get(jumpType).get(currentSelection.get(jumpType)) == Type.PEPTIDE) {
      peptideShakerGUI.setSelectedItems(
          PeptideShakerGUI.NO_SELECTION,
          possibilities.get(jumpType).get(currentSelection.get(jumpType)),
          PeptideShakerGUI.NO_SELECTION);
      if (peptideShakerGUI.getSelectedTab() == PeptideShakerGUI.MODIFICATIONS_TAB_INDEX
          && !peptideShakerGUI
              .getDisplayedPeptides()
              .contains(possibilities.get(jumpType).get(currentSelection.get(jumpType)))) {
        // warn the user that the current selection is not in the tab
        indexLabel.setForeground(Color.RED);
      } else {
        peptideShakerGUI.updateSelectionInCurrentTab();
      }
    } else {
      peptideShakerGUI.setSelectedItems(
          PeptideShakerGUI.NO_SELECTION,
          PeptideShakerGUI.NO_SELECTION,
          possibilities.get(jumpType).get(currentSelection.get(jumpType)));
      peptideShakerGUI.updateSelectionInCurrentTab();
    }
    String label =
        "("
            + (currentSelection.get(jumpType) + 1)
            + " of "
            + possibilities.get(jumpType).size()
            + ")";
    indexLabel.setText(label);
    lastLabel.put(jumpType, label);
  }

  /**
   * Returns a list of descriptions corresponding to every item matching the search.
   *
   * @return a list of descriptions
   * @throws SQLException thrown if an SQLException occurs
   * @throws ClassNotFoundException thrown if a ClassNotFoundException occurs
   * @throws IOException thrown if an IOException occurs
   * @throws InterruptedException thrown if an InterruptedException occurs
   */
  public ArrayList<String> getPossibilitiesDescriptions()
      throws SQLException, ClassNotFoundException, IOException, InterruptedException {

    Identification identification = peptideShakerGUI.getIdentification();

    // Some necessary pre-caching
    ArrayList<Type> typeList = types.get(jumpType);
    ArrayList<String> keys = possibilities.get(jumpType),
        proteinKeys = new ArrayList<String>(),
        peptideKeys = new ArrayList<String>();
    for (int i = 0; i < keys.size(); i++) {
      String key = keys.get(i);
      if (typeList.get(i) == Type.PROTEIN) {
        proteinKeys.add(key);
      } else if (typeList.get(i) == Type.PEPTIDE) {
        peptideKeys.add(key);
      }
    }
    if (!proteinKeys.isEmpty()) {
      identification.loadProteinMatches(proteinKeys, null, false);
    }
    if (!peptideKeys.isEmpty()) {
      identification.loadPeptideMatches(peptideKeys, null, false);
    }

    ArrayList<String> descriptions = new ArrayList<String>();
    for (int i = 0; i < keys.size(); i++) {
      String key = keys.get(i);
      Type type = typeList.get(i);
      String description = getItemDescription(key, type);
      descriptions.add(description);
    }
    return descriptions;
  }

  /**
   * Returns the description of an item.
   *
   * @param key the key of the item
   * @param itemType the type of the item
   * @return the description of an item
   * @throws SQLException thrown if an SQLException occurs
   * @throws ClassNotFoundException thrown if a ClassNotFoundException occurs
   * @throws IOException thrown if an IOException occurs
   * @throws InterruptedException thrown if an InterruptedException occurs
   */
  private String getItemDescription(String key, Type itemType)
      throws IllegalArgumentException, SQLException, IOException, ClassNotFoundException,
          InterruptedException {
    Identification identification = peptideShakerGUI.getIdentification();
    switch (itemType) {
      case PROTEIN:
        ProteinMatch proteinMatch = identification.getProteinMatch(key);
        String mainMatch = proteinMatch.getMainMatch();
        String description = sequenceFactory.getHeader(mainMatch).getSimpleProteinDescription();
        String result = mainMatch;
        for (String accession : ProteinMatch.getAccessions(key)) {
          if (!accession.equals(mainMatch)) {
            if (!result.equals(mainMatch)) {
              result += ", ";
            }
            result += accession;
          }
        }
        result += " - " + description;
        return result;
      case PEPTIDE:
        PeptideMatch peptideMatch = identification.getPeptideMatch(key);
        return peptideShakerGUI
            .getDisplayFeaturesGenerator()
            .getTaggedPeptideSequence(peptideMatch, true, true, true);
      case SPECTRUM:
        return Spectrum.getSpectrumTitle(key) + " (" + Spectrum.getSpectrumFile(key) + ")";
      default:
        return "Unknown";
    }
  }

  /**
   * Returns the index of the selected item.
   *
   * @return the index of the selected item
   */
  public int getIndexOfSelectedItem() {
    return currentSelection.get(jumpType);
  }

  /**
   * Sets the index of the selected item. Note: this does not update the selection in tab and the
   * GUI (see updateSelectionInTab()).
   *
   * @param itemIndex the item index
   */
  public void setSelectedItem(int itemIndex) {
    currentSelection.put(jumpType, itemIndex);
  }

  /**
   * This method is called from within the constructor to initialize the form. WARNING: Do NOT
   * modify this code. The content of this method is always regenerated by the Form Editor.
   */
  @SuppressWarnings("unchecked")
  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
  private void initComponents() {

    findJLabel = new javax.swing.JLabel();
    inputTxt = new javax.swing.JTextField();
    previousButton = new javax.swing.JButton();
    nextButton = new javax.swing.JButton();
    indexLabel = new javax.swing.JLabel();

    setOpaque(false);

    findJLabel.setText("Find");

    inputTxt.setForeground(new java.awt.Color(204, 204, 204));
    inputTxt.setHorizontalAlignment(javax.swing.JTextField.CENTER);
    inputTxt.setText("(peptide or protein)");
    inputTxt.setBorder(
        javax.swing.BorderFactory.createLineBorder(new java.awt.Color(204, 204, 204)));
    inputTxt.addMouseListener(
        new java.awt.event.MouseAdapter() {
          public void mouseReleased(java.awt.event.MouseEvent evt) {
            inputTxtMouseReleased(evt);
          }
        });
    inputTxt.addKeyListener(
        new java.awt.event.KeyAdapter() {
          public void keyReleased(java.awt.event.KeyEvent evt) {
            inputTxtKeyReleased(evt);
          }
        });

    previousButton.setIcon(
        new javax.swing.ImageIcon(getClass().getResource("/icons/previous_grey.png"))); // NOI18N
    previousButton.setToolTipText("Previous");
    previousButton.setBorder(null);
    previousButton.setBorderPainted(false);
    previousButton.setContentAreaFilled(false);
    previousButton.setIconTextGap(0);
    previousButton.setRolloverIcon(
        new javax.swing.ImageIcon(getClass().getResource("/icons/previous.png"))); // NOI18N
    previousButton.addMouseListener(
        new java.awt.event.MouseAdapter() {
          public void mouseEntered(java.awt.event.MouseEvent evt) {
            previousButtonMouseEntered(evt);
          }

          public void mouseExited(java.awt.event.MouseEvent evt) {
            previousButtonMouseExited(evt);
          }
        });
    previousButton.addActionListener(
        new java.awt.event.ActionListener() {
          public void actionPerformed(java.awt.event.ActionEvent evt) {
            previousButtonActionPerformed(evt);
          }
        });

    nextButton.setIcon(
        new javax.swing.ImageIcon(getClass().getResource("/icons/next_grey.png"))); // NOI18N
    nextButton.setToolTipText("Next");
    nextButton.setBorderPainted(false);
    nextButton.setContentAreaFilled(false);
    nextButton.setRolloverIcon(
        new javax.swing.ImageIcon(getClass().getResource("/icons/next.png"))); // NOI18N
    nextButton.addMouseListener(
        new java.awt.event.MouseAdapter() {
          public void mouseEntered(java.awt.event.MouseEvent evt) {
            nextButtonMouseEntered(evt);
          }

          public void mouseExited(java.awt.event.MouseEvent evt) {
            nextButtonMouseExited(evt);
          }
        });
    nextButton.addActionListener(
        new java.awt.event.ActionListener() {
          public void actionPerformed(java.awt.event.ActionEvent evt) {
            nextButtonActionPerformed(evt);
          }
        });

    indexLabel.setFont(
        indexLabel.getFont().deriveFont((indexLabel.getFont().getStyle() | java.awt.Font.ITALIC)));
    indexLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
    indexLabel.setText(" ");

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
    this.setLayout(layout);
    layout.setHorizontalGroup(
        layout
            .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(
                layout
                    .createSequentialGroup()
                    .addContainerGap()
                    .addComponent(findJLabel)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                    .addComponent(
                        inputTxt,
                        javax.swing.GroupLayout.PREFERRED_SIZE,
                        205,
                        javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                    .addComponent(
                        previousButton,
                        javax.swing.GroupLayout.PREFERRED_SIZE,
                        15,
                        javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGap(0, 0, 0)
                    .addComponent(
                        nextButton,
                        javax.swing.GroupLayout.PREFERRED_SIZE,
                        15,
                        javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                    .addComponent(
                        indexLabel,
                        javax.swing.GroupLayout.PREFERRED_SIZE,
                        97,
                        javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addContainerGap()));

    layout.linkSize(
        javax.swing.SwingConstants.HORIZONTAL,
        new java.awt.Component[] {nextButton, previousButton});

    layout.setVerticalGroup(
        layout
            .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(
                layout
                    .createSequentialGroup()
                    .addContainerGap()
                    .addGroup(
                        layout
                            .createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER)
                            .addComponent(findJLabel)
                            .addComponent(
                                inputTxt,
                                javax.swing.GroupLayout.PREFERRED_SIZE,
                                javax.swing.GroupLayout.DEFAULT_SIZE,
                                javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(indexLabel)
                            .addComponent(
                                previousButton,
                                javax.swing.GroupLayout.PREFERRED_SIZE,
                                15,
                                javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(
                                nextButton,
                                javax.swing.GroupLayout.PREFERRED_SIZE,
                                15,
                                javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addContainerGap()));
  } // </editor-fold>//GEN-END:initComponents

  /**
   * Update the jump to filter.
   *
   * @param evt the key event
   */
  private void inputTxtKeyReleased(
      java.awt.event.KeyEvent evt) { // GEN-FIRST:event_inputTxtKeyReleased

    final KeyEvent event = evt;
    keyPressedCounter++;

    new Thread("FindThread") {
      @Override
      public synchronized void run() {

        try {
          wait(waitingTime);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }

        try {
          // see if the gui is to be updated or not
          Identification identification = peptideShakerGUI.getIdentification();
          if (identification != null && keyPressedCounter == 1) {

            if (!inputTxt.getText().equalsIgnoreCase(welcomeText.get(jumpType))) {
              inputTxt.setForeground(Color.black);
            } else {
              inputTxt.setForeground(new Color(204, 204, 204));
            }

            if (event.getKeyCode() == KeyEvent.VK_UP && previousButton.isEnabled()) {
              previousButtonActionPerformed(null);
            } else if (event.getKeyCode() == KeyEvent.VK_DOWN && nextButton.isEnabled()) {
              nextButtonActionPerformed(null);
            } else {
              if (!possibilities.containsKey(jumpType)) {
                possibilities.put(jumpType, new ArrayList<String>());
                types.put(jumpType, new ArrayList<Type>());
              } else {
                possibilities.get(jumpType).clear();
                types.get(jumpType).clear();
              }
              currentSelection.put(jumpType, 0);
              String doubleString, input = inputTxt.getText().trim().toLowerCase();
              lastInput.put(jumpType, input);

              if (!input.equals("")) {

                peptideShakerGUI.setCursor(new java.awt.Cursor(java.awt.Cursor.WAIT_CURSOR));
                inputTxt.setCursor(new java.awt.Cursor(java.awt.Cursor.WAIT_CURSOR));

                if (jumpType == JumpType.proteinAndPeptides) {

                  for (String proteinKey :
                      peptideShakerGUI
                          .getIdentificationFeaturesGenerator()
                          .getProcessedProteinKeys(null, peptideShakerGUI.getFilterPreferences())) {
                    if (!ProteinMatch.isDecoy(proteinKey)) {
                      if (proteinKey.toLowerCase().contains(input)) {
                        possibilities.get(jumpType).add(proteinKey);
                        types.get(jumpType).add(Type.PROTEIN);
                      } else {
                        try {
                          for (String accession : ProteinMatch.getAccessions(proteinKey)) {
                            if (sequenceFactory
                                .getHeader(accession)
                                .getSimpleProteinDescription()
                                .toLowerCase()
                                .contains(input)) {
                              possibilities.get(jumpType).add(proteinKey);
                              types.get(jumpType).add(Type.PROTEIN);
                              break;
                            }
                          }
                        } catch (Exception e) {
                          // cannot get description, ignore
                        }
                      }
                    }
                  }

                  // check if it's a valid peptide sequence
                  boolean validPeptideSequence;
                  try {
                    AminoAcid.getMatchingSequence(
                        input,
                        peptideShakerGUI
                            .getIdentificationParameters()
                            .getSequenceMatchingPreferences());
                    validPeptideSequence = true;
                  } catch (IllegalArgumentException e) {
                    // ignore, not a peptide sequence
                    validPeptideSequence = false;
                  }

                  if (validPeptideSequence) {

                    ArrayList<String> secondaryCandidates = new ArrayList<String>();

                    // pre-caching
                    PSParameter psParameter = new PSParameter();
                    identification.loadPeptideMatchParameters(psParameter, null, false);
                    String matchingInput =
                        AminoAcid.getMatchingSequence(
                            input,
                            peptideShakerGUI
                                .getIdentificationParameters()
                                .getSequenceMatchingPreferences());

                    for (String peptideKey : identification.getPeptideIdentification()) {
                      try {
                        psParameter =
                            (PSParameter)
                                identification.getPeptideMatchParameter(peptideKey, psParameter);
                      } catch (Exception e) {
                        peptideShakerGUI.catchException(e);
                        return;
                      }
                      if (!psParameter.isHidden()) {
                        if (peptideKey.startsWith(matchingInput)) {
                          possibilities.get(jumpType).add(peptideKey);
                          types.get(jumpType).add(Type.PEPTIDE);
                        } else if (peptideKey.toLowerCase().contains(matchingInput)) {
                          secondaryCandidates.add(peptideKey);
                        }
                      }
                    }

                    PeptideMatchesIterator peptideMatchesIterator =
                        identification.getPeptideMatchesIterator(
                            secondaryCandidates,
                            null,
                            false,
                            null,
                            null); // @TODO: waiting handler?

                    while (peptideMatchesIterator.hasNext()) {

                      try {
                        PeptideMatch peptideMatch = peptideMatchesIterator.next();
                        String peptideKey = peptideMatch.getKey();
                        ArrayList<String> proteins =
                            peptideMatch.getTheoreticPeptide().getParentProteinsNoRemapping();
                        if (proteins != null) {
                          for (String protein : proteins) {
                            if (!ProteinMatch.isDecoy(protein)) {
                              possibilities.get(jumpType).add(peptideKey);
                              types.get(jumpType).add(Type.PEPTIDE);
                              break;
                            }
                          }
                        }
                      } catch (Exception e) {
                        peptideShakerGUI.catchException(e);
                        return;
                      }
                    }
                  }
                } else {
                  for (String spectrumTitle : spectrumFactory.getSpectrumTitles(spectrumfile)) {
                    String spectrumKey = Spectrum.getSpectrumKey(spectrumfile, spectrumTitle);
                    if (spectrumKey.toLowerCase().contains(input)) {
                      possibilities.get(jumpType).add(spectrumKey);
                      types.get(jumpType).add(Type.SPECTRUM);
                    } else {
                      try {
                        Precursor precursor = spectrumFactory.getPrecursor(spectrumKey);
                        doubleString = precursor.getMz() + "";
                        if (doubleString.startsWith(input)) {
                          possibilities.get(jumpType).add(spectrumKey);
                          types.get(jumpType).add(Type.SPECTRUM);
                        } else {
                          doubleString = precursor.getRt() + "";
                          if (doubleString.startsWith(input)) {
                            possibilities.get(jumpType).add(spectrumKey);
                            types.get(jumpType).add(Type.SPECTRUM);
                          }
                        }
                      } catch (Exception e) {
                        e.printStackTrace();
                      }
                    }
                  }
                }

                if (possibilities.get(jumpType).size() > 0) {

                  if (possibilities.get(jumpType).size() > 1) {
                    previousButton.setEnabled(true);
                    nextButton.setEnabled(true);
                  } else { // possibilities.size() == 1
                    previousButton.setEnabled(false);
                    nextButton.setEnabled(false);
                  }

                  updateSelectionInTab();
                } else {
                  previousButton.setEnabled(false);
                  nextButton.setEnabled(false);

                  if (!input.equalsIgnoreCase(welcomeText.get(jumpType))) {
                    indexLabel.setText("(no matches)");
                  } else {
                    indexLabel.setText("");
                  }
                }

                peptideShakerGUI.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
                inputTxt.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));

              } else {
                indexLabel.setText("");
                previousButton.setEnabled(false);
                nextButton.setEnabled(false);
                inputTxt.setText(welcomeText.get(jumpType));
                inputTxt.selectAll();
              }
            }

            lastLabel.put(jumpType, indexLabel.getText());

            // gui updated, reset the counter
            keyPressedCounter = 0;
          } else {
            // gui not updated, decrease the counter
            keyPressedCounter--;
          }
        } catch (Exception e) {
          peptideShakerGUI.catchException(e);
        }
      }
    }.start();
  } // GEN-LAST:event_inputTxtKeyReleased

  /**
   * Display the previous match in the list.
   *
   * @param evt the action event
   */
  private void previousButtonActionPerformed(
      java.awt.event.ActionEvent evt) { // GEN-FIRST:event_previousButtonActionPerformed
    if (currentSelection.get(jumpType) == 0) {
      currentSelection.put(jumpType, possibilities.get(jumpType).size() - 1);
    } else {
      currentSelection.put(jumpType, currentSelection.get(jumpType) - 1);
    }
    updateSelectionInTab();
  } // GEN-LAST:event_previousButtonActionPerformed

  /**
   * Display the next match in the list.
   *
   * @param evt the action event
   */
  private void nextButtonActionPerformed(
      java.awt.event.ActionEvent evt) { // GEN-FIRST:event_nextButtonActionPerformed
    if (currentSelection.get(jumpType) == possibilities.get(jumpType).size() - 1) {
      currentSelection.put(jumpType, 0);
    } else {
      currentSelection.put(jumpType, currentSelection.get(jumpType) + 1);
    }
    updateSelectionInTab();
  } // GEN-LAST:event_nextButtonActionPerformed

  /**
   * Select all text in the search field.
   *
   * @param evt the mouse event
   */
  private void inputTxtMouseReleased(
      java.awt.event.MouseEvent evt) { // GEN-FIRST:event_inputTxtMouseReleased
    if (inputTxt.getText().equals(welcomeText.get(jumpType))) {
      inputTxt.selectAll();
    }
  } // GEN-LAST:event_inputTxtMouseReleased

  /**
   * Change the icon to a hand icon.
   *
   * @param evt the mouse event
   */
  private void previousButtonMouseEntered(
      java.awt.event.MouseEvent evt) { // GEN-FIRST:event_previousButtonMouseEntered
    if (previousButton.isEnabled()) {
      this.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
    }
  } // GEN-LAST:event_previousButtonMouseEntered

  /**
   * Change the icon back to the default icon.
   *
   * @param evt the mouse event
   */
  private void previousButtonMouseExited(
      java.awt.event.MouseEvent evt) { // GEN-FIRST:event_previousButtonMouseExited
    this.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
  } // GEN-LAST:event_previousButtonMouseExited

  /**
   * Change the icon back to the default icon.
   *
   * @param evt the mouse event
   */
  private void nextButtonMouseExited(
      java.awt.event.MouseEvent evt) { // GEN-FIRST:event_nextButtonMouseExited
    this.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
  } // GEN-LAST:event_nextButtonMouseExited

  /**
   * Change the icon to a hand icon.
   *
   * @param evt the mouse event
   */
  private void nextButtonMouseEntered(
      java.awt.event.MouseEvent evt) { // GEN-FIRST:event_nextButtonMouseEntered
    if (nextButton.isEnabled()) {
      this.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
    }
  } // GEN-LAST:event_nextButtonMouseEntered
  // Variables declaration - do not modify//GEN-BEGIN:variables
  private javax.swing.JLabel findJLabel;
  private javax.swing.JLabel indexLabel;
  private javax.swing.JTextField inputTxt;
  private javax.swing.JButton nextButton;
  private javax.swing.JButton previousButton;
  // End of variables declaration//GEN-END:variables

  @Override
  public void setEnabled(boolean enabled) {

    inputTxt.setEnabled(enabled);
    indexLabel.setEnabled(enabled);

    if (possibilities.size() > 0 && enabled) {
      previousButton.setEnabled(true);
      nextButton.setEnabled(true);
    } else {
      previousButton.setEnabled(false);
      nextButton.setEnabled(false);
    }
  }

  /**
   * Changes the type of jumpToPanel.
   *
   * @param jumpType the new type of jump to panel
   */
  public void setType(JumpType jumpType) {
    this.jumpType = jumpType;
    if (lastInput.get(jumpType) != null && !lastInput.get(jumpType).equals("")) {
      inputTxt.setText(lastInput.get(jumpType));
      indexLabel.setText(lastLabel.get(jumpType));
    } else {
      inputTxt.setText(welcomeText.get(jumpType));
      indexLabel.setText("");
    }
  }

  /**
   * Sets the spectrum file inspected.
   *
   * @param spectrumFile the name of the spectrum file inspected
   */
  public void setSpectrumFile(String spectrumFile) {
    this.spectrumfile = spectrumFile;
  }
}
  /**
   * Fills the PSM specific map.
   *
   * @param inputMap The input map
   * @param waitingHandler the handler displaying feedback to the user
   * @param shotgunProtocol information about the protocol
   * @param identificationParameters the identification parameters
   * @throws java.sql.SQLException exception thrown whenever an error occurred while interacting
   *     with the back-end database
   * @throws java.io.IOException exception thrown whenever an error occurred while reading an
   *     external file
   * @throws java.lang.ClassNotFoundException exception thrown whenever an error occurred while
   *     deserializing an object
   * @throws java.lang.InterruptedException exception thrown whenever a threading error occurred
   * @throws uk.ac.ebi.jmzml.xml.io.MzMLUnmarshallerException exception thrown whenever an error
   *     occurred while reading an mzML file
   */
  public void selectBestHitAndFillPsmMap(
      InputMap inputMap,
      WaitingHandler waitingHandler,
      ShotgunProtocol shotgunProtocol,
      IdentificationParameters identificationParameters)
      throws SQLException, IOException, ClassNotFoundException, InterruptedException,
          MzMLUnmarshallerException {

    waitingHandler.setSecondaryProgressCounterIndeterminate(false);
    waitingHandler.setMaxSecondaryProgressCounter(identification.getSpectrumIdentificationSize());

    PeptideSpectrumAnnotator spectrumAnnotator = new PeptideSpectrumAnnotator();
    boolean multiSE = inputMap.isMultipleAlgorithms();

    SequenceMatchingPreferences sequenceMatchingPreferences =
        identificationParameters.getSequenceMatchingPreferences();
    AnnotationSettings annotationPreferences = identificationParameters.getAnnotationPreferences();

    PeptideAssumptionFilter idFilter = identificationParameters.getPeptideAssumptionFilter();

    // Keep a map of the spectrum keys grouped by peptide
    HashMap<String, ArrayList<String>> orderedPsmMap = null;
    if (MemoryConsumptionStatus.memoryUsed() < 0.8) {
      orderedPsmMap =
          new HashMap<String, ArrayList<String>>(
              identification.getSpectrumIdentificationMap().size());
    }

    PSParameter psParameter = new PSParameter();

    for (String spectrumFileName : identification.getSpectrumFiles()) {

      HashMap<String, ArrayList<String>> keysMap = null;
      if (orderedPsmMap != null) {
        keysMap = new HashMap<String, ArrayList<String>>();
      }

      PsmIterator psmIterator =
          identification.getPsmIterator(spectrumFileName, null, true, waitingHandler);

      while (psmIterator.hasNext()) {

        SpectrumMatch advocateMatch = psmIterator.next();
        String spectrumKey = advocateMatch.getKey();

        // map of the peptide first hits for this spectrum: score -> max protein count -> max search
        // engine votes -> amino acids annotated -> min mass deviation -> peptide sequence
        HashMap<
                Double,
                HashMap<
                    Integer,
                    HashMap<
                        Integer,
                        HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>>>>
            peptideAssumptions =
                new HashMap<
                    Double,
                    HashMap<
                        Integer,
                        HashMap<
                            Integer,
                            HashMap<
                                Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>>>>();

        // map of the tag first hits: score -> assumptions
        HashMap<Double, ArrayList<TagAssumption>> tagAssumptions =
            new HashMap<Double, ArrayList<TagAssumption>>();

        ArrayList<String> identifications = new ArrayList<String>();

        HashMap<Integer, HashMap<Double, ArrayList<SpectrumIdentificationAssumption>>> assumptions =
            identification.getAssumptions(spectrumKey);

        for (int searchEngine1 : assumptions.keySet()) {

          HashMap<Double, ArrayList<SpectrumIdentificationAssumption>> advocate1Map =
              assumptions.get(searchEngine1);

          double bestEvalue = Collections.min(advocate1Map.keySet());

          for (SpectrumIdentificationAssumption assumption1 : advocate1Map.get(bestEvalue)) {

            if (assumption1 instanceof PeptideAssumption) {

              PeptideAssumption peptideAssumption1 = (PeptideAssumption) assumption1;
              String id = peptideAssumption1.getPeptide().getKey();

              if (!identifications.contains(id)) {

                psParameter = (PSParameter) peptideAssumption1.getUrParam(psParameter);
                double p;

                if (multiSE && sequenceFactory.concatenatedTargetDecoy()) {
                  p = psParameter.getSearchEngineProbability();
                } else {
                  p = peptideAssumption1.getScore();
                }

                int nSE = 1;
                int proteinMax = 1;
                for (String protein :
                    peptideAssumption1
                        .getPeptide()
                        .getParentProteins(sequenceMatchingPreferences)) {
                  Integer tempCount = proteinCount.get(protein);
                  if (tempCount != null && tempCount > proteinMax) {
                    proteinMax = tempCount;
                  }
                }

                for (int searchEngine2 : assumptions.keySet()) {

                  if (searchEngine1 != searchEngine2) {

                    HashMap<Double, ArrayList<SpectrumIdentificationAssumption>> advocate2Map =
                        assumptions.get(searchEngine2);

                    boolean found = false;
                    ArrayList<Double> eValues2 = new ArrayList<Double>(advocate2Map.keySet());
                    Collections.sort(eValues2);

                    for (double eValue2 : eValues2) {
                      for (SpectrumIdentificationAssumption assumption2 :
                          advocate2Map.get(eValue2)) {

                        if (assumption2 instanceof PeptideAssumption) {

                          PeptideAssumption peptideAssumption2 = (PeptideAssumption) assumption2;

                          if (peptideAssumption1
                              .getPeptide()
                              .isSameSequenceAndModificationStatus(
                                  peptideAssumption2.getPeptide(), sequenceMatchingPreferences)) {
                            PSParameter psParameter2 =
                                (PSParameter) peptideAssumption2.getUrParam(psParameter);
                            p = p * psParameter2.getSearchEngineProbability();
                            nSE++;
                            found = true;
                            break;
                          }
                        }
                      }
                      if (found) {
                        break;
                      }
                    }
                  }
                }

                identifications.add(id);

                HashMap<
                        Integer,
                        HashMap<
                            Integer,
                            HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>>>
                    pMap = peptideAssumptions.get(p);
                if (pMap == null) {
                  pMap =
                      new HashMap<
                          Integer,
                          HashMap<
                              Integer,
                              HashMap<
                                  Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>>>(
                          advocate1Map.size());
                  peptideAssumptions.put(p, pMap);
                }

                HashMap<
                        Integer,
                        HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>>
                    proteinMaxMap = pMap.get(proteinMax);
                if (proteinMaxMap == null) {
                  proteinMaxMap =
                      new HashMap<
                          Integer,
                          HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>>(1);
                  pMap.put(proteinMax, proteinMaxMap);
                }

                HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>> nSeMap =
                    proteinMaxMap.get(nSE);
                if (nSeMap == null) {
                  nSeMap =
                      new HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>(1);
                  proteinMaxMap.put(nSE, nSeMap);
                  HashMap<Double, HashMap<String, PeptideAssumption>> coverageMap =
                      new HashMap<Double, HashMap<String, PeptideAssumption>>(1);
                  nSeMap.put(-1, coverageMap);
                  HashMap<String, PeptideAssumption> assumptionMap =
                      new HashMap<String, PeptideAssumption>(1);
                  coverageMap.put(-1.0, assumptionMap);
                  assumptionMap.put(
                      peptideAssumption1.getPeptide().getSequenceWithLowerCasePtms(),
                      peptideAssumption1);
                } else {
                  MSnSpectrum spectrum = (MSnSpectrum) spectrumFactory.getSpectrum(spectrumKey);

                  HashMap<Double, HashMap<String, PeptideAssumption>> coverageMap = nSeMap.get(-1);
                  if (coverageMap != null) {
                    HashMap<String, PeptideAssumption> assumptionMap = coverageMap.get(-1.0);
                    for (PeptideAssumption tempAssumption :
                        assumptionMap.values()) { // There should be only one
                      Peptide peptide = tempAssumption.getPeptide();
                      SpecificAnnotationSettings specificAnnotationPreferences =
                          annotationPreferences.getSpecificAnnotationPreferences(
                              spectrum.getSpectrumKey(),
                              tempAssumption,
                              identificationParameters.getSequenceMatchingPreferences(),
                              identificationParameters
                                  .getPtmScoringPreferences()
                                  .getSequenceMatchingPreferences());
                      HashMap<Integer, ArrayList<IonMatch>> coveredAminoAcids =
                          spectrumAnnotator.getCoveredAminoAcids(
                              annotationPreferences,
                              specificAnnotationPreferences,
                              (MSnSpectrum) spectrum,
                              peptide);
                      int nIons = coveredAminoAcids.size();
                      nSeMap.put(nIons, coverageMap);
                    }
                    nSeMap.remove(-1);
                  }

                  Peptide peptide = peptideAssumption1.getPeptide();
                  SpecificAnnotationSettings specificAnnotationPreferences =
                      annotationPreferences.getSpecificAnnotationPreferences(
                          spectrum.getSpectrumKey(),
                          peptideAssumption1,
                          identificationParameters.getSequenceMatchingPreferences(),
                          identificationParameters
                              .getPtmScoringPreferences()
                              .getSequenceMatchingPreferences());
                  HashMap<Integer, ArrayList<IonMatch>> coveredAminoAcids =
                      spectrumAnnotator.getCoveredAminoAcids(
                          annotationPreferences,
                          specificAnnotationPreferences,
                          (MSnSpectrum) spectrum,
                          peptide);
                  int nIons = coveredAminoAcids.size();

                  coverageMap = nSeMap.get(nIons);
                  if (coverageMap == null) {
                    coverageMap = new HashMap<Double, HashMap<String, PeptideAssumption>>(1);
                    HashMap<String, PeptideAssumption> assumptionMap =
                        new HashMap<String, PeptideAssumption>(1);
                    assumptionMap.put(
                        peptideAssumption1.getPeptide().getSequenceWithLowerCasePtms(),
                        peptideAssumption1);
                    coverageMap.put(-1.0, assumptionMap);
                    nSeMap.put(nIons, coverageMap);
                  } else {
                    HashMap<String, PeptideAssumption> assumptionMap = coverageMap.get(-1.0);
                    if (assumptionMap != null) {
                      for (PeptideAssumption tempAssumption :
                          assumptionMap.values()) { // There should be only one
                        double massError =
                            Math.abs(
                                tempAssumption.getDeltaMass(
                                    spectrum.getPrecursor().getMz(),
                                    shotgunProtocol.isMs1ResolutionPpm()));
                        coverageMap.put(massError, assumptionMap);
                      }
                      coverageMap.remove(-1.0);
                    }

                    double massError =
                        Math.abs(
                            peptideAssumption1.getDeltaMass(
                                spectrum.getPrecursor().getMz(),
                                shotgunProtocol.isMs1ResolutionPpm()));
                    assumptionMap = coverageMap.get(massError);
                    if (assumptionMap == null) {
                      assumptionMap = new HashMap<String, PeptideAssumption>(1);
                      coverageMap.put(massError, assumptionMap);
                    }
                    assumptionMap.put(
                        peptideAssumption1.getPeptide().getSequenceWithLowerCasePtms(),
                        peptideAssumption1);
                  }
                }
              }
            } else if (assumption1 instanceof TagAssumption) {
              TagAssumption tagAssumption = (TagAssumption) assumption1;
              ArrayList<TagAssumption> assumptionList = tagAssumptions.get(bestEvalue);
              if (assumptionList == null) {
                assumptionList = new ArrayList<TagAssumption>();
                tagAssumptions.put(bestEvalue, assumptionList);
              }
              assumptionList.add(tagAssumption);
            }
          }
        }

        SpectrumMatch spectrumMatch = new SpectrumMatch(spectrumKey);
        if (!peptideAssumptions.isEmpty()) {

          PeptideAssumption bestPeptideAssumption = null;
          ArrayList<Double> ps = new ArrayList<Double>(peptideAssumptions.keySet());
          Collections.sort(ps);
          double retainedP = 0;

          for (double p : ps) {

            retainedP = p;
            HashMap<
                    Integer,
                    HashMap<
                        Integer,
                        HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>>>
                pMap = peptideAssumptions.get(p);
            ArrayList<Integer> proteinMaxs = new ArrayList<Integer>(pMap.keySet());
            Collections.sort(proteinMaxs, Collections.reverseOrder());

            for (int proteinMax : proteinMaxs) {

              HashMap<
                      Integer,
                      HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>>
                  proteinMaxMap = pMap.get(proteinMax);
              ArrayList<Integer> nSEs = new ArrayList<Integer>(proteinMaxMap.keySet());
              Collections.sort(nSEs, Collections.reverseOrder());

              for (int nSE : nSEs) {

                HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>> nSeMap =
                    proteinMaxMap.get(nSE);
                ArrayList<Integer> coverages = new ArrayList<Integer>(nSeMap.keySet());
                Collections.sort(coverages, Collections.reverseOrder());

                for (Integer coverage : coverages) {

                  HashMap<Double, HashMap<String, PeptideAssumption>> coverageMap =
                      nSeMap.get(coverage);
                  ArrayList<Double> minErrors = new ArrayList<Double>(coverageMap.keySet());
                  Collections.sort(minErrors);

                  for (double minError : minErrors) {

                    HashMap<String, PeptideAssumption> bestPeptideAssumptions =
                        coverageMap.get(minError);
                    ArrayList<String> sequences =
                        new ArrayList<String>(bestPeptideAssumptions.keySet());
                    Collections.sort(sequences);

                    for (String sequence : sequences) {
                      PeptideAssumption peptideAssumption = bestPeptideAssumptions.get(sequence);
                      if (idFilter.validateProteins(
                          peptideAssumption.getPeptide(), sequenceMatchingPreferences)) {
                        bestPeptideAssumption = peptideAssumption;
                        break;
                      }
                    }
                    if (bestPeptideAssumption != null) {
                      break;
                    }
                  }
                  if (bestPeptideAssumption != null) {
                    break;
                  }
                }
                if (bestPeptideAssumption != null) {
                  break;
                }
              }
              if (bestPeptideAssumption != null) {
                break;
              }
            }
            if (bestPeptideAssumption != null) {
              break;
            }
          }
          if (bestPeptideAssumption != null) {

            if (multiSE) {

              // try to find the most likely modification localization based on the search engine
              // results
              HashMap<PeptideAssumption, ArrayList<Double>> assumptionPEPs =
                  new HashMap<PeptideAssumption, ArrayList<Double>>();
              String bestAssumptionKey =
                  bestPeptideAssumption.getPeptide().getMatchingKey(sequenceMatchingPreferences);

              for (int searchEngine : assumptions.keySet()) {

                boolean found = false;
                HashMap<Double, ArrayList<SpectrumIdentificationAssumption>> advocateMap =
                    assumptions.get(searchEngine);
                ArrayList<Double> eValues = new ArrayList<Double>(advocateMap.keySet());
                Collections.sort(eValues);

                for (double eValue : eValues) {
                  for (SpectrumIdentificationAssumption assumption : advocateMap.get(eValue)) {

                    if (assumption instanceof PeptideAssumption) {

                      PeptideAssumption peptideAssumption = (PeptideAssumption) assumption;

                      if (peptideAssumption
                          .getPeptide()
                          .getMatchingKey(sequenceMatchingPreferences)
                          .equals(bestAssumptionKey)) {

                        found = true;
                        boolean found2 = false;

                        for (PeptideAssumption assumption1 : assumptionPEPs.keySet()) {
                          if (assumption1
                              .getPeptide()
                              .sameModificationsAs(peptideAssumption.getPeptide())) {
                            found2 = true;
                            psParameter = (PSParameter) assumption.getUrParam(psParameter);
                            ArrayList<Double> peps = assumptionPEPs.get(assumption1);
                            peps.add(psParameter.getSearchEngineProbability());
                            break;
                          }
                        }

                        if (!found2) {
                          ArrayList<Double> peps = new ArrayList<Double>(1);
                          assumptionPEPs.put(peptideAssumption, peps);
                          psParameter = (PSParameter) assumption.getUrParam(psParameter);
                          peps.add(psParameter.getSearchEngineProbability());
                        }
                      }
                    }
                  }

                  if (found) {
                    break;
                  }
                }
              }

              Double bestSeP = null;
              int nSe = -1;

              for (PeptideAssumption peptideAssumption : assumptionPEPs.keySet()) {

                ArrayList<Double> peps = assumptionPEPs.get(peptideAssumption);
                Double sep = Collections.min(peps);

                if (bestSeP == null || bestSeP > sep) {
                  bestSeP = sep;
                  nSe = peps.size();
                  bestPeptideAssumption = peptideAssumption;
                } else if (peps.size() > nSe) {
                  if (sep != null && (Math.abs(sep - bestSeP) <= 1e-10)) {
                    nSe = peps.size();
                    bestPeptideAssumption = peptideAssumption;
                  }
                }
              }
            }

            // create a PeptideShaker match based on the best search engine match
            Peptide sePeptide = bestPeptideAssumption.getPeptide();
            ArrayList<String> psProteins =
                new ArrayList<String>(sePeptide.getParentProteins(sequenceMatchingPreferences));
            ArrayList<ModificationMatch> psModificationMatches = null;
            if (sePeptide.isModified()) {
              psModificationMatches =
                  new ArrayList<ModificationMatch>(sePeptide.getNModifications());
              for (ModificationMatch seModMatch : sePeptide.getModificationMatches()) {
                psModificationMatches.add(
                    new ModificationMatch(
                        seModMatch.getTheoreticPtm(),
                        seModMatch.isVariable(),
                        seModMatch.getModificationSite()));
              }
            }

            Peptide psPeptide = new Peptide(sePeptide.getSequence(), psModificationMatches);
            psPeptide.setParentProteins(psProteins);
            PeptideAssumption psAssumption =
                new PeptideAssumption(
                    psPeptide,
                    1,
                    Advocate.peptideShaker.getIndex(),
                    bestPeptideAssumption.getIdentificationCharge(),
                    retainedP);

            spectrumMatch.setBestPeptideAssumption(psAssumption);

            if (orderedPsmMap != null) {
              String peptideKey = psPeptide.getMatchingKey(sequenceMatchingPreferences);
              ArrayList<String> spectrumKeys = keysMap.get(peptideKey);
              if (spectrumKeys == null) {
                spectrumKeys = new ArrayList<String>();
                keysMap.put(peptideKey, spectrumKeys);
              }
              spectrumKeys.add(spectrumKey);
            }

            psParameter = new PSParameter();
            psParameter.setSpectrumProbabilityScore(retainedP);

            PSParameter matchParameter =
                (PSParameter) bestPeptideAssumption.getUrParam(psParameter);
            psParameter.setSearchEngineProbability(matchParameter.getSearchEngineProbability());
            psParameter.setAlgorithmDeltaPEP(matchParameter.getAlgorithmDeltaPEP());
            psParameter.setDeltaPEP(matchParameter.getDeltaPEP());

            matchesValidator
                .getPsmMap()
                .addPoint(
                    psParameter.getPsmProbabilityScore(),
                    spectrumMatch,
                    sequenceMatchingPreferences);
            psParameter.setSpecificMapKey(
                spectrumMatch.getBestPeptideAssumption().getIdentificationCharge().value + "");
            identification.addSpectrumMatchParameter(spectrumKey, psParameter);
            identification.updateSpectrumMatch(spectrumMatch);
          }
        }
        if (!tagAssumptions.isEmpty()) {
          ArrayList<Double> evalues = new ArrayList<Double>(tagAssumptions.keySet());
          Double bestEvalue = Collections.min(evalues);
          TagAssumption bestAssumption = tagAssumptions.get(bestEvalue).get(0);
          spectrumMatch.setBestTagAssumption(bestAssumption);
          identification.updateSpectrumMatch(spectrumMatch);
          if (spectrumMatch.getBestPeptideAssumption() == null) {
            psParameter = new PSParameter();
            if (!multiSE) {
              psParameter.setSpectrumProbabilityScore(bestEvalue);
            }
            PSParameter matchParameter = (PSParameter) bestAssumption.getUrParam(psParameter);
            psParameter.setSearchEngineProbability(matchParameter.getSearchEngineProbability());
            psParameter.setAlgorithmDeltaPEP(matchParameter.getAlgorithmDeltaPEP());
            psParameter.setDeltaPEP(matchParameter.getDeltaPEP());
            psParameter.setSpecificMapKey(
                spectrumMatch.getBestTagAssumption().getIdentificationCharge().value + "");
            identification.addSpectrumMatchParameter(spectrumKey, psParameter);
          }
        }
        waitingHandler.increaseSecondaryProgressCounter();
        if (waitingHandler.isRunCanceled()) {
          return;
        }
      }

      if (orderedPsmMap != null) {
        ArrayList<String> orderedKeys =
            new ArrayList<String>(
                identification.getSpectrumIdentification(spectrumFileName).size());
        for (ArrayList<String> keys : keysMap.values()) {
          orderedKeys.addAll(keys);
        }
        orderedPsmMap.put(spectrumFileName, orderedKeys);

        if (MemoryConsumptionStatus.memoryUsed() > 0.9) {
          orderedPsmMap = null;
        }
      }
    }

    if (orderedPsmMap != null) {
      metrics.setOrderedSpectrumKeys(orderedPsmMap);
    }

    // the protein count map is no longer needed
    proteinCount.clear();

    waitingHandler.setSecondaryProgressCounterIndeterminate(true);
  }
  /**
   * Selects a first hit in a list of equally scoring peptide matches. The selection is made based
   * on: 1 - The occurrence of the protein detection as given in the proteinCount map 2 - The
   * sequence coverage by fragment ions 3 - The precursor mass error.
   *
   * <p>If no best hit is found, the first one sorted alphabetically is retained.
   *
   * @param spectrumKey the key of the spectrum
   * @param firstHits list of equally scoring peptide matches
   * @param proteinCount map of the number of peptides for every protein
   * @param sequenceMatchingPreferences the sequence matching preferences
   * @param shotgunProtocol the shotgun protocol
   * @param identificationParameters the identification parameters
   * @param spectrumAnnotator the spectrum annotator to use
   * @return a first hit from the list of equally scoring peptide matches
   * @throws IOException exception thrown whenever an IO exception occurred while remapping the
   *     proteins or getting the spectrum
   * @throws InterruptedException exception thrown whenever an interrupted exception occurred while
   *     remapping the proteins or getting the spectrum
   * @throws SQLException exception thrown whenever an SQL exception occurred while interacting with
   *     the protein tree
   * @throws ClassNotFoundException exception thrown whenever an exception occurred while
   *     deserializing an object
   * @throws MzMLUnmarshallerException exception thrown whenever an exception occurred while reading
   *     an mzML file
   */
  public static PeptideAssumption getBestHit(
      String spectrumKey,
      ArrayList<PeptideAssumption> firstHits,
      HashMap<String, Integer> proteinCount,
      SequenceMatchingPreferences sequenceMatchingPreferences,
      ShotgunProtocol shotgunProtocol,
      IdentificationParameters identificationParameters,
      PeptideSpectrumAnnotator spectrumAnnotator)
      throws IOException, InterruptedException, SQLException, ClassNotFoundException,
          MzMLUnmarshallerException {

    if (firstHits.size() == 1) {
      return firstHits.get(0);
    }

    Integer maxProteins = 0;
    ArrayList<PeptideAssumption> bestPeptideAssumptions =
        new ArrayList<PeptideAssumption>(firstHits.size());

    for (PeptideAssumption peptideAssumption : firstHits) {
      for (String accession :
          peptideAssumption.getPeptide().getParentProteins(sequenceMatchingPreferences)) {
        Integer count = proteinCount.get(accession);
        if (count != null) {
          if (count > maxProteins) {
            maxProteins = count;
            bestPeptideAssumptions.clear();
            bestPeptideAssumptions.add(peptideAssumption);
          } else if (count.equals(maxProteins)) {
            bestPeptideAssumptions.add(peptideAssumption);
          }
        }
      }
    }

    if (bestPeptideAssumptions.size() == 1) {
      return bestPeptideAssumptions.get(0);
    } else if (!bestPeptideAssumptions.isEmpty()) {
      firstHits = bestPeptideAssumptions;
      bestPeptideAssumptions = new ArrayList<PeptideAssumption>(firstHits.size());
    }

    MSnSpectrum spectrum = (MSnSpectrum) SpectrumFactory.getInstance().getSpectrum(spectrumKey);
    int maxCoveredAminoAcids = 0;
    AnnotationSettings annotationPreferences = identificationParameters.getAnnotationPreferences();

    for (PeptideAssumption peptideAssumption : firstHits) {
      Peptide peptide = peptideAssumption.getPeptide();
      SpecificAnnotationSettings specificAnnotationPreferences =
          annotationPreferences.getSpecificAnnotationPreferences(
              spectrum.getSpectrumKey(),
              peptideAssumption,
              identificationParameters.getSequenceMatchingPreferences(),
              identificationParameters.getPtmScoringPreferences().getSequenceMatchingPreferences());
      HashMap<Integer, ArrayList<IonMatch>> coveredAminoAcids =
          spectrumAnnotator.getCoveredAminoAcids(
              annotationPreferences,
              specificAnnotationPreferences,
              (MSnSpectrum) spectrum,
              peptide);
      int nAas = coveredAminoAcids.size();
      if (nAas > maxCoveredAminoAcids) {
        maxCoveredAminoAcids = nAas;
        bestPeptideAssumptions.clear();
        bestPeptideAssumptions.add(peptideAssumption);
      } else if (nAas == maxCoveredAminoAcids) {
        bestPeptideAssumptions.add(peptideAssumption);
      }
    }

    if (bestPeptideAssumptions.size() == 1) {
      return bestPeptideAssumptions.get(0);
    } else if (!bestPeptideAssumptions.isEmpty()) {
      firstHits = bestPeptideAssumptions;
      bestPeptideAssumptions = new ArrayList<PeptideAssumption>(firstHits.size());
    }

    double minMassError = identificationParameters.getPeptideAssumptionFilter().getMaxMzDeviation();
    if (minMassError == -1.0) {
      minMassError = identificationParameters.getSearchParameters().getPrecursorAccuracy();
    }

    for (PeptideAssumption peptideAssumption : firstHits) {
      double massError =
          Math.abs(
              peptideAssumption.getDeltaMass(
                  spectrum.getPrecursor().getMz(), shotgunProtocol.isMs1ResolutionPpm()));
      if (massError < minMassError) {
        minMassError = massError;
        bestPeptideAssumptions.clear();
        bestPeptideAssumptions.add(peptideAssumption);
      } else if (massError == minMassError) {
        bestPeptideAssumptions.add(peptideAssumption);
      }
    }

    if (bestPeptideAssumptions.size() == 1) {
      return bestPeptideAssumptions.get(0);
    } else if (bestPeptideAssumptions.isEmpty()) {
      bestPeptideAssumptions = firstHits;
    }

    HashMap<String, PeptideAssumption> sequenceToPeptideAssumptionsMap =
        new HashMap<String, PeptideAssumption>(bestPeptideAssumptions.size());
    for (PeptideAssumption peptideAssumption : bestPeptideAssumptions) {
      sequenceToPeptideAssumptionsMap.put(
          peptideAssumption.getPeptide().getSequence(), peptideAssumption);
    }

    ArrayList<String> sequences = new ArrayList<String>(sequenceToPeptideAssumptionsMap.keySet());
    Collections.sort(sequences);
    return sequenceToPeptideAssumptionsMap.get(sequences.get(0));
  }
/**
 * This class contains the method for PSM best hit selection.
 *
 * @author Marc Vaudel
 */
public class BestMatchSelection {

  /** The sequence factory. */
  private SequenceFactory sequenceFactory = SequenceFactory.getInstance();
  /** The spectrum factory. */
  private SpectrumFactory spectrumFactory = SpectrumFactory.getInstance();
  /**
   * Map indicating how often a protein was found in a search engine first hit whenever this protein
   * was found more than one time.
   */
  private HashMap<String, Integer> proteinCount = new HashMap<String, Integer>();
  /** The identification object. */
  private Identification identification;
  /** The validator which will take care of the matches validation. */
  private MatchesValidator matchesValidator;
  /** Metrics to be picked when loading the identification. */
  private Metrics metrics = new Metrics();

  /**
   * Constructor.
   *
   * @param identification the identification object where to get the matches from
   * @param proteinCount a map of proteins found multiple times
   * @param matchesValidator the matches validator
   * @param metrics the object where to store dataset metrics
   */
  public BestMatchSelection(
      Identification identification,
      HashMap<String, Integer> proteinCount,
      MatchesValidator matchesValidator,
      Metrics metrics) {
    this.identification = identification;
    this.proteinCount = proteinCount;
    this.matchesValidator = matchesValidator;
    this.metrics = metrics;
  }

  /**
   * Fills the PSM specific map.
   *
   * @param inputMap The input map
   * @param waitingHandler the handler displaying feedback to the user
   * @param shotgunProtocol information about the protocol
   * @param identificationParameters the identification parameters
   * @throws java.sql.SQLException exception thrown whenever an error occurred while interacting
   *     with the back-end database
   * @throws java.io.IOException exception thrown whenever an error occurred while reading an
   *     external file
   * @throws java.lang.ClassNotFoundException exception thrown whenever an error occurred while
   *     deserializing an object
   * @throws java.lang.InterruptedException exception thrown whenever a threading error occurred
   * @throws uk.ac.ebi.jmzml.xml.io.MzMLUnmarshallerException exception thrown whenever an error
   *     occurred while reading an mzML file
   */
  public void selectBestHitAndFillPsmMap(
      InputMap inputMap,
      WaitingHandler waitingHandler,
      ShotgunProtocol shotgunProtocol,
      IdentificationParameters identificationParameters)
      throws SQLException, IOException, ClassNotFoundException, InterruptedException,
          MzMLUnmarshallerException {

    waitingHandler.setSecondaryProgressCounterIndeterminate(false);
    waitingHandler.setMaxSecondaryProgressCounter(identification.getSpectrumIdentificationSize());

    PeptideSpectrumAnnotator spectrumAnnotator = new PeptideSpectrumAnnotator();
    boolean multiSE = inputMap.isMultipleAlgorithms();

    SequenceMatchingPreferences sequenceMatchingPreferences =
        identificationParameters.getSequenceMatchingPreferences();
    AnnotationSettings annotationPreferences = identificationParameters.getAnnotationPreferences();

    PeptideAssumptionFilter idFilter = identificationParameters.getPeptideAssumptionFilter();

    // Keep a map of the spectrum keys grouped by peptide
    HashMap<String, ArrayList<String>> orderedPsmMap = null;
    if (MemoryConsumptionStatus.memoryUsed() < 0.8) {
      orderedPsmMap =
          new HashMap<String, ArrayList<String>>(
              identification.getSpectrumIdentificationMap().size());
    }

    PSParameter psParameter = new PSParameter();

    for (String spectrumFileName : identification.getSpectrumFiles()) {

      HashMap<String, ArrayList<String>> keysMap = null;
      if (orderedPsmMap != null) {
        keysMap = new HashMap<String, ArrayList<String>>();
      }

      PsmIterator psmIterator =
          identification.getPsmIterator(spectrumFileName, null, true, waitingHandler);

      while (psmIterator.hasNext()) {

        SpectrumMatch advocateMatch = psmIterator.next();
        String spectrumKey = advocateMatch.getKey();

        // map of the peptide first hits for this spectrum: score -> max protein count -> max search
        // engine votes -> amino acids annotated -> min mass deviation -> peptide sequence
        HashMap<
                Double,
                HashMap<
                    Integer,
                    HashMap<
                        Integer,
                        HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>>>>
            peptideAssumptions =
                new HashMap<
                    Double,
                    HashMap<
                        Integer,
                        HashMap<
                            Integer,
                            HashMap<
                                Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>>>>();

        // map of the tag first hits: score -> assumptions
        HashMap<Double, ArrayList<TagAssumption>> tagAssumptions =
            new HashMap<Double, ArrayList<TagAssumption>>();

        ArrayList<String> identifications = new ArrayList<String>();

        HashMap<Integer, HashMap<Double, ArrayList<SpectrumIdentificationAssumption>>> assumptions =
            identification.getAssumptions(spectrumKey);

        for (int searchEngine1 : assumptions.keySet()) {

          HashMap<Double, ArrayList<SpectrumIdentificationAssumption>> advocate1Map =
              assumptions.get(searchEngine1);

          double bestEvalue = Collections.min(advocate1Map.keySet());

          for (SpectrumIdentificationAssumption assumption1 : advocate1Map.get(bestEvalue)) {

            if (assumption1 instanceof PeptideAssumption) {

              PeptideAssumption peptideAssumption1 = (PeptideAssumption) assumption1;
              String id = peptideAssumption1.getPeptide().getKey();

              if (!identifications.contains(id)) {

                psParameter = (PSParameter) peptideAssumption1.getUrParam(psParameter);
                double p;

                if (multiSE && sequenceFactory.concatenatedTargetDecoy()) {
                  p = psParameter.getSearchEngineProbability();
                } else {
                  p = peptideAssumption1.getScore();
                }

                int nSE = 1;
                int proteinMax = 1;
                for (String protein :
                    peptideAssumption1
                        .getPeptide()
                        .getParentProteins(sequenceMatchingPreferences)) {
                  Integer tempCount = proteinCount.get(protein);
                  if (tempCount != null && tempCount > proteinMax) {
                    proteinMax = tempCount;
                  }
                }

                for (int searchEngine2 : assumptions.keySet()) {

                  if (searchEngine1 != searchEngine2) {

                    HashMap<Double, ArrayList<SpectrumIdentificationAssumption>> advocate2Map =
                        assumptions.get(searchEngine2);

                    boolean found = false;
                    ArrayList<Double> eValues2 = new ArrayList<Double>(advocate2Map.keySet());
                    Collections.sort(eValues2);

                    for (double eValue2 : eValues2) {
                      for (SpectrumIdentificationAssumption assumption2 :
                          advocate2Map.get(eValue2)) {

                        if (assumption2 instanceof PeptideAssumption) {

                          PeptideAssumption peptideAssumption2 = (PeptideAssumption) assumption2;

                          if (peptideAssumption1
                              .getPeptide()
                              .isSameSequenceAndModificationStatus(
                                  peptideAssumption2.getPeptide(), sequenceMatchingPreferences)) {
                            PSParameter psParameter2 =
                                (PSParameter) peptideAssumption2.getUrParam(psParameter);
                            p = p * psParameter2.getSearchEngineProbability();
                            nSE++;
                            found = true;
                            break;
                          }
                        }
                      }
                      if (found) {
                        break;
                      }
                    }
                  }
                }

                identifications.add(id);

                HashMap<
                        Integer,
                        HashMap<
                            Integer,
                            HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>>>
                    pMap = peptideAssumptions.get(p);
                if (pMap == null) {
                  pMap =
                      new HashMap<
                          Integer,
                          HashMap<
                              Integer,
                              HashMap<
                                  Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>>>(
                          advocate1Map.size());
                  peptideAssumptions.put(p, pMap);
                }

                HashMap<
                        Integer,
                        HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>>
                    proteinMaxMap = pMap.get(proteinMax);
                if (proteinMaxMap == null) {
                  proteinMaxMap =
                      new HashMap<
                          Integer,
                          HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>>(1);
                  pMap.put(proteinMax, proteinMaxMap);
                }

                HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>> nSeMap =
                    proteinMaxMap.get(nSE);
                if (nSeMap == null) {
                  nSeMap =
                      new HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>(1);
                  proteinMaxMap.put(nSE, nSeMap);
                  HashMap<Double, HashMap<String, PeptideAssumption>> coverageMap =
                      new HashMap<Double, HashMap<String, PeptideAssumption>>(1);
                  nSeMap.put(-1, coverageMap);
                  HashMap<String, PeptideAssumption> assumptionMap =
                      new HashMap<String, PeptideAssumption>(1);
                  coverageMap.put(-1.0, assumptionMap);
                  assumptionMap.put(
                      peptideAssumption1.getPeptide().getSequenceWithLowerCasePtms(),
                      peptideAssumption1);
                } else {
                  MSnSpectrum spectrum = (MSnSpectrum) spectrumFactory.getSpectrum(spectrumKey);

                  HashMap<Double, HashMap<String, PeptideAssumption>> coverageMap = nSeMap.get(-1);
                  if (coverageMap != null) {
                    HashMap<String, PeptideAssumption> assumptionMap = coverageMap.get(-1.0);
                    for (PeptideAssumption tempAssumption :
                        assumptionMap.values()) { // There should be only one
                      Peptide peptide = tempAssumption.getPeptide();
                      SpecificAnnotationSettings specificAnnotationPreferences =
                          annotationPreferences.getSpecificAnnotationPreferences(
                              spectrum.getSpectrumKey(),
                              tempAssumption,
                              identificationParameters.getSequenceMatchingPreferences(),
                              identificationParameters
                                  .getPtmScoringPreferences()
                                  .getSequenceMatchingPreferences());
                      HashMap<Integer, ArrayList<IonMatch>> coveredAminoAcids =
                          spectrumAnnotator.getCoveredAminoAcids(
                              annotationPreferences,
                              specificAnnotationPreferences,
                              (MSnSpectrum) spectrum,
                              peptide);
                      int nIons = coveredAminoAcids.size();
                      nSeMap.put(nIons, coverageMap);
                    }
                    nSeMap.remove(-1);
                  }

                  Peptide peptide = peptideAssumption1.getPeptide();
                  SpecificAnnotationSettings specificAnnotationPreferences =
                      annotationPreferences.getSpecificAnnotationPreferences(
                          spectrum.getSpectrumKey(),
                          peptideAssumption1,
                          identificationParameters.getSequenceMatchingPreferences(),
                          identificationParameters
                              .getPtmScoringPreferences()
                              .getSequenceMatchingPreferences());
                  HashMap<Integer, ArrayList<IonMatch>> coveredAminoAcids =
                      spectrumAnnotator.getCoveredAminoAcids(
                          annotationPreferences,
                          specificAnnotationPreferences,
                          (MSnSpectrum) spectrum,
                          peptide);
                  int nIons = coveredAminoAcids.size();

                  coverageMap = nSeMap.get(nIons);
                  if (coverageMap == null) {
                    coverageMap = new HashMap<Double, HashMap<String, PeptideAssumption>>(1);
                    HashMap<String, PeptideAssumption> assumptionMap =
                        new HashMap<String, PeptideAssumption>(1);
                    assumptionMap.put(
                        peptideAssumption1.getPeptide().getSequenceWithLowerCasePtms(),
                        peptideAssumption1);
                    coverageMap.put(-1.0, assumptionMap);
                    nSeMap.put(nIons, coverageMap);
                  } else {
                    HashMap<String, PeptideAssumption> assumptionMap = coverageMap.get(-1.0);
                    if (assumptionMap != null) {
                      for (PeptideAssumption tempAssumption :
                          assumptionMap.values()) { // There should be only one
                        double massError =
                            Math.abs(
                                tempAssumption.getDeltaMass(
                                    spectrum.getPrecursor().getMz(),
                                    shotgunProtocol.isMs1ResolutionPpm()));
                        coverageMap.put(massError, assumptionMap);
                      }
                      coverageMap.remove(-1.0);
                    }

                    double massError =
                        Math.abs(
                            peptideAssumption1.getDeltaMass(
                                spectrum.getPrecursor().getMz(),
                                shotgunProtocol.isMs1ResolutionPpm()));
                    assumptionMap = coverageMap.get(massError);
                    if (assumptionMap == null) {
                      assumptionMap = new HashMap<String, PeptideAssumption>(1);
                      coverageMap.put(massError, assumptionMap);
                    }
                    assumptionMap.put(
                        peptideAssumption1.getPeptide().getSequenceWithLowerCasePtms(),
                        peptideAssumption1);
                  }
                }
              }
            } else if (assumption1 instanceof TagAssumption) {
              TagAssumption tagAssumption = (TagAssumption) assumption1;
              ArrayList<TagAssumption> assumptionList = tagAssumptions.get(bestEvalue);
              if (assumptionList == null) {
                assumptionList = new ArrayList<TagAssumption>();
                tagAssumptions.put(bestEvalue, assumptionList);
              }
              assumptionList.add(tagAssumption);
            }
          }
        }

        SpectrumMatch spectrumMatch = new SpectrumMatch(spectrumKey);
        if (!peptideAssumptions.isEmpty()) {

          PeptideAssumption bestPeptideAssumption = null;
          ArrayList<Double> ps = new ArrayList<Double>(peptideAssumptions.keySet());
          Collections.sort(ps);
          double retainedP = 0;

          for (double p : ps) {

            retainedP = p;
            HashMap<
                    Integer,
                    HashMap<
                        Integer,
                        HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>>>
                pMap = peptideAssumptions.get(p);
            ArrayList<Integer> proteinMaxs = new ArrayList<Integer>(pMap.keySet());
            Collections.sort(proteinMaxs, Collections.reverseOrder());

            for (int proteinMax : proteinMaxs) {

              HashMap<
                      Integer,
                      HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>>>
                  proteinMaxMap = pMap.get(proteinMax);
              ArrayList<Integer> nSEs = new ArrayList<Integer>(proteinMaxMap.keySet());
              Collections.sort(nSEs, Collections.reverseOrder());

              for (int nSE : nSEs) {

                HashMap<Integer, HashMap<Double, HashMap<String, PeptideAssumption>>> nSeMap =
                    proteinMaxMap.get(nSE);
                ArrayList<Integer> coverages = new ArrayList<Integer>(nSeMap.keySet());
                Collections.sort(coverages, Collections.reverseOrder());

                for (Integer coverage : coverages) {

                  HashMap<Double, HashMap<String, PeptideAssumption>> coverageMap =
                      nSeMap.get(coverage);
                  ArrayList<Double> minErrors = new ArrayList<Double>(coverageMap.keySet());
                  Collections.sort(minErrors);

                  for (double minError : minErrors) {

                    HashMap<String, PeptideAssumption> bestPeptideAssumptions =
                        coverageMap.get(minError);
                    ArrayList<String> sequences =
                        new ArrayList<String>(bestPeptideAssumptions.keySet());
                    Collections.sort(sequences);

                    for (String sequence : sequences) {
                      PeptideAssumption peptideAssumption = bestPeptideAssumptions.get(sequence);
                      if (idFilter.validateProteins(
                          peptideAssumption.getPeptide(), sequenceMatchingPreferences)) {
                        bestPeptideAssumption = peptideAssumption;
                        break;
                      }
                    }
                    if (bestPeptideAssumption != null) {
                      break;
                    }
                  }
                  if (bestPeptideAssumption != null) {
                    break;
                  }
                }
                if (bestPeptideAssumption != null) {
                  break;
                }
              }
              if (bestPeptideAssumption != null) {
                break;
              }
            }
            if (bestPeptideAssumption != null) {
              break;
            }
          }
          if (bestPeptideAssumption != null) {

            if (multiSE) {

              // try to find the most likely modification localization based on the search engine
              // results
              HashMap<PeptideAssumption, ArrayList<Double>> assumptionPEPs =
                  new HashMap<PeptideAssumption, ArrayList<Double>>();
              String bestAssumptionKey =
                  bestPeptideAssumption.getPeptide().getMatchingKey(sequenceMatchingPreferences);

              for (int searchEngine : assumptions.keySet()) {

                boolean found = false;
                HashMap<Double, ArrayList<SpectrumIdentificationAssumption>> advocateMap =
                    assumptions.get(searchEngine);
                ArrayList<Double> eValues = new ArrayList<Double>(advocateMap.keySet());
                Collections.sort(eValues);

                for (double eValue : eValues) {
                  for (SpectrumIdentificationAssumption assumption : advocateMap.get(eValue)) {

                    if (assumption instanceof PeptideAssumption) {

                      PeptideAssumption peptideAssumption = (PeptideAssumption) assumption;

                      if (peptideAssumption
                          .getPeptide()
                          .getMatchingKey(sequenceMatchingPreferences)
                          .equals(bestAssumptionKey)) {

                        found = true;
                        boolean found2 = false;

                        for (PeptideAssumption assumption1 : assumptionPEPs.keySet()) {
                          if (assumption1
                              .getPeptide()
                              .sameModificationsAs(peptideAssumption.getPeptide())) {
                            found2 = true;
                            psParameter = (PSParameter) assumption.getUrParam(psParameter);
                            ArrayList<Double> peps = assumptionPEPs.get(assumption1);
                            peps.add(psParameter.getSearchEngineProbability());
                            break;
                          }
                        }

                        if (!found2) {
                          ArrayList<Double> peps = new ArrayList<Double>(1);
                          assumptionPEPs.put(peptideAssumption, peps);
                          psParameter = (PSParameter) assumption.getUrParam(psParameter);
                          peps.add(psParameter.getSearchEngineProbability());
                        }
                      }
                    }
                  }

                  if (found) {
                    break;
                  }
                }
              }

              Double bestSeP = null;
              int nSe = -1;

              for (PeptideAssumption peptideAssumption : assumptionPEPs.keySet()) {

                ArrayList<Double> peps = assumptionPEPs.get(peptideAssumption);
                Double sep = Collections.min(peps);

                if (bestSeP == null || bestSeP > sep) {
                  bestSeP = sep;
                  nSe = peps.size();
                  bestPeptideAssumption = peptideAssumption;
                } else if (peps.size() > nSe) {
                  if (sep != null && (Math.abs(sep - bestSeP) <= 1e-10)) {
                    nSe = peps.size();
                    bestPeptideAssumption = peptideAssumption;
                  }
                }
              }
            }

            // create a PeptideShaker match based on the best search engine match
            Peptide sePeptide = bestPeptideAssumption.getPeptide();
            ArrayList<String> psProteins =
                new ArrayList<String>(sePeptide.getParentProteins(sequenceMatchingPreferences));
            ArrayList<ModificationMatch> psModificationMatches = null;
            if (sePeptide.isModified()) {
              psModificationMatches =
                  new ArrayList<ModificationMatch>(sePeptide.getNModifications());
              for (ModificationMatch seModMatch : sePeptide.getModificationMatches()) {
                psModificationMatches.add(
                    new ModificationMatch(
                        seModMatch.getTheoreticPtm(),
                        seModMatch.isVariable(),
                        seModMatch.getModificationSite()));
              }
            }

            Peptide psPeptide = new Peptide(sePeptide.getSequence(), psModificationMatches);
            psPeptide.setParentProteins(psProteins);
            PeptideAssumption psAssumption =
                new PeptideAssumption(
                    psPeptide,
                    1,
                    Advocate.peptideShaker.getIndex(),
                    bestPeptideAssumption.getIdentificationCharge(),
                    retainedP);

            spectrumMatch.setBestPeptideAssumption(psAssumption);

            if (orderedPsmMap != null) {
              String peptideKey = psPeptide.getMatchingKey(sequenceMatchingPreferences);
              ArrayList<String> spectrumKeys = keysMap.get(peptideKey);
              if (spectrumKeys == null) {
                spectrumKeys = new ArrayList<String>();
                keysMap.put(peptideKey, spectrumKeys);
              }
              spectrumKeys.add(spectrumKey);
            }

            psParameter = new PSParameter();
            psParameter.setSpectrumProbabilityScore(retainedP);

            PSParameter matchParameter =
                (PSParameter) bestPeptideAssumption.getUrParam(psParameter);
            psParameter.setSearchEngineProbability(matchParameter.getSearchEngineProbability());
            psParameter.setAlgorithmDeltaPEP(matchParameter.getAlgorithmDeltaPEP());
            psParameter.setDeltaPEP(matchParameter.getDeltaPEP());

            matchesValidator
                .getPsmMap()
                .addPoint(
                    psParameter.getPsmProbabilityScore(),
                    spectrumMatch,
                    sequenceMatchingPreferences);
            psParameter.setSpecificMapKey(
                spectrumMatch.getBestPeptideAssumption().getIdentificationCharge().value + "");
            identification.addSpectrumMatchParameter(spectrumKey, psParameter);
            identification.updateSpectrumMatch(spectrumMatch);
          }
        }
        if (!tagAssumptions.isEmpty()) {
          ArrayList<Double> evalues = new ArrayList<Double>(tagAssumptions.keySet());
          Double bestEvalue = Collections.min(evalues);
          TagAssumption bestAssumption = tagAssumptions.get(bestEvalue).get(0);
          spectrumMatch.setBestTagAssumption(bestAssumption);
          identification.updateSpectrumMatch(spectrumMatch);
          if (spectrumMatch.getBestPeptideAssumption() == null) {
            psParameter = new PSParameter();
            if (!multiSE) {
              psParameter.setSpectrumProbabilityScore(bestEvalue);
            }
            PSParameter matchParameter = (PSParameter) bestAssumption.getUrParam(psParameter);
            psParameter.setSearchEngineProbability(matchParameter.getSearchEngineProbability());
            psParameter.setAlgorithmDeltaPEP(matchParameter.getAlgorithmDeltaPEP());
            psParameter.setDeltaPEP(matchParameter.getDeltaPEP());
            psParameter.setSpecificMapKey(
                spectrumMatch.getBestTagAssumption().getIdentificationCharge().value + "");
            identification.addSpectrumMatchParameter(spectrumKey, psParameter);
          }
        }
        waitingHandler.increaseSecondaryProgressCounter();
        if (waitingHandler.isRunCanceled()) {
          return;
        }
      }

      if (orderedPsmMap != null) {
        ArrayList<String> orderedKeys =
            new ArrayList<String>(
                identification.getSpectrumIdentification(spectrumFileName).size());
        for (ArrayList<String> keys : keysMap.values()) {
          orderedKeys.addAll(keys);
        }
        orderedPsmMap.put(spectrumFileName, orderedKeys);

        if (MemoryConsumptionStatus.memoryUsed() > 0.9) {
          orderedPsmMap = null;
        }
      }
    }

    if (orderedPsmMap != null) {
      metrics.setOrderedSpectrumKeys(orderedPsmMap);
    }

    // the protein count map is no longer needed
    proteinCount.clear();

    waitingHandler.setSecondaryProgressCounterIndeterminate(true);
  }

  /**
   * Selects a first hit in a list of equally scoring peptide matches. The selection is made based
   * on: 1 - The occurrence of the protein detection as given in the proteinCount map 2 - The
   * sequence coverage by fragment ions 3 - The precursor mass error.
   *
   * <p>If no best hit is found, the first one sorted alphabetically is retained.
   *
   * @param spectrumKey the key of the spectrum
   * @param firstHits list of equally scoring peptide matches
   * @param proteinCount map of the number of peptides for every protein
   * @param sequenceMatchingPreferences the sequence matching preferences
   * @param shotgunProtocol the shotgun protocol
   * @param identificationParameters the identification parameters
   * @param spectrumAnnotator the spectrum annotator to use
   * @return a first hit from the list of equally scoring peptide matches
   * @throws IOException exception thrown whenever an IO exception occurred while remapping the
   *     proteins or getting the spectrum
   * @throws InterruptedException exception thrown whenever an interrupted exception occurred while
   *     remapping the proteins or getting the spectrum
   * @throws SQLException exception thrown whenever an SQL exception occurred while interacting with
   *     the protein tree
   * @throws ClassNotFoundException exception thrown whenever an exception occurred while
   *     deserializing an object
   * @throws MzMLUnmarshallerException exception thrown whenever an exception occurred while reading
   *     an mzML file
   */
  public static PeptideAssumption getBestHit(
      String spectrumKey,
      ArrayList<PeptideAssumption> firstHits,
      HashMap<String, Integer> proteinCount,
      SequenceMatchingPreferences sequenceMatchingPreferences,
      ShotgunProtocol shotgunProtocol,
      IdentificationParameters identificationParameters,
      PeptideSpectrumAnnotator spectrumAnnotator)
      throws IOException, InterruptedException, SQLException, ClassNotFoundException,
          MzMLUnmarshallerException {

    if (firstHits.size() == 1) {
      return firstHits.get(0);
    }

    Integer maxProteins = 0;
    ArrayList<PeptideAssumption> bestPeptideAssumptions =
        new ArrayList<PeptideAssumption>(firstHits.size());

    for (PeptideAssumption peptideAssumption : firstHits) {
      for (String accession :
          peptideAssumption.getPeptide().getParentProteins(sequenceMatchingPreferences)) {
        Integer count = proteinCount.get(accession);
        if (count != null) {
          if (count > maxProteins) {
            maxProteins = count;
            bestPeptideAssumptions.clear();
            bestPeptideAssumptions.add(peptideAssumption);
          } else if (count.equals(maxProteins)) {
            bestPeptideAssumptions.add(peptideAssumption);
          }
        }
      }
    }

    if (bestPeptideAssumptions.size() == 1) {
      return bestPeptideAssumptions.get(0);
    } else if (!bestPeptideAssumptions.isEmpty()) {
      firstHits = bestPeptideAssumptions;
      bestPeptideAssumptions = new ArrayList<PeptideAssumption>(firstHits.size());
    }

    MSnSpectrum spectrum = (MSnSpectrum) SpectrumFactory.getInstance().getSpectrum(spectrumKey);
    int maxCoveredAminoAcids = 0;
    AnnotationSettings annotationPreferences = identificationParameters.getAnnotationPreferences();

    for (PeptideAssumption peptideAssumption : firstHits) {
      Peptide peptide = peptideAssumption.getPeptide();
      SpecificAnnotationSettings specificAnnotationPreferences =
          annotationPreferences.getSpecificAnnotationPreferences(
              spectrum.getSpectrumKey(),
              peptideAssumption,
              identificationParameters.getSequenceMatchingPreferences(),
              identificationParameters.getPtmScoringPreferences().getSequenceMatchingPreferences());
      HashMap<Integer, ArrayList<IonMatch>> coveredAminoAcids =
          spectrumAnnotator.getCoveredAminoAcids(
              annotationPreferences,
              specificAnnotationPreferences,
              (MSnSpectrum) spectrum,
              peptide);
      int nAas = coveredAminoAcids.size();
      if (nAas > maxCoveredAminoAcids) {
        maxCoveredAminoAcids = nAas;
        bestPeptideAssumptions.clear();
        bestPeptideAssumptions.add(peptideAssumption);
      } else if (nAas == maxCoveredAminoAcids) {
        bestPeptideAssumptions.add(peptideAssumption);
      }
    }

    if (bestPeptideAssumptions.size() == 1) {
      return bestPeptideAssumptions.get(0);
    } else if (!bestPeptideAssumptions.isEmpty()) {
      firstHits = bestPeptideAssumptions;
      bestPeptideAssumptions = new ArrayList<PeptideAssumption>(firstHits.size());
    }

    double minMassError = identificationParameters.getPeptideAssumptionFilter().getMaxMzDeviation();
    if (minMassError == -1.0) {
      minMassError = identificationParameters.getSearchParameters().getPrecursorAccuracy();
    }

    for (PeptideAssumption peptideAssumption : firstHits) {
      double massError =
          Math.abs(
              peptideAssumption.getDeltaMass(
                  spectrum.getPrecursor().getMz(), shotgunProtocol.isMs1ResolutionPpm()));
      if (massError < minMassError) {
        minMassError = massError;
        bestPeptideAssumptions.clear();
        bestPeptideAssumptions.add(peptideAssumption);
      } else if (massError == minMassError) {
        bestPeptideAssumptions.add(peptideAssumption);
      }
    }

    if (bestPeptideAssumptions.size() == 1) {
      return bestPeptideAssumptions.get(0);
    } else if (bestPeptideAssumptions.isEmpty()) {
      bestPeptideAssumptions = firstHits;
    }

    HashMap<String, PeptideAssumption> sequenceToPeptideAssumptionsMap =
        new HashMap<String, PeptideAssumption>(bestPeptideAssumptions.size());
    for (PeptideAssumption peptideAssumption : bestPeptideAssumptions) {
      sequenceToPeptideAssumptionsMap.put(
          peptideAssumption.getPeptide().getSequence(), peptideAssumption);
    }

    ArrayList<String> sequences = new ArrayList<String>(sequenceToPeptideAssumptionsMap.keySet());
    Collections.sort(sequences);
    return sequenceToPeptideAssumptionsMap.get(sequences.get(0));
  }
}
public class PSFileImporter {

  private File currentPSFile;
  private EnzymeFactory enzymeFactory = EnzymeFactory.getInstance();
  private String resource;
  /** The spectrum annotator. */
  private SpectrumAnnotator spectrumAnnotator = new SpectrumAnnotator();
  /** The project details. */
  private ProjectDetails projectDetails = null;
  /** The spectrum factory. */
  private SpectrumFactory spectrumFactory = SpectrumFactory.getInstance(100);
  /** The identification to display. */
  private Identification identification;
  /** The compomics PTM factory. */
  private PTMFactory ptmFactory = PTMFactory.getInstance();
  /** The parameters of the search. */
  private SearchParameters searchParameters = new SearchParameters();
  /** The initial processing preferences */
  private ProcessingPreferences processingPreferences = new ProcessingPreferences();
  /** The annotation preferences. */
  private AnnotationPreferences annotationPreferences = new AnnotationPreferences();
  /** The spectrum counting preferences. */
  private SpectrumCountingPreferences spectrumCountingPreferences =
      new SpectrumCountingPreferences();
  /** The PTM scoring preferences */
  private PTMScoringPreferences ptmScoringPreferences = new PTMScoringPreferences();
  /** The identification filter used for this project. */
  private IdFilter idFilter = new IdFilter();

  /** The actually identified modifications. */
  /**
   * Returns the modifications found in this project.
   *
   * @return the modifications found in this project
   */
  public ArrayList<String> getFoundModifications() {
    if (identifiedModifications == null) {
      identifiedModifications = new ArrayList<String>();
      for (String peptideKey : identification.getPeptideIdentification()) {

        boolean modified = false;

        for (String modificationName : Peptide.getModificationFamily(peptideKey)) {
          if (!identifiedModifications.contains(modificationName)) {
            identifiedModifications.add(modificationName);
            modified = true;
          }
        }
        if (!modified && !identifiedModifications.contains(PtmPanel.NO_MODIFICATION)) {
          identifiedModifications.add(PtmPanel.NO_MODIFICATION);
        }
      }
    }
    return identifiedModifications;
  }

  private ArrayList<String> identifiedModifications = null;
  /** Metrics picked-up while loading the files. */
  private Metrics metrics;
  /** The display preferences. */
  private DisplayPreferences displayPreferences = new DisplayPreferences();
  /** The sequence factory. */
  private SequenceFactory sequenceFactory = SequenceFactory.getInstance(30000);
  /** The filter preferences. */
  private FilterPreferences filterPreferences = new FilterPreferences();
  /** The compomics experiment. */
  private MsExperiment experiment = null;
  /** The investigated sample. */
  private Sample sample;
  /** The replicate number. */
  private int replicateNumber;
  /** The class used to provide sexy features out of the identification. */
  private IdentificationFeaturesGenerator identificationFeaturesGenerator;
  /** The last folder opened by the user. Defaults to user.home. */
  private String lastSelectedFolder = "user.home";
  /** The object cache used for the identification database. */
  private ObjectsCache objectsCache;

  private com.compomics.util.experiment.ProteomicAnalysis proteomicAnalysis;
  private ProgressDialogX progressDialog;
  private javax.swing.JProgressBar jprog;

  public PSFileImporter(javax.swing.JProgressBar jprog) {
    this.progressDialog = new ProgressDialogX(false);
    this.jprog = jprog;
  }

  public void importPeptideShakerFile(File aPsFile, final String resource) {

    this.resource = resource;
    this.currentPSFile = aPsFile;
    loadGeneMapping();
    loadEnzymes();
    resetPtmFactory();
    // setDefaultPreferences(); // @TODO: i tried re-adding this but then we get a null pointer, but
    // the two below have to be added or the default neutral losses won't appear
    IonFactory.getInstance().addDefaultNeutralLoss(NeutralLoss.H2O);
    IonFactory.getInstance().addDefaultNeutralLoss(NeutralLoss.NH3);

    // exceptionHandler = new ExceptionHandler(this);

    new Thread("ProgressThread") {
      @Override
      public void run() {
        jprog.setValue(10);
      }
    }.start();

    Thread importThread =
        new Thread("ImportThread") {
          @Override
          public void run() {
            try {
              // reset enzymes, ptms and preferences
              loadEnzymes();
              resetPtmFactory();
              setDefaultPreferences();
              try {
                // close any open connection to an identification database
                if (identification != null) {
                  identification.close();
                }
              } catch (Exception e) {
                e.printStackTrace();
              }
              File experimentFile =
                  new File(
                      PeptideShaker.SERIALIZATION_DIRECTORY, PeptideShaker.experimentObjectName);
              File matchFolder = new File(PeptideShaker.SERIALIZATION_DIRECTORY);
              // empty the existing files in the matches folder
              if (matchFolder.exists()) {
                for (File file : matchFolder.listFiles()) {
                  if (file.isDirectory()) {
                    boolean deleted = Util.deleteDir(file);

                    if (!deleted) {
                      System.out.println("Failed to delete folder: " + file.getPath());
                    }
                  } else {
                    boolean deleted = file.delete();

                    if (!deleted) {
                      System.out.println("Failed to delete file: " + file.getPath());
                    }
                  }
                }
              }
              final int BUFFER = 2048;
              byte data[] = new byte[BUFFER];
              FileInputStream fi = new FileInputStream(currentPSFile);
              BufferedInputStream bis = new BufferedInputStream(fi, BUFFER);
              try {
                ArchiveInputStream tarInput =
                    new ArchiveStreamFactory().createArchiveInputStream(bis);
                ArchiveEntry archiveEntry;

                while ((archiveEntry = tarInput.getNextEntry()) != null) {
                  File destinationFile = new File(archiveEntry.getName());
                  File destinationFolder = destinationFile.getParentFile();
                  boolean destFolderExists = true;
                  if (!destinationFolder.exists()) {
                    destFolderExists = destinationFolder.mkdirs();
                  }
                  if (destFolderExists) {
                    FileOutputStream fos = new FileOutputStream(destinationFile);
                    BufferedOutputStream bos = new BufferedOutputStream(fos);
                    int count;
                    while ((count = tarInput.read(data, 0, BUFFER)) != -1
                        && !progressDialog.isRunCanceled()) {
                      bos.write(data, 0, count);
                    }

                    bos.close();
                    fos.close();

                    //	                                int progress = (int) (100 *
                    // tarInput.getBytesRead() / fileLength);
                    //	                               progressDialog.setValue(progress);
                  } else {
                    System.out.println(
                        "Folder does not exist: \'"
                            + destinationFolder.getAbsolutePath()
                            + "\'. User preferences not saved.");
                  }
                }
                tarInput.close();
              } catch (ArchiveException e) {
                // Most likely an old project
                experimentFile = currentPSFile;
                e.printStackTrace();
              }
              fi.close();
              bis.close();
              fi.close();

              MsExperiment tempExperiment = ExperimentIO.loadExperiment(experimentFile);
              Sample tempSample = null;
              PeptideShakerSettings experimentSettings = new PeptideShakerSettings();
              if (tempExperiment.getUrParam(experimentSettings) instanceof PSSettings) {
                // convert old settings files using utilities version 3.10.68 or older
                // convert the old ProcessingPreferences object
                PSSettings tempSettings =
                    (PSSettings) tempExperiment.getUrParam(experimentSettings);
                ProcessingPreferences tempProcessingPreferences = new ProcessingPreferences();
                tempProcessingPreferences.setProteinFDR(
                    tempSettings.getProcessingPreferences().getProteinFDR());
                tempProcessingPreferences.setPeptideFDR(
                    tempSettings.getProcessingPreferences().getPeptideFDR());
                tempProcessingPreferences.setPsmFDR(
                    tempSettings.getProcessingPreferences().getPsmFDR());
                // convert the old PTMScoringPreferences object
                PTMScoringPreferences tempPTMScoringPreferences = new PTMScoringPreferences();
                tempPTMScoringPreferences.setaScoreCalculation(
                    tempSettings.getPTMScoringPreferences().aScoreCalculation());
                tempPTMScoringPreferences.setaScoreNeutralLosses(
                    tempSettings.getPTMScoringPreferences().isaScoreNeutralLosses());
                tempPTMScoringPreferences.setFlrThreshold(
                    tempSettings.getPTMScoringPreferences().getFlrThreshold());
                // missing gene refrences
                GenePreferences genePreferences = getGenePreferences();
                //     String selectedSpecies = genePreferences.getCurrentSpecies();
                //    String speciesDatabase =
                // genePreferences.getEnsemblDatabaseName(selectedSpecies);

                experimentSettings =
                    new PeptideShakerSettings(
                        tempSettings.getSearchParameters(),
                        tempSettings.getAnnotationPreferences(),
                        tempSettings.getSpectrumCountingPreferences(),
                        tempSettings.getProjectDetails(),
                        tempSettings.getFilterPreferences(),
                        tempSettings.getDisplayPreferences(),
                        tempSettings.getMetrics(),
                        tempProcessingPreferences,
                        tempSettings.getIdentificationFeaturesCache(),
                        tempPTMScoringPreferences,
                        genePreferences,
                        new IdFilter());
                ;
              } else {
                experimentSettings =
                    (PeptideShakerSettings) tempExperiment.getUrParam(experimentSettings);
              }

              idFilter = experimentSettings.getIdFilter();
              setAnnotationPreferences(experimentSettings.getAnnotationPreferences());
              setSpectrumCountingPreferences(experimentSettings.getSpectrumCountingPreferences());
              setPtmScoringPreferences(experimentSettings.getPTMScoringPreferences());
              setProjectDetails(experimentSettings.getProjectDetails());
              setSearchParameters(experimentSettings.getSearchParameters());
              setProcessingPreferences(experimentSettings.getProcessingPreferences());
              setMetrics(experimentSettings.getMetrics());
              setDisplayPreferences(experimentSettings.getDisplayPreferences());

              if (experimentSettings.getFilterPreferences() != null) {
                setFilterPreferences(experimentSettings.getFilterPreferences());
              } else {
                setFilterPreferences(new FilterPreferences());
              }
              if (experimentSettings.getDisplayPreferences() != null) {
                setDisplayPreferences(experimentSettings.getDisplayPreferences());
                displayPreferences.compatibilityCheck(searchParameters.getModificationProfile());
              } else {
                setDisplayPreferences(new DisplayPreferences());
                displayPreferences.setDefaultSelection(searchParameters.getModificationProfile());
              }
              ArrayList<Sample> samples = new ArrayList(tempExperiment.getSamples().values());

              if (samples.size() == 1) {
                tempSample = samples.get(0);
              } else {
                tempSample = samples.get(0);
                String[] sampleNames = new String[samples.size()];
                for (int cpt = 0; cpt < sampleNames.length; cpt++) {
                  sampleNames[cpt] = samples.get(cpt).getReference();
                  System.out.println(sampleNames[cpt]);
                }
                SampleSelection sampleSelection =
                    new SampleSelection(null, true, sampleNames, "sample");
                sampleSelection.setVisible(false);
                String choice = sampleSelection.getChoice();
                for (Sample sampleTemp : samples) {
                  if (sampleTemp.getReference().equals(choice)) {
                    tempSample = sampleTemp;
                    break;
                  }
                }
              }

              ArrayList<Integer> replicates =
                  new ArrayList(tempExperiment.getAnalysisSet(tempSample).getReplicateNumberList());

              System.out.println(replicates);
              int tempReplicate;

              if (replicates.size() == 1) {
                tempReplicate = replicates.get(0);
              } else {
                String[] replicateNames = new String[replicates.size()];
                for (int cpt = 0; cpt < replicateNames.length; cpt++) {
                  replicateNames[cpt] = samples.get(cpt).getReference();
                }
                SampleSelection sampleSelection =
                    new SampleSelection(null, true, replicateNames, "replicate");
                sampleSelection.setVisible(false);
                Integer choice = new Integer(sampleSelection.getChoice());
                tempReplicate = 0;
              }

              setProject(tempExperiment, tempSample, tempReplicate);

              identificationFeaturesGenerator =
                  new IdentificationFeaturesGenerator(
                      identification,
                      searchParameters,
                      idFilter,
                      metrics,
                      spectrumCountingPreferences);
              if (experimentSettings.getIdentificationFeaturesCache() != null) {
                identificationFeaturesGenerator.setIdentificationFeaturesCache(
                    experimentSettings.getIdentificationFeaturesCache());
              }

              //	                    mainProgressDialog.setTitle("Loading FASTA File. Please
              // Wait...");

              try {
                File providedFastaLocation =
                    experimentSettings.getSearchParameters().getFastaFile();
                String fileName = providedFastaLocation.getName();
                File projectFolder = currentPSFile.getParentFile();
                File dataFolder = new File(projectFolder, "data");

                // try to locate the FASTA file
                if (providedFastaLocation.exists()) {
                  SequenceFactory.getInstance().loadFastaFile(providedFastaLocation);
                } else if (new File(projectFolder, fileName).exists()) {
                  SequenceFactory.getInstance().loadFastaFile(new File(projectFolder, fileName));
                  experimentSettings
                      .getSearchParameters()
                      .setFastaFile(new File(projectFolder, fileName));
                } else if (new File(dataFolder, fileName).exists()) {
                  SequenceFactory.getInstance().loadFastaFile(new File(dataFolder, fileName));
                  experimentSettings
                      .getSearchParameters()
                      .setFastaFile(new File(dataFolder, fileName));
                } else {
                  // return error

                  System.out.println("fastafile is missing");
                }
              } catch (Exception e) {
                e.printStackTrace();
                System.out.println("fastafile is missing");
              }

              //	                 mainProgressDialog.setTitle("Locating Spectrum Files. Please
              // Wait...");

              for (String spectrumFileName : identification.getSpectrumFiles()) {

                try {
                  File providedSpectrumLocation = projectDetails.getSpectrumFile(spectrumFileName);
                  // try to locate the spectrum file
                  if (providedSpectrumLocation == null || !providedSpectrumLocation.exists()) {
                    File projectFolder = currentPSFile.getParentFile();
                    File fileInProjectFolder = new File(projectFolder, spectrumFileName);
                    File dataFolder = new File(projectFolder, "data");
                    File fileInDataFolder = new File(dataFolder, spectrumFileName);
                    File fileInLastSelectedFolder =
                        new File(getLastSelectedFolder(), spectrumFileName);
                    if (fileInProjectFolder.exists()) {
                      projectDetails.addSpectrumFile(fileInProjectFolder);
                    } else if (fileInDataFolder.exists()) {
                      projectDetails.addSpectrumFile(fileInDataFolder);
                    } else if (fileInLastSelectedFolder.exists()) {
                      projectDetails.addSpectrumFile(fileInLastSelectedFolder);
                    } else {

                      System.out.println("error no file");
                    }
                  }
                } catch (Exception e) {
                  clearData(true);
                  // clearPreferences();
                  e.printStackTrace();
                  System.out.println("error no file");
                  return;
                }
              }

              objectsCache = new ObjectsCache();
              objectsCache.setAutomatedMemoryManagement(true);

              if (identification.isDB()) {
                try {
                  String dbFolder =
                      new File(resource, PeptideShaker.SERIALIZATION_DIRECTORY).getAbsolutePath();
                  identification.establishConnection(dbFolder, false, objectsCache);
                } catch (Exception e) {
                  e.printStackTrace();
                }
              } else {
                updateAnnotationPreferencesFromSearchSettings();
                annotationPreferences.useAutomaticAnnotation(true);
              }

              int cpt = 1, nfiles = identification.getSpectrumFiles().size();
              for (String fileName : identification.getSpectrumFiles()) {

                //                             mainProgressDialog.setTitle("Importing Spectrum
                // Files. Please Wait...");
                try {
                  File mgfFile = projectDetails.getSpectrumFile(fileName);
                  spectrumFactory.addSpectra(mgfFile, progressDialog);
                } catch (Exception e) {
                  clearData(true);
                  e.printStackTrace();
                  return;
                }
              }
              boolean compatibilityIssue =
                  getSearchParameters().getIonSearched1() == null
                      || getSearchParameters().getIonSearched2() == null;

              if (compatibilityIssue) {
                JOptionPane.showMessageDialog(
                    null,
                    "The annotation preferences for this project may have changed.\n\n"
                        + "Note that PeptideShaker has substancially improved, we strongly\n"
                        + "recommend reprocessing your identification files.",
                    "Annotation Preferences",
                    JOptionPane.INFORMATION_MESSAGE);
                updateAnnotationPreferencesFromSearchSettings();
              }

              if (identification.getSpectrumIdentificationMap() == null) {
                // 0.18 version, needs update of the spectrum mapping
                identification.updateSpectrumMapping();
              }
            } catch (OutOfMemoryError error) {
              System.out.println(
                  "Ran out of memory! (runtime.maxMemory(): "
                      + Runtime.getRuntime().maxMemory()
                      + ")");
              Runtime.getRuntime().gc();
              JOptionPane.showMessageDialog(
                  null,
                  "The task used up all the available memory and had to be stopped.\n"
                      + "Memory boundaries are set in ../resources/conf/JavaOptions.txt.",
                  "Out Of Memory Error",
                  JOptionPane.ERROR_MESSAGE);
              error.printStackTrace();
            } catch (Exception exp) {
              exp.printStackTrace();
            }
          }
        };
    importThread.setPriority(Thread.MAX_PRIORITY);
    //        importThread.start();
    //        while (importThread.isAlive()) {
    //            try {
    //                Thread.currentThread().sleep(100);
    //
    //            } catch (Exception e) {
    //                e.printStackTrace();
    //            }
    //        }
    ExecutorService es = Executors.newCachedThreadPool();
    es.execute(importThread);
    es.shutdown();
    try {
      boolean finshed = es.awaitTermination(1, TimeUnit.DAYS);
      System.gc();
      return;

      //        t.start();
    } catch (InterruptedException ex) {
      System.err.println(ex.getMessage());
      // Logger.getLogger(UpdatedOutputGenerator.class.getName()).log(Level.SEVERE, null, ex);
    }
    System.gc();
    //        return;

  }

  /** Loads the enzymes from the enzyme file into the enzyme factory. */
  private void loadEnzymes() {
    try {
      enzymeFactory.importEnzymes(new File(resource, PeptideShaker.ENZYME_FILE));
    } catch (Exception e) {
      System.out.println("Not able to load the enzyme file." + "Wrong enzyme file.");
      e.printStackTrace();
    }
  }

  /** Loads the modifications from the modification file. */
  public void resetPtmFactory() {
    // reset ptm factory
    ptmFactory.reloadFactory();
    ptmFactory = PTMFactory.getInstance();
    try {
      ptmFactory.importModifications(new File(resource, PeptideShaker.MODIFICATIONS_FILE), false);
    } catch (Exception e) {
      e.printStackTrace();
    }

    try {
      ptmFactory.importModifications(
          new File(resource, PeptideShaker.USER_MODIFICATIONS_FILE), true);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  /** Set the default preferences. */
  private void setDefaultPreferences() {
    searchParameters = new SearchParameters();
    annotationPreferences.setAnnotationLevel(0.75);
    annotationPreferences.useAutomaticAnnotation(true);
    spectrumCountingPreferences.setSelectedMethod(SpectralCountingMethod.NSAF);
    spectrumCountingPreferences.setValidatedHits(true);
    IonFactory.getInstance().addDefaultNeutralLoss(NeutralLoss.NH3);
    IonFactory.getInstance().addDefaultNeutralLoss(NeutralLoss.H2O);
    processingPreferences = new ProcessingPreferences();
    ptmScoringPreferences = new PTMScoringPreferences();
  }

  /** Imports the gene mapping. */
  private void loadGeneMapping() {
    try {
      geneFactory.initialize(new File(resource, GENE_MAPPING_PATH), null);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  /** The path to the gene mapping file. */
  private final String GENE_MAPPING_PATH = "/resources/conf/gene_ontology/gene_details_human";
  /** The gene factory. */
  private GeneFactory geneFactory = GeneFactory.getInstance();

  /**
   * Updates the new annotation preferences.
   *
   * @param annotationPreferences the new annotation preferences
   */
  public void setAnnotationPreferences(AnnotationPreferences annotationPreferences) {
    this.annotationPreferences = annotationPreferences;
  }

  /**
   * Sets new spectrum counting preferences.
   *
   * @param spectrumCountingPreferences new spectrum counting preferences
   */
  public void setSpectrumCountingPreferences(
      SpectrumCountingPreferences spectrumCountingPreferences) {
    this.spectrumCountingPreferences = spectrumCountingPreferences;
  }

  /**
   * Sets the PTM scoring preferences
   *
   * @param ptmScoringPreferences the PTM scoring preferences
   */
  public void setPtmScoringPreferences(PTMScoringPreferences ptmScoringPreferences) {
    this.ptmScoringPreferences = ptmScoringPreferences;
  }

  /**
   * Sets the project details.
   *
   * @param projectDetails the project details
   */
  public void setProjectDetails(ProjectDetails projectDetails) {
    this.projectDetails = projectDetails;
  }

  /**
   * Updates the search parameters.
   *
   * @param searchParameters the new search parameters
   */
  public void setSearchParameters(SearchParameters searchParameters) {
    this.searchParameters = searchParameters;
    PeptideShaker.loadModifications(searchParameters);
  }

  /**
   * Sets the initial processing preferences.
   *
   * @param processingPreferences the initial processing preferences
   */
  public void setProcessingPreferences(ProcessingPreferences processingPreferences) {
    this.processingPreferences = processingPreferences;
  }

  /**
   * Sets the metrics saved while loading the files.
   *
   * @param metrics the metrics saved while loading the files
   */
  public void setMetrics(Metrics metrics) {
    this.metrics = metrics;
  }

  /**
   * Sets the display preferences to use.
   *
   * @param displayPreferences the display preferences to use
   */
  public void setDisplayPreferences(DisplayPreferences displayPreferences) {
    this.displayPreferences = displayPreferences;
  }
  /**
   * Sets the gui filter preferences to use. .\
   *
   * @param filterPreferences the gui filter preferences to use
   */
  public void setFilterPreferences(FilterPreferences filterPreferences) {
    this.filterPreferences = filterPreferences;
  }
  /**
   * This method sets the information of the project when opened.
   *
   * @param experiment the experiment conducted
   * @param sample The sample analyzed
   * @param replicateNumber The replicate number
   */
  public void setProject(MsExperiment experiment, Sample sample, int replicateNumber) {
    this.experiment = experiment;
    this.sample = sample;
    this.replicateNumber = replicateNumber;
    ProteomicAnalysis proteomic_Analysis =
        experiment.getAnalysisSet(sample).getProteomicAnalysis(replicateNumber);
    identification = proteomic_Analysis.getIdentification(IdentificationMethod.MS2_IDENTIFICATION);
  }

  /**
   * Returns the last selected folder.
   *
   * @return the last selected folder
   */
  public String getLastSelectedFolder() {
    return lastSelectedFolder;
  }

  /**
   * Set the last selected folder.
   *
   * @param lastSelectedFolder the folder to set
   */
  public void setLastSelectedFolder(String lastSelectedFolder) {
    this.lastSelectedFolder = lastSelectedFolder;
  }

  /**
   * Returns the identification displayed.
   *
   * @return the identification displayed
   */
  public com.compomics.util.experiment.identification.Identification getIdentification() {
    return identification;
  }

  /**
   * Returns the identification features generator.
   *
   * @return the identification features generator
   */
  public IdentificationFeaturesGenerator getIdentificationFeaturesGenerator() {
    return identificationFeaturesGenerator;
  }

  /**
   * Returns the search parameters.
   *
   * @return the search parameters
   */
  public SearchParameters getSearchParameters() {
    return searchParameters;
  }

  /**
   * Return the display preferences to use.
   *
   * @return the display preferences to use
   */
  public DisplayPreferences getDisplayPreferences() {
    return displayPreferences;
  }

  public ArrayList<IonMatch> getIonsCurrentlyMatched() throws MzMLUnmarshallerException {
    return spectrumAnnotator.getCurrentAnnotation(
        annotationPreferences.getIonTypes(),
        annotationPreferences.getNeutralLosses(),
        annotationPreferences.getValidatedCharges());
  }

  public SpectrumAnnotator getSpectrumAnnorator() {
    return spectrumAnnotator;
  }

  public void clearData(boolean clearDatabaseFolder) {
    projectDetails = null;
    spectrumAnnotator = new SpectrumAnnotator();
    try {
      spectrumFactory.closeFiles();
    } catch (Exception e) {
      e.printStackTrace();
    }
    try {
      sequenceFactory.closeFile();
    } catch (Exception e) {
      e.printStackTrace();
    }
    try {
      GOFactory.getInstance().closeFiles();
    } catch (Exception e) {
      e.printStackTrace();
    }

    try {
      spectrumFactory.clearFactory();
    } catch (Exception e) {
      e.printStackTrace();
    }

    try {
      sequenceFactory.clearFactory();
    } catch (Exception e) {
      e.printStackTrace();
    }

    try {
      GOFactory.getInstance().clearFactory();
    } catch (Exception e) {
      e.printStackTrace();
    }

    identifiedModifications = null;

    if (clearDatabaseFolder) {
      clearDatabaseFolder();
    }

    resetFeatureGenerator();

    // set up the tabs/panels

    currentPSFile = null;
  }

  /** Resets the feature generator. */
  public void resetFeatureGenerator() {
    identificationFeaturesGenerator =
        new IdentificationFeaturesGenerator(
            identification, searchParameters, idFilter, metrics, spectrumCountingPreferences);
  }

  /** Clears the database folder. */
  private void clearDatabaseFolder() {

    boolean databaseClosed = true;

    // close the database connection
    if (identification != null) {

      try {
        identification.close();
        identification = null;
      } catch (SQLException e) {
        databaseClosed = false;
        e.printStackTrace();
        JOptionPane.showMessageDialog(
            null, "Failed to close the database.", "Database Error", JOptionPane.WARNING_MESSAGE);
      }
    }

    // empty the matches folder
    if (databaseClosed) {
      File matchFolder = new File(resource, PeptideShaker.SERIALIZATION_DIRECTORY);

      if (matchFolder.exists()) {

        File[] tempFiles = matchFolder.listFiles();

        if (tempFiles != null) {
          for (File currentFile : tempFiles) {
            Util.deleteDir(currentFile);
          }
        }

        if (matchFolder.listFiles() != null && matchFolder.listFiles().length > 0) {
          JOptionPane.showMessageDialog(
              null,
              "Failed to empty the database folder:\n" + matchFolder.getPath() + ".",
              "Database Cleanup Failed",
              JOptionPane.WARNING_MESSAGE);
        }
      }
    }
  }

  /** Updates the ions used for fragment annotation. */
  public void updateAnnotationPreferencesFromSearchSettings() {
    annotationPreferences.setPreferencesFromSearchParamaers(searchParameters);
  }

  /**
   * Returns the gene preferences.
   *
   * @return the gene preferences
   */
  public GenePreferences getGenePreferences() {
    return genePreferences;
  }

  private GenePreferences genePreferences = new GenePreferences();

  /**
   * Returns the experiment.
   *
   * @return the experiment
   */
  public MsExperiment getExperiment() {
    return experiment;
  }

  /*
   * Returns the sample.
   * @return the sample
   */
  public Sample getSample() {
    return sample;
  }
  /**
   * Returns the replicate number.
   *
   * @return the replicateNumber
   */
  public int getReplicateNumber() {
    return this.replicateNumber;
  }

  /**
   * Returns the desired spectrum.
   *
   * @param spectrumKey the key of the spectrum
   * @return the desired spectrum
   */
  public MSnSpectrum getSpectrum(String spectrumKey) {
    String spectrumFile = Spectrum.getSpectrumFile(spectrumKey);
    String spectrumTitle = Spectrum.getSpectrumTitle(spectrumKey);
    try {
      return (MSnSpectrum) spectrumFactory.getSpectrum(spectrumFile, spectrumTitle);
    } catch (Exception e) {
      System.out.println(e.getMessage());
      return null;
    }
  }
}
  /**
   * Indicates whether the match designated by the match key validates the given item using the
   * given comparator and value threshold.
   *
   * @param itemName the name of the item to filter on
   * @param filterItemComparator the comparator to use
   * @param value the value to use as a threshold
   * @param spectrumKey the key of the match of interest
   * @param peptideAssumption the assumption to validate
   * @param identification the identification objects where to get identification matches from
   * @param identificationFeaturesGenerator the identification feature generator where to get
   *     identification features
   * @param identificationParameters the identification parameters used
   * @param peptideSpectrumAnnotator the annotator to use to annotate spectra when filtering on PSM
   *     or assumptions
   * @return a boolean indicating whether the match designated by the protein key validates the
   *     given item using the given comparator and value threshold.
   * @throws java.io.IOException exception thrown whenever an exception occurred while reading or
   *     writing a file
   * @throws java.lang.InterruptedException exception thrown whenever a threading issue occurred
   *     while validating that the match passes the filter
   * @throws java.lang.ClassNotFoundException exception thrown whenever an error occurred while
   *     deserilalizing a match
   * @throws java.sql.SQLException exception thrown whenever an error occurred while interacting
   *     with a database
   * @throws uk.ac.ebi.jmzml.xml.io.MzMLUnmarshallerException exception thrown whenever an error
   *     occurred while reading an mzML file
   * @throws org.apache.commons.math.MathException exception thrown whenever an error occurred while
   *     doing statistics on a distribution
   */
  public boolean isValidated(
      String itemName,
      FilterItemComparator filterItemComparator,
      Object value,
      String spectrumKey,
      PeptideAssumption peptideAssumption,
      Identification identification,
      IdentificationFeaturesGenerator identificationFeaturesGenerator,
      IdentificationParameters identificationParameters,
      PeptideSpectrumAnnotator peptideSpectrumAnnotator)
      throws IOException, InterruptedException, ClassNotFoundException, SQLException,
          MzMLUnmarshallerException, MathException {

    AssumptionFilterItem filterItem = AssumptionFilterItem.getItem(itemName);
    if (filterItem == null) {
      throw new IllegalArgumentException(
          "Filter item " + itemName + "not recognized as spectrum assumption filter item.");
    }
    String input = value.toString();
    switch (filterItem) {
      case precrusorMz:
        Precursor precursor = SpectrumFactory.getInstance().getPrecursor(spectrumKey);
        Double mz = precursor.getMz();
        return filterItemComparator.passes(input, mz.toString());
      case precrusorRT:
        precursor = SpectrumFactory.getInstance().getPrecursor(spectrumKey);
        Double rt = precursor.getRt();
        return filterItemComparator.passes(input, rt.toString());
      case precrusorCharge:
        Integer charge = peptideAssumption.getIdentificationCharge().value;
        return filterItemComparator.passes(input, charge.toString());
      case precrusorMzErrorDa:
        precursor = SpectrumFactory.getInstance().getPrecursor(spectrumKey);
        SearchParameters searchParameters = identificationParameters.getSearchParameters();
        Double mzError =
            Math.abs(
                peptideAssumption.getDeltaMass(
                    precursor.getMz(),
                    false,
                    searchParameters.getMinIsotopicCorrection(),
                    searchParameters.getMaxIsotopicCorrection()));
        return filterItemComparator.passes(input, mzError.toString());
      case precrusorMzErrorPpm:
        searchParameters = identificationParameters.getSearchParameters();
        precursor = SpectrumFactory.getInstance().getPrecursor(spectrumKey);
        mzError =
            Math.abs(
                peptideAssumption.getDeltaMass(
                    precursor.getMz(),
                    true,
                    searchParameters.getMinIsotopicCorrection(),
                    searchParameters.getMaxIsotopicCorrection()));
        return filterItemComparator.passes(input, mzError.toString());
      case precrusorMzErrorStat:
        searchParameters = identificationParameters.getSearchParameters();
        precursor = SpectrumFactory.getInstance().getPrecursor(spectrumKey);
        mzError =
            peptideAssumption.getDeltaMass(
                precursor.getMz(),
                identificationParameters.getSearchParameters().isPrecursorAccuracyTypePpm(),
                searchParameters.getMinIsotopicCorrection(),
                searchParameters.getMaxIsotopicCorrection());
        NonSymmetricalNormalDistribution precDeviationDistribution =
            identificationFeaturesGenerator.getMassErrorDistribution(
                Spectrum.getSpectrumFile(spectrumKey));
        Double p;
        if (mzError > precDeviationDistribution.getMean()) {
          p = precDeviationDistribution.getDescendingCumulativeProbabilityAt(mzError);
        } else {
          p = precDeviationDistribution.getCumulativeProbabilityAt(mzError);
        }
        return filterItemComparator.passes(input, p.toString());
      case sequenceCoverage:
        SpectrumFactory spectrumFactory = SpectrumFactory.getInstance();
        MSnSpectrum spectrum = (MSnSpectrum) spectrumFactory.getSpectrum(spectrumKey);
        Peptide peptide = peptideAssumption.getPeptide();
        AnnotationSettings annotationPreferences =
            identificationParameters.getAnnotationPreferences();
        SpecificAnnotationSettings specificAnnotationPreferences =
            annotationPreferences.getSpecificAnnotationPreferences(
                spectrum.getSpectrumKey(),
                peptideAssumption,
                identificationParameters.getSequenceMatchingPreferences(),
                identificationParameters
                    .getPtmScoringPreferences()
                    .getSequenceMatchingPreferences());
        HashMap<Integer, ArrayList<IonMatch>> matches =
            peptideSpectrumAnnotator.getCoveredAminoAcids(
                annotationPreferences,
                specificAnnotationPreferences,
                (MSnSpectrum) spectrum,
                peptide);
        double nCovered = 0;
        int nAA = peptide.getSequence().length();
        for (int i = 0; i <= nAA; i++) {
          ArrayList<IonMatch> matchesAtAa = matches.get(i);
          if (matchesAtAa != null && !matchesAtAa.isEmpty()) {
            nCovered++;
          }
        }
        Double coverage = 100.0 * nCovered / nAA;
        return filterItemComparator.passes(input, coverage.toString());
      case algorithmScore:
        Double score = peptideAssumption.getRawScore();
        if (score == null) {
          score = peptideAssumption.getScore();
        }
        return filterItemComparator.passes(input, score.toString());
      case fileNames:
        return filterItemComparator.passes(input, Spectrum.getSpectrumFile(spectrumKey));
      case confidence:
        PSParameter psParameter = new PSParameter();
        psParameter =
            (PSParameter) identification.getPeptideMatchParameter(spectrumKey, psParameter);
        Double confidence = psParameter.getProteinConfidence();
        return filterItemComparator.passes(input, confidence.toString());
      case validationStatus:
        psParameter = new PSParameter();
        psParameter =
            (PSParameter) identification.getPeptideMatchParameter(spectrumKey, psParameter);
        Integer validation = psParameter.getMatchValidationLevel().getIndex();
        return filterItemComparator.passes(input, validation.toString());
      case stared:
        psParameter = new PSParameter();
        psParameter =
            (PSParameter) identification.getPeptideMatchParameter(spectrumKey, psParameter);
        String starred;
        if (psParameter.isStarred()) {
          starred = FilterItemComparator.trueFalse[0];
        } else {
          starred = FilterItemComparator.trueFalse[1];
        }
        return filterItemComparator.passes(input, starred);
      default:
        throw new IllegalArgumentException(
            "Protein filter not implemented for item " + filterItem.name + ".");
    }
  }