
/*******************************************************************************
 * Copyright (c) 2017 Olivier Langella <olivier.langella@u-psud.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/>.
 *
 * Contributors:
 *     Olivier Langella <olivier.langella@u-psud.fr> - initial API and
 *implementation
 ******************************************************************************/

#include "groupinggroup.h"
#include <core/proteinmatch.h>
#include <core/peptidematch.h>
#include <pappsomspp/core/grouping/grppeptide.h>
#include <pappsomspp/core/utils.h>
#include <set>

GroupingGroup::GroupingGroup()
{
}

GroupingGroup::~GroupingGroup()
{
}

const std::vector<std::pair<unsigned int, const PeptideEvidence *>> &
GroupingGroup::getPairSgNumberPeptideEvidenceList() const
{
  return _pair_sg_number_peptide_evidence_list;
}
unsigned int
GroupingGroup::getGroupNumber() const
{
  return _group_number;
}
unsigned int
GroupingGroup::getNumberOfSubgroups() const
{
  return _number_of_subgroup;
}
const std::vector<const ProteinMatch *> &
GroupingGroup::getProteinMatchList() const
{
  return _protein_match_list;
}
std::vector<const PeptideEvidence *>
GroupingGroup::getPeptideEvidenceList() const
{
  std::vector<const PeptideEvidence *> peptide_match_list;
  for(auto &&pair_peptide_match : _pair_sg_number_peptide_evidence_list)
    {
      peptide_match_list.push_back(pair_peptide_match.second);
    }
  return peptide_match_list;
}

const QStringList
GroupingGroup::getSubgroupIdList(const PeptideEvidence *p_peptide_match) const
{
  std::set<unsigned int> subgroup_list;
  pappso::GrpPeptide *p_grp_peptide = p_peptide_match->getGrpPeptideSp().get();
  if(p_grp_peptide != nullptr)
    {
      for(auto &&pair_peptide_match : _pair_sg_number_peptide_evidence_list)
        {
          if(pair_peptide_match.second->getGrpPeptideSp().get() ==
             p_grp_peptide)
            {
              subgroup_list.insert(pair_peptide_match.first);
            }
        }
    }


  QStringList sg_str_list;
  for(unsigned int sgnum : subgroup_list)
    {
      sg_str_list << QString("%1.%2")
                       .arg(
                         pappso::Utils::getLexicalOrderedString(_group_number))
                       .arg(pappso::Utils::getLexicalOrderedString(sgnum));
    }
  return sg_str_list;
}

unsigned int
GroupingGroup::countSubgroupPresence(
  const PeptideEvidence *p_peptide_evidence) const
{
  std::set<unsigned int> subgroup_list;
  pappso::GrpPeptide *p_grp_peptide =
    p_peptide_evidence->getGrpPeptideSp().get();
  if(p_grp_peptide != nullptr)
    {
      for(auto &&pair_peptide_match : _pair_sg_number_peptide_evidence_list)
        {
          if(pair_peptide_match.second->getGrpPeptideSp().get() ==
             p_grp_peptide)
            {
              subgroup_list.insert(pair_peptide_match.first);
            }
        }
    }
  return subgroup_list.size();
}

std::size_t
GroupingGroup::countSpecificSampleScan(const ProteinMatch *p_protein_match,
                                       ValidationState state,
                                       const MsRun *p_msrun_id,
                                       const Label *p_label) const
{
  if(_number_of_subgroup == 1)
    {
      return p_protein_match->countSampleScan(state, p_msrun_id);
    }
  std::vector<size_t> spectrum_list_in;
  for(auto &&p_peptide_match : p_protein_match->getPeptideMatchList())
    {
      if(p_peptide_match.getPeptideEvidence()->getValidationState() >= state)
        {
          if(p_msrun_id == nullptr)
            {
              spectrum_list_in.push_back(
                p_peptide_match.getPeptideEvidence()->getHashSampleScan());
            }
          else
            {
              if(p_label != nullptr)
                {
                  if((p_peptide_match.getPeptideEvidence()->getMsRunP() ==
                      p_msrun_id) &&
                     (p_peptide_match.getPeptideEvidence()
                        ->getPeptideXtpSp()
                        .get()
                        ->getLabel() == p_label))
                    {
                      spectrum_list_in.push_back(
                        p_peptide_match.getPeptideEvidence()
                          ->getHashSampleScan());
                    }
                }
              else
                {
                  if(p_peptide_match.getPeptideEvidence()->getMsRunP() ==
                     p_msrun_id)
                    {
                      spectrum_list_in.push_back(
                        p_peptide_match.getPeptideEvidence()
                          ->getHashSampleScan());
                    }
                }
            }
        }
    }


  // unicity check on spectrum_list_in
  std::sort(spectrum_list_in.begin(), spectrum_list_in.end());
  auto last = std::unique(spectrum_list_in.begin(), spectrum_list_in.end());
  spectrum_list_in.erase(last, spectrum_list_in.end());

  std::vector<size_t> spectrum_list_out;
  unsigned int sg_number =
    p_protein_match->getGrpProteinSp().get()->getSubGroupNumber();
  for(auto &&pair_peptide_match : _pair_sg_number_peptide_evidence_list)
    {
      if(pair_peptide_match.first != sg_number)
        {
          spectrum_list_out.push_back(
            pair_peptide_match.second->getHashSampleScan());
        }
    }

  // unicity check on spectrum_list_out
  std::sort(spectrum_list_out.begin(), spectrum_list_out.end());
  auto last2 = std::unique(spectrum_list_out.begin(), spectrum_list_out.end());
  spectrum_list_out.erase(last2, spectrum_list_out.end());

  // count common elements :
  std::size_t i = 0, j = 0, count_common = 0;
  while(i < spectrum_list_in.size() && j < spectrum_list_out.size())
    {
      if(spectrum_list_in[i] == spectrum_list_out[j])
        {
          ++count_common;
          ++i;
          ++j;
        }

      else if(spectrum_list_in[i] < spectrum_list_out[j])
        {
          ++i;
        }

      else
        {
          ++j;
        }
    }


  qDebug();
  // return number of specific (only found in sequen_list_in :
  return (spectrum_list_in.size() - count_common);
}

std::size_t
GroupingGroup::countSpecificSequenceLi(const ProteinMatch *p_protein_match,
                                       ValidationState state,
                                       const MsRun *p_msrun_id,
                                       const Label *p_label) const
{
  if(_number_of_subgroup == 1)
    {
      return p_protein_match->countSequenceLi(state, p_msrun_id, p_label);
    }
  qDebug();
  std::vector<QString> sequence_list_in;
  for(auto &&p_peptide_match : p_protein_match->getPeptideMatchList())
    {
      if(p_peptide_match.getPeptideEvidence()->getValidationState() >= state)
        {
          if(p_msrun_id == nullptr)
            {
              sequence_list_in.push_back(p_peptide_match.getPeptideEvidence()
                                           ->getPeptideXtpSp()
                                           .get()
                                           ->getSequenceLi());
            }
          else
            {
              if(p_label != nullptr)
                {
                  if((p_peptide_match.getPeptideEvidence()->getMsRunP() ==
                      p_msrun_id) &&
                     (p_peptide_match.getPeptideEvidence()
                        ->getPeptideXtpSp()
                        .get()
                        ->getLabel() == p_label))
                    {
                      sequence_list_in.push_back(
                        p_peptide_match.getPeptideEvidence()
                          ->getPeptideXtpSp()
                          .get()
                          ->getSequenceLi());
                    }
                }
              else
                {
                  if(p_peptide_match.getPeptideEvidence()->getMsRunP() ==
                     p_msrun_id)
                    {
                      sequence_list_in.push_back(
                        p_peptide_match.getPeptideEvidence()
                          ->getPeptideXtpSp()
                          .get()
                          ->getSequenceLi());
                    }
                }
            }
        }
    }
  qDebug();
  // unicity check on sequence_list_in
  std::sort(sequence_list_in.begin(), sequence_list_in.end());
  auto last = std::unique(sequence_list_in.begin(), sequence_list_in.end());
  sequence_list_in.erase(last, sequence_list_in.end());
  qDebug();

  std::vector<QString> sequence_list_out;
  unsigned int sg_number =
    p_protein_match->getGrpProteinSp().get()->getSubGroupNumber();
  for(auto &&pair_peptide_match : _pair_sg_number_peptide_evidence_list)
    {
      if(pair_peptide_match.first != sg_number)
        {
          sequence_list_out.push_back(
            pair_peptide_match.second->getPeptideXtpSp()
              .get()
              ->getSequenceLi());
        }
    }
  qDebug();
  // unicity check on sequence_list_out
  std::sort(sequence_list_out.begin(), sequence_list_out.end());
  auto last2 = std::unique(sequence_list_out.begin(), sequence_list_out.end());
  sequence_list_out.erase(last2, sequence_list_out.end());
  qDebug();
  // count common elements :
  std::size_t i = 0, j = 0, count_common = 0;
  while(i < sequence_list_in.size() && j < sequence_list_out.size())
    {
      if(sequence_list_in[i] == sequence_list_out[j])
        {
          ++count_common;
          ++i;
          ++j;
        }

      else if(sequence_list_in[i] < sequence_list_out[j])
        {
          ++i;
        }

      else
        {
          ++j;
        }
    }


  qDebug();
  // return number of specific (only found in sequen_list_in :
  return (sequence_list_in.size() - count_common);
}

unsigned int
GroupingGroup::countProteinInSubgroup(unsigned int subgroup_number) const
{
  return std::count_if(
    _protein_match_list.begin(),
    _protein_match_list.end(),
    [subgroup_number](const ProteinMatch *p_protein_match) {
      if(p_protein_match->getGrpProteinSp().get()->getSubGroupNumber() ==
         subgroup_number)
        {
          return true;
        }
      else
        {
          return false;
        }
    });
}

QString
GroupingGroup::getProteinGroupingIdOfSubgroup(
  unsigned int subgroup_number) const
{
  return QString("%1.%2.a1")
    .arg(pappso::Utils::getLexicalOrderedString(_group_number))
    .arg(pappso::Utils::getLexicalOrderedString(subgroup_number));
}

void
GroupingGroup::add(const ProteinMatch *p_protein_match)
{
  _group_number = p_protein_match->getGrpProteinSp().get()->getGroupNumber();
  _protein_match_list.push_back(p_protein_match);
  if(p_protein_match->getGrpProteinSp().get()->getRank() == 1)
    {
      _number_of_subgroup++;
      unsigned int sg_number =
        p_protein_match->getGrpProteinSp().get()->getSubGroupNumber();

      for(auto &&peptide_match : p_protein_match->getPeptideMatchList())
        {
          if(peptide_match.getPeptideEvidence()->isValidAndChecked())
            {
              _pair_sg_number_peptide_evidence_list.push_back(
                std::pair<unsigned int, const PeptideEvidence *>(
                  sg_number, peptide_match.getPeptideEvidence()));
            }
        }
    }
}
