
/*******************************************************************************
 * Copyright (c) 2015 Olivier Langella <Olivier.Langella@moulon.inra.fr>.
 *
 * This file is part of the PAPPSOms++ library.
 *
 *     PAPPSOms++ 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.
 *
 *     PAPPSOms++ 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 PAPPSOms++.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *     Olivier Langella <Olivier.Langella@moulon.inra.fr> - initial API and
 *implementation
 ******************************************************************************/

#include <QDebug>
#include "grpsubgroup.h"
#include "grppeptideset.h"
#include "../pappsoexception.h"
#include "../utils.h"


namespace pappso
{


GrpSubGroup::GrpSubGroup(GrpProtein *p_protein) : m_peptidePtrList(p_protein)
{
  m_grpProteinPtrList.push_back(p_protein);
}

GrpSubGroup::GrpSubGroup(const GrpSubGroup &other)
  : m_grpProteinPtrList(other.m_grpProteinPtrList),
    m_peptidePtrList(other.m_peptidePtrList)
{
}

unsigned int
GrpSubGroup::getGroupNumber() const
{
  return m_groupNumber;
}
unsigned int
GrpSubGroup::getSubGroupNumber() const
{
  return m_subGroupNumber;
}
const std::vector<GrpProtein *> &
GrpSubGroup::getGrpProteinList() const
{
  return m_grpProteinPtrList;
}
const QString
GrpSubGroup::getGroupingId() const
{
  if(m_groupNumber == 0)
    {
      return "";
    }
  return QString("%1.%2")
    .arg(Utils::getLexicalOrderedString(m_groupNumber))
    .arg(Utils::getLexicalOrderedString(m_subGroupNumber));
}
unsigned int
GrpSubGroup::maxCount() const
{
  unsigned int max = 0;
  for(GrpProtein *p_protein : m_grpProteinPtrList)
    {
      if(max < p_protein->getCount())
        {
          max = p_protein->getCount();
        }
    }
  return max;
}
bool
GrpSubGroup::operator<(const GrpSubGroup &other) const
{
  if(m_peptidePtrList.size() == other.m_peptidePtrList.size())
    {
      if(maxCount() == other.maxCount())
        {
          if(m_grpProteinPtrList.size() == other.m_grpProteinPtrList.size())
            {
              // compare peptide set surface ?
              // alphabetic order taken into account
              return ((*(m_grpProteinPtrList.begin()))->getAccession() <
                      (*(other.m_grpProteinPtrList.begin()))->getAccession());
            }
          else
            {
              // if there is same peptide size evidence, then perhaps it's
              // better to consider that
              // the best group is the one that include more proteins
              return (m_grpProteinPtrList.size() >
                      other.m_grpProteinPtrList.size());
            }
        }
      else
        {
          // counts are evidences of the presence of a subgroup
          // the fewer is the count, the weaker is the subgroup
          return (maxCount() > other.maxCount());
        }
    }
  else
    {
      // peptides are evidences of the presence of a subgroup
      // the fewer is the peptide list, the weaker is the subgroup
      return (m_peptidePtrList.size() > other.m_peptidePtrList.size());
    }
}

GrpSubGroup::~GrpSubGroup()
{
}
GrpSubGroupSp
GrpSubGroup::makeGrpSubGroupSp()
{
  return std::make_shared<GrpSubGroup>(*this);
}

const GrpPeptideSet &
GrpSubGroup::getPeptideSet() const
{
  return m_peptidePtrList;
}

bool
GrpSubGroup::merge(GrpSubGroup *p_subgroup)
{
  qDebug() << "GrpSubGroup::merge begin " << m_grpProteinPtrList.size() << " "
           << this->getFirstAccession() << " "
           << p_subgroup->getFirstAccession();
  // if (this == p_subgroup) {
  //     return true;
  //}
  if(p_subgroup->m_peptidePtrList == m_peptidePtrList)
    {
      // m_grpProteinPtrList.splice (m_grpProteinPtrList.end(),
      // p_subgroup->m_grpProteinPtrList);
      m_grpProteinPtrList.insert(m_grpProteinPtrList.end(),
                                 p_subgroup->m_grpProteinPtrList.begin(),
                                 p_subgroup->m_grpProteinPtrList.end());
      // m_grpProteinPtrList.insert (m_grpProteinPtrList.end(),
      // p_subgroup->m_grpProteinPtrList.begin(),p_subgroup->m_grpProteinPtrList.end());
      return true;
    }
  else
    {
      return false;
    }
}

bool
GrpSubGroup::includes(const GrpSubGroup *p_subgroup) const
{
  if(m_peptidePtrList.biggerAndContainsAll(p_subgroup->getPeptideSet()))
    {
      return true;
    }
  else
    {
      return false;
    }
}

void
GrpSubGroup::setGroupNumber(unsigned int i)
{
  m_groupNumber = i;
  for(auto &&p_protein : m_grpProteinPtrList)
    {
      p_protein->setGroupNumber(i);
    }
}

void
GrpSubGroup::setSubGroupNumber(unsigned int i)
{
  m_subGroupNumber = i;
  for(auto &&p_protein : m_grpProteinPtrList)
    {
      p_protein->setSubGroupNumber(i);
    }
}

void
GrpSubGroup::numbering()
{
  qDebug() << "GrpSubGroup::numbering begin";

  // sort proteins by accession numbers :
  // m_grpProteinPtrList.sort([](GrpProtein * first, GrpProtein * second) {
  //    return (first->getAccession() < second->getAccession()) ;
  //});
  std::sort(m_grpProteinPtrList.begin(),
            m_grpProteinPtrList.end(),
            [](GrpProtein *first, GrpProtein *second) {
              return (first->getAccession() < second->getAccession());
            });
  // list unique removes all but the first element from every consecutive group
  // of equal elements in the container
  //   m_grpProteinPtrList.unique();


  unsigned int i = 1;
  for(auto &&p_protein : m_grpProteinPtrList)
    {
      p_protein->setRank(i);
      i++;
    }
  qDebug() << "GrpSubGroup::numbering end";
}
const QString &
GrpSubGroup::getFirstAccession() const
{
  auto it = m_grpProteinPtrList.begin();
  if(it == m_grpProteinPtrList.end())
    {
      throw PappsoException(QObject::tr("m_grpProteinPtrList is empty"));
    }
  else
    {
      return (*it)->getAccession();
    }
}

std::size_t
GrpSubGroup::peptideListSize() const
{
  return m_peptidePtrList.size();
}

} // namespace pappso
