// --------------------------------------------------------------------------
//                   OpenMS -- Open-Source Mass Spectrometry
// --------------------------------------------------------------------------
// Copyright The OpenMS Team -- Eberhard Karls University Tuebingen,
// ETH Zurich, and Freie Universitaet Berlin 2002-2020.
//
// This software is released under a three-clause BSD license:
//  * Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//  * Neither the name of any author or any participating institution
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission.
// For a full list of authors, refer to the file AUTHORS.
// --------------------------------------------------------------------------
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE CONTRIBUTING
// INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// --------------------------------------------------------------------------
// $Maintainer: Eugen Netz $
// $Authors: Timo Sachsenberg, Eugen Netz $
// --------------------------------------------------------------------------

#pragma once

#include <OpenMS/CONCEPT/ProgressLogger.h>
#include <OpenMS/DATASTRUCTURES/DefaultParamHandler.h>
#include <OpenMS/KERNEL/StandardTypes.h>
#include <OpenMS/KERNEL/ConsensusMap.h>
#include <OpenMS/FORMAT/FASTAFile.h>
#include <OpenMS/ANALYSIS/XLMS/OPXLDataStructs.h>

namespace OpenMS
{

//-------------------------------------------------------------
//Doxygen docu
//-------------------------------------------------------------

/**
  @brief Search for peptide pairs linked with a labeled cross-linker

  This tool performs a search for cross-links in the given mass spectra.
  It uses linked MS1 features to pair up MS2 spectra and uses these pairs to find the fragment peaks that contain the linker and those that do not.

  It executes the following steps in order:
  <ul>
    <li>Processing of spectra: deisotoping and filtering</li>
    <li>Digesting and preprocessing the protein database, building a peptide pair index dependent on the precursor masses of the MS2 spectra</li>
    <li>Generating theoretical spectra of cross-linked peptides and aligning the experimental spectra against those</li>
    <li>Scoring of cross-link spectrum matches</li>
    <li>Using PeptideIndexer to map the peptides to all possible source proteins</li>
  </ul>

  See below for available parameters and more functionality.

  <h3>Input: MS2 spectra, linked features from FeatureFinderMultiplex and fasta database of proteins expected to be cross-linked in the sample</h3>
  The spectra should be provided as one PeakMap. If you have multiple files, e.g. for multiple fractions, you should run this tool on each
  file separately.
  The database should be provided as a vector of FASTAEntrys containing the target and decoy proteins.
  A ConsensusMap, that links the MS1 feature pairs from heavy and light cross-linkers is also required.
  This can be generated by the tool FeatureFinderMultiplex.
  Setting up FeatureFinderMultiplex:
  In the FeatureFinderMultiplex parameters you have to change the mass of one of the labels to the difference between the light and heavy
  (e.g. change the mass of Arg6 to 12.075321 for labeled DSS) in the advanced options.
  The parameter -labels should have one empty label ( [] ) and the label you adapted (e.g. [][Arg6]).
  For the other settings refer to the documentation of FeatureFinderMultiplex.

  <h3>Parameters</h3>
  The parameters for fixed and variable modifications refer to additional modifications beside the cross-linker.
  The linker used in the experiment has to be described using the cross-linker specific parameters.
  Only one mass is allowed for a cross-linker, that links two peptides (cross_linker:mass_light), while multiple masses are possible for mono-links of the same cross-linking reagent.
  Mono-links are cross-linkers, that are linked to one peptide by one of their two reactive groups.
  The masses refer to the light version of the linker. The parameter cross_linker:mass_iso_shift defines the difference
  between the light and heavy versions of the cross-linker and the mono-links.
  The parameters cross_linker:residue1 and cross_linker:residue2 are used to enumerate the amino acids,
  that each end of the linker can react with. This way any heterobifunctional cross-linker can be defined.
  To define a homobifunctional cross-linker, these two parameters should have the same value.
  The parameter cross_linker:name is used to solve ambiguities arising from different cross-linkers having the same mass
  after the linking reaction (see section on output for clarification).

  <h3>Output: XL-MS Identifications with scores and linked positions in the proteins</h3>
  The input parameters protein_ids and peptide_ids are filled with XL-MS search parameters and IDs


  <CENTER>
    <table>
        <tr>
            <td ALIGN = "center" BGCOLOR="#EBEBEB"> pot. predecessor tools </td>
            <td VALIGN="middle" ROWSPAN=2> \f$ \longrightarrow \f$ OpenPepXL \f$ \longrightarrow \f$</td>
            <td ALIGN = "center" BGCOLOR="#EBEBEB"> pot. successor tools </td>
        </tr>
        <tr>
            <td VALIGN="middle" ALIGN = "center" ROWSPAN=1> - </td>
            <td VALIGN="middle" ALIGN = "center" ROWSPAN=1> - </td>
        </tr>
    </table>
  </CENTER>

*/

  class OPENMS_DLLAPI OpenPepXLAlgorithm :
   public DefaultParamHandler, public ProgressLogger
  {
public:

    /// Exit codes
    enum ExitCodes
    {
      EXECUTION_OK,
      ILLEGAL_PARAMETERS,
      UNEXPECTED_RESULT,
      INCOMPATIBLE_INPUT_DATA
    };

    /// Default constructor
    OpenPepXLAlgorithm();

    /// Default destructor
    ~OpenPepXLAlgorithm() override;

    /**
     * @brief Performs the main function of this class, the search for cross-linked peptides

     * @param unprocessed_spectra The input PeakMap of experimental spectra
     * @param fasta_db The protein database containing targets and decoys
     * @param protein_ids A result vector containing search settings. Should contain one PeptideIdentification.
     * @param peptide_ids A result vector containing cross-link spectrum matches as PeptideIdentifications and PeptideHits. Should be empty.
     * @param preprocessed_pair_spectra A result structure containing linear and cross-linked ion spectra. Will be overwritten. This is only necessary for writing out xQuest type spectrum files.
     * @param spectrum_pairs A result vector containing paired spectra indices. Should be empty. This is only necessary for writing out xQuest type spectrum files.
     * @param all_top_csms A result vector containing cross-link spectrum matches as CrossLinkSpectrumMatches. Should be empty. This is only necessary for writing out xQuest type spectrum files.
     * @param spectra A result vector containing the input spectra after preprocessing and filtering. Should be empty. This is only necessary for writing out xQuest type spectrum files.
     */
    ExitCodes run(PeakMap& unprocessed_spectra, ConsensusMap& cfeatures, std::vector<FASTAFile::FASTAEntry>& fasta_db, std::vector<ProteinIdentification>& protein_ids, std::vector<PeptideIdentification>& peptide_ids, OPXLDataStructs::PreprocessedPairSpectra& preprocessed_pair_spectra, std::vector< std::pair<Size, Size> >& spectrum_pairs, std::vector< std::vector< OPXLDataStructs::CrossLinkSpectrumMatch > >& all_top_csms, PeakMap& spectra);

private:
    void updateMembers_() override;

    static OPXLDataStructs::PreprocessedPairSpectra preprocessPairs_(const PeakMap& spectra, const std::vector< std::pair<Size, Size> >& spectrum_pairs, const double cross_link_mass_iso_shift, double fragment_mass_tolerance, double fragment_mass_tolerance_xlinks, bool fragment_mass_tolerance_unit_ppm, bool deisotope);

    String decoy_string_;
    bool decoy_prefix_;

    Int min_precursor_charge_;
    Int max_precursor_charge_;
    double precursor_mass_tolerance_;
    bool precursor_mass_tolerance_unit_ppm_;
    IntList precursor_correction_steps_;

    double fragment_mass_tolerance_;
    double fragment_mass_tolerance_xlinks_;
    bool fragment_mass_tolerance_unit_ppm_;

    StringList cross_link_residue1_;
    StringList cross_link_residue2_;
    double cross_link_mass_light_;
    double cross_link_mass_iso_shift_;
    DoubleList cross_link_mass_mono_link_;
    String cross_link_name_;

    StringList fixedModNames_;
    StringList varModNames_;
    Size max_variable_mods_per_peptide_;
    Size peptide_min_size_;
    Size missed_cleavages_;
    String enzyme_name_;

    Int number_top_hits_;
    String deisotope_mode_;

    String add_y_ions_;
    String add_b_ions_;
    String add_x_ions_;
    String add_a_ions_;
    String add_c_ions_;
    String add_z_ions_;
    String add_losses_;
  };
}
