/**
 * \file /output/fann/fanndataoutput.cpp
 * \date 18/07/2022
 * \author Olivier Langella
 * \brief write data for fann c++ library
 */

/*******************************************************************************
 * Copyright (c) 2022 Olivier Langella
 *<olivier.langella@universite-paris-saclay.fr>.
 *
 * This file is part of i2MassChroQ.
 *
 *     i2MassChroQ 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.
 *
 *     i2MassChroQ 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 i2MassChroQ.  If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

#include "fanndataoutput.h"
#include <pappsomspp/core/psm/xtandem/xtandemhyperscore.h>
#include <cmath>

FannDataOutput::FannDataOutput(CalcWriterInterface *p_writer,
                               const Project *p_project)
  : mp_project(p_project)
{


  mp_writer = p_writer;

  std::vector<const PeptideEvidence *> peptide_evidence_list_all;
  std::vector<const PeptideEvidence *> peptide_evidence_list_target;

  for(IdentificationGroup *identification_group :
      mp_project->getIdentificationGroupList())
    {
      for(auto &p_protein_match : identification_group->getProteinMatchList())
        {
          std::vector<const PeptideEvidence *> peptide_evidence_list;
          p_protein_match->collectPeptideEvidences(peptide_evidence_list,
                                                   ValidationState::notValid);

          for(auto &peptide_evidence : peptide_evidence_list)
            {
              if(peptide_evidence->getIdentificationEngine() ==
                 IdentificationEngine::DeepProt)
                {
                  peptide_evidence_list_all.push_back(peptide_evidence);
                }
            }

          if(!p_protein_match->getProteinXtpSp().get()->isDecoy())
            {
              peptide_evidence_list_target.insert(
                peptide_evidence_list_target.end(),
                peptide_evidence_list.begin(),
                peptide_evidence_list.end());
            }
        }

      std::sort(peptide_evidence_list_all.begin(),
                peptide_evidence_list_all.end());
      auto last = std::unique(peptide_evidence_list_all.begin(),
                              peptide_evidence_list_all.end());
      peptide_evidence_list_all.erase(last, peptide_evidence_list_all.end());


      std::sort(peptide_evidence_list_target.begin(),
                peptide_evidence_list_target.end());
      auto last2 = std::unique(peptide_evidence_list_target.begin(),
                               peptide_evidence_list_target.end());
      peptide_evidence_list_target.erase(last2,
                                         peptide_evidence_list_target.end());
    }


  mp_writer->writeCell(peptide_evidence_list_all.size());
  mp_writer->writeCell(29);
  mp_writer->writeCell(1);
  mp_writer->writeLine();


  pappso::XtandemSpectrumProcess spectrum_process;
  spectrum_process.setMinimumMz(150);
  spectrum_process.setNmostIntense(100);
  spectrum_process.setDynamicRange(100);

  for(auto &peptide_evidence : peptide_evidence_list_all)
    {
      writeFeatures(peptide_evidence, spectrum_process);
      mp_writer->writeLine();
      if(std::find(peptide_evidence_list_target.begin(),
                   peptide_evidence_list_target.end(),
                   peptide_evidence) != peptide_evidence_list_target.end())
        {
          mp_writer->writeCell(1);
        }
      else
        {
          mp_writer->writeCell(0);
        }
      mp_writer->writeLine();
    }
}

FannDataOutput::~FannDataOutput()
{
}


void
FannDataOutput::writeFeatures(const PeptideEvidence *p_peptide_evidence,
                              pappso::XtandemSpectrumProcess &spectrum_process)
{
  qDebug();
  const PeptideEvidence *p_best_peptide_evidence = p_peptide_evidence;
  mp_writer->writeCell(p_peptide_evidence->getExperimentalMz());
  mp_writer->writeCell(p_peptide_evidence->getTheoreticalMz());
  mp_writer->writeCell(p_peptide_evidence->getDeltaMass());
  mp_writer->writeCell(std::abs(p_peptide_evidence->getDeltaMass()));
  mp_writer->writeCell(
    p_peptide_evidence->getParam(PeptideEvidenceParam::deepprot_original_count)
      .toInt());
  mp_writer->writeCell(
    p_peptide_evidence->getParam(PeptideEvidenceParam::deepprot_fitted_count)
      .toInt());
  mp_writer->writeCell(
    p_peptide_evidence->getParam(PeptideEvidenceParam::deepprot_match_type)
      .toInt());
  mp_writer->writeCell(
    p_peptide_evidence
      ->getParam(PeptideEvidenceParam::deepprot_peptide_candidate_status)
      .toInt());


  pappso::MassSpectrum spectrum = spectrum_process.process(
    *p_peptide_evidence->getMassSpectrumCstSPtr().get(),
    p_peptide_evidence->getExperimentalMz(),
    p_peptide_evidence->getCharge());

  std::list<pappso::Enums::PeptideIon> ion_list;
  ion_list.push_back(pappso::Enums::PeptideIon::y);
  ion_list.push_back(pappso::Enums::PeptideIon::b);

  pappso::PrecisionPtr precision =
    pappso::PrecisionFactory::getDaltonInstance(0.02);


  std::shared_ptr<pappso::XtandemHyperscore> p_best_hyperscore(
    std::make_shared<pappso::XtandemHyperscore>(
      spectrum,
      p_peptide_evidence->getPeptideXtpSp(),
      p_peptide_evidence->getCharge(),
      precision,
      ion_list,
      true));

  std::vector<pappso::XtandemHyperscore> resultable;
  std::vector<std::shared_ptr<PeptideEvidence>> peptide_evidence_solution_list =
    generatePeptideEvidenceSolutions(p_peptide_evidence);
  for(auto sp_peptide_evidence : peptide_evidence_solution_list)
    {
      qDebug();
      std::shared_ptr<pappso::XtandemHyperscore> p_hyperscore(
        std::make_shared<pappso::XtandemHyperscore>(
          spectrum,
          sp_peptide_evidence->getPeptideXtpSp(),
          sp_peptide_evidence->getCharge(),
          precision,
          ion_list,
          true));

      if(p_hyperscore.get()->getHyperscore() >
         p_best_hyperscore.get()->getHyperscore())
        {
          p_best_hyperscore       = p_hyperscore;
          p_best_peptide_evidence = sp_peptide_evidence.get();
        }
      qDebug();
    }

  qDebug();
  mp_writer->writeCell(p_best_hyperscore->getHyperscore());


  std::size_t peptide_size =
    p_best_peptide_evidence->getPeptideXtpSp().get()->size();

  mp_writer->writeCell(peptide_size);

  qDebug();
  mp_writer->writeCell((std::size_t)p_best_peptide_evidence->getCharge());

  m_psmFeatures.setPeptideSpectrumCharge(
    p_best_peptide_evidence->getPeptideXtpSp(),
    p_best_peptide_evidence->getMassSpectrumCstSPtr().get(),
    p_best_peptide_evidence->getCharge());


  mp_writer->writeCell(std::log(m_psmFeatures.getTotalIntensity()));

  mp_writer->writeCell(m_psmFeatures.getNumberOfMatchedIons());

  mp_writer->writeCell(
    std::log(m_psmFeatures.getIntensityOfMatchedIon(pappso::Enums::PeptideIon::y)));
  mp_writer->writeCell(
    std::log(m_psmFeatures.getIntensityOfMatchedIon(pappso::Enums::PeptideIon::b)));


  mp_writer->writeCell(
    m_psmFeatures.getMaxConsecutiveIon(pappso::Enums::PeptideIon::y));
  mp_writer->writeCell(
    m_psmFeatures.getMaxConsecutiveIon(pappso::Enums::PeptideIon::b));


  mp_writer->writeCell(
    m_psmFeatures.getIntensityOfMatchedIon(pappso::Enums::PeptideIon::y) /
    m_psmFeatures.getTotalIntensity());
  mp_writer->writeCell(
    m_psmFeatures.getIntensityOfMatchedIon(pappso::Enums::PeptideIon::b) /
    m_psmFeatures.getTotalIntensity());


  mp_writer->writeCell(
    std::log(p_best_peptide_evidence->getMassSpectrumCstSPtr()
               .get()
               ->maxIntensityDataPoint()
               .y));

  mp_writer->writeCell(
    std::log(m_psmFeatures.getMaxIntensityPeakIonMatch(pappso::Enums::PeptideIon::y)));

  mp_writer->writeCell(
    std::log(m_psmFeatures.getMaxIntensityPeakIonMatch(pappso::Enums::PeptideIon::b)));

  mp_writer->writeCell(
    m_psmFeatures.getAaSequenceCoverage(pappso::Enums::PeptideIon::y) / peptide_size);

  mp_writer->writeCell(
    m_psmFeatures.getAaSequenceCoverage(pappso::Enums::PeptideIon::b) / peptide_size);

  mp_writer->writeCell(m_psmFeatures.getMatchedMzDiffMean());

  mp_writer->writeCell(m_psmFeatures.getMatchedMzDiffSd());


  mp_writer->writeCell(m_psmFeatures.countMatchedIonComplementPairs());
  mp_writer->writeCell(
    std::log(m_psmFeatures.getTotalIntensityOfMatchedIonComplementPairs() /
             m_psmFeatures.getTotalIntensity()));

  mp_writer->writeCell(m_psmFeatures.getComplementPairsAaSequenceCoverage() /
                       peptide_size);
  qDebug();
}


std::vector<std::shared_ptr<PeptideEvidence>>
FannDataOutput::generatePeptideEvidenceSolutions(
  const PeptideEvidence *peptide_evidence) const
{
  std::vector<std::shared_ptr<PeptideEvidence>> solution_list;
  std::vector<std::size_t> position_list;
  QVariant param =
    peptide_evidence->getParam(PeptideEvidenceParam::deepprot_delta_positions);
  if(!param.isNull())
    {
      for(auto pos_str : param.toString().split(" ", Qt::SkipEmptyParts))
        {
          position_list.push_back(pos_str.toUInt());
        }
    }
  if(position_list.size() > 0)
    {
      std::sort(position_list.begin(),
                position_list.end(),
                [](std::size_t a, std::size_t b) { return a < b; });

      pappso::AaModificationP modification =
        pappso::AaModification::getInstanceCustomizedMod(
          peptide_evidence->getDeltaMass());
      qDebug();
      for(std::size_t pos : position_list)
        {
          qDebug();
          PeptideXtpSp peptide_sp =
            PeptideXtp(*(peptide_evidence->getPeptideXtpSp().get()))
              .makePeptideXtpSp();

          qDebug() << peptide_sp.get()->toAbsoluteString();
          peptide_sp.get()->addAaModification(modification, pos);

          qDebug() << peptide_sp.get()->toAbsoluteString();
          PeptideEvidenceSp pe =
            PeptideEvidence(*(peptide_evidence)).makePeptideEvidenceSp();
          pe.get()->setPeptideXtpSp(peptide_sp);

          qDebug();
          solution_list.push_back(pe);
          qDebug() << pe.get()->getHtmlSequence();
        }
    }
  qDebug();
  return solution_list;
}
