/**
 * \file core/spoms/interpretationsaver.cpp
 * \date 16/02/2026
 * \author Aurélien Berthier, BENOIST Emile, TESSIER Dominique
 * \brief store alignment interpretations
 */


/*
 * PeptidOMS, Spectra to protein alignment tool
 * Copyright (C) 2026  Olivier Langella
 * <olivier.langella@cnrs.fr>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "interpretationsaver.h"
#include "locationbackup.h"
#include <algorithm>
#include <pappsomspp/core/exception/exceptionnotimplemented.h>
#include <pappsomspp/core/exception/exceptionnotfound.h>
#include <qobject.h>

namespace pappso
{
namespace spoms
{

InterpretationsSaver::InterpretationsSaver(const Protein *protein_p,
                                           int nb_locations_saved)
  : m_NB_LOCATIONS_SAVED(nb_locations_saved), mp_protein(protein_p)
{
  m_locationHeap.reserve(
    m_NB_LOCATIONS_SAVED); // la taille du tas correspond au nombre maximum de
                           // localisations potentielles a retenir par spectre
  // le tas est initialise avec des "ScenarioBackup" par default
  // min_score_location = MIN_SCENARIO_SCORE;
  // max_score_location = MIN_SCENARIO_SCORE;
  /*
  simple_alignment_hits_modified   = new String[NB_INTERPRETATIONS_SAVED];
  simple_alignment_sequences       = new String[NB_INTERPRETATIONS_SAVED];
  simple_alignment_scores          = new int[NB_INTERPRETATIONS_SAVED];
  simple_alignment_nb_common_peaks = new int[NB_INTERPRETATIONS_SAVED];

  non_aligned_mass_hits_modified   = new String[NB_INTERPRETATIONS_SAVED];
  non_aligned_mass_sequences       = new String[NB_INTERPRETATIONS_SAVED];
  non_aligned_mass_scores          = new int[NB_INTERPRETATIONS_SAVED];
  non_aligned_mass_nb_common_peaks = new int[NB_INTERPRETATIONS_SAVED];
  non_aligned_masses               = new double[NB_INTERPRETATIONS_SAVED];
  */
}

InterpretationsSaver::InterpretationsSaver(const InterpretationsSaver &other)
  : m_NB_LOCATIONS_SAVED(other.m_NB_LOCATIONS_SAVED),
    mp_protein(other.mp_protein)
{
  m_locationHeap = other.m_locationHeap;
  // min_score_location = MIN_SCENARIO_SCORE;
  // max_score_location = MIN_SCENARIO_SCORE;
}


InterpretationsSaver::~InterpretationsSaver()
{
}
/*
void
InterpretationsSaver::updateSpectrum(const std::vector<int> trees_position,
                                     NativeSpectrum spectrum)
{
  this.trees_position   = trees_position;
  this.current_spectrum = spectrum;
}
*/

/*
void
InterpretationsSaver::updateProtein(int protein_number)
{
  this.current_protein_number = protein_number;
}
 */
int
InterpretationsSaver::tryAddLocation(int start_line,
                                     int end_line,
                                     int score,
                                     int tree_id)
{

  auto it_find_location_backup =
    std::find_if(m_locationHeap.begin(),
                 m_locationHeap.end(),
                 [tree_id](const LocationBackup &location) {
                   return location.tree_id == tree_id;
                 });
  if(it_find_location_backup == m_locationHeap.end())
    {
      if(m_locationHeap.size() < m_NB_LOCATIONS_SAVED)
        {
          m_locationHeap.emplace_back(
            LocationBackup(mp_protein, start_line, end_line, score, tree_id));
        }
      else
        {
          // find the lowest score and replace
          auto it_find_min = std::min_element(
            m_locationHeap.begin(),
            m_locationHeap.end(),
            [](const LocationBackup &a, const LocationBackup &b) {
              return (a.score < b.score);
            });
          it_find_min->update(start_line, end_line, score, tree_id);
        }
    }
  else
    {
      if(it_find_location_backup->score < score)
        {
          // replace this tree id
          it_find_location_backup->update(start_line, end_line, score, tree_id);
        }
    }

  auto it_find_min =
    std::min_element(m_locationHeap.begin(),
                     m_locationHeap.end(),
                     [](const LocationBackup &a, const LocationBackup &b) {
                       return (a.score < b.score);
                     });
  return it_find_min->score;
}


const LocationBackup &
InterpretationsSaver::getMaxScore() const
{

  auto it_find_max =
    std::max_element(m_locationHeap.begin(),
                     m_locationHeap.end(),
                     [](const LocationBackup &a, const LocationBackup &b) {
                       return (a.score < b.score);
                     });
  if(it_find_max == m_locationHeap.end())
    {
      throw pappso::ExceptionNotFound(
        QObject::tr("max location score not found"));
    }
  return *it_find_max;
}

const std::vector<LocationBackup> &
InterpretationsSaver::getLocations() const
{
  /*
this.locations_score_threshold =
  this.max_score_location * LOCATIONS_SCORE_THRESHOLD;
this.max_score_location = MIN_SCENARIO_SCORE;
*/
  return m_locationHeap;
}


double
InterpretationsSaver::getLocationsScoreThreshold() const
{
  throw pappso::ExceptionNotImplemented(QObject::tr("not implemented %1 %2 %3")
                                          .arg(__FILE__)
                                          .arg(__FUNCTION__)
                                          .arg(__LINE__));
  return 0;
  // return locations_score_threshold;
}

/*
void
InterpretationsSaver::saveSimpleAlignment(int interpretation_number,
                                          Alignment alignment)
{
  if(alignment.getScore() > MIN_SCENARIO_SCORE)
    {
      // String[] res = alignment.computeHitModifiedAndRealSequence(spectrum);
      this.hit_modified_and_real_sequence =
        alignment.computeHitModifiedAndRealSequence();
      this.simple_alignment_hits_modified[interpretation_number] =
        this.hit_modified_and_real_sequence[0];
      this.simple_alignment_sequences[interpretation_number] =
        this.hit_modified_and_real_sequence[1];
      this.simple_alignment_scores[interpretation_number] =
        alignment.getScore();
      // this.simple_alignment_nb_common_peaks[interpretation_number] =
      // alignment.nbPeaksInCommon(spectrum);
      alignment.computeNbPeaksInCommon();
      this.simple_alignment_nb_common_peaks[interpretation_number] =
        alignment.getNBPeaksInCommon();
    }
  else
    {
      this.simple_alignment_hits_modified[interpretation_number] = null;
    }
}
*/

/*
public
void
saveNonAlignedMass(int interpretation_number, Alignment alignment)
{
  if(alignment.getScore() > MIN_SCENARIO_SCORE)
    {
      // String[] res = alignment.computeHitModifiedAndRealSequence(spectrum);
      this.hit_modified_and_real_sequence =
        alignment.computeHitModifiedAndRealSequence();
      this.non_aligned_mass_hits_modified[interpretation_number] =
        this.hit_modified_and_real_sequence[0];
      this.non_aligned_mass_sequences[interpretation_number] =
        this.hit_modified_and_real_sequence[1];
      this.non_aligned_mass_scores[interpretation_number] =
        alignment.getScore();
      // this.non_aligned_mass_nb_common_peaks[interpretation_number] =
      // alignment.nbPeaksInCommon(spectrum);
      alignment.computeNbPeaksInCommon();
      this.non_aligned_mass_nb_common_peaks[interpretation_number] =
        alignment.getNBPeaksInCommon();
      this.non_aligned_masses[interpretation_number] =
        alignment.getTransformedSpectrum().getNonAlignedMass();
    }
  else
    {
      this.non_aligned_mass_hits_modified[interpretation_number] = null;
    }
}
*/


/*
 * methode appelee lorsque les resultats courant doivent etre sauvegardes dans
 * le fichier de resultat
 */
/*
public
void
save(PrintWriter output)
{
  for(int interpretation_number = 0;
      interpretation_number < NB_INTERPRETATIONS_SAVED;
      ++interpretation_number)
    {
      if(this.simple_alignment_hits_modified[interpretation_number] != null)
        {
          output.write(String.format("%s;%d;%d",
                                     this.current_spectrum.getTitle(),
                                     this.current_spectrum.getScan(),
                                     this.current_spectrum.getID()));
          output.write(String.format(
            ";%s;%s;%s;%d;%d",
            this.simple_alignment_sequences[interpretation_number],
            Proteins.foundPeptide(
              this.simple_alignment_sequences[interpretation_number]),
            this.simple_alignment_hits_modified[interpretation_number],
            this.simple_alignment_scores[interpretation_number],
            this.simple_alignment_nb_common_peaks[interpretation_number]));
          // if (this.non_aligned_mass_nb_common_peaks[interpretation_number]
          // >= this.simple_alignment_nb_common_peaks[interpretation_number] +
          // 3)
          if(this.non_aligned_mass_hits_modified[interpretation_number] != null)
            {
              output.write(String.format(
                ";%s;%s;%s;%s;%d;%d\n",
                DECIMAL_FORMAT.format(
                  this.non_aligned_masses[interpretation_number]),
                this.non_aligned_mass_sequences[interpretation_number],
                Proteins.foundPeptide(
                  this.non_aligned_mass_sequences[interpretation_number]),
                this.non_aligned_mass_hits_modified[interpretation_number],
                this.non_aligned_mass_scores[interpretation_number],
                this.non_aligned_mass_nb_common_peaks[interpretation_number]));
            }
          else
            {
              output.write(";;;;;;;\n");
            }
        }
    }
}
*/
} // namespace spoms
} // namespace pappso
