
/*******************************************************************************
 * Copyright (c) 2015 Olivier Langella <Olivier.Langella@moulon.inra.fr>.
 *
 * This file is part of XTPcpp.
 *
 *     XTPcpp 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.
 *
 *     XTPcpp 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 XTPcpp.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Contributors:
 *     Olivier Langella <Olivier.Langella@moulon.inra.fr> - initial API and
 *implementation
 ******************************************************************************/
#include "project.h"
#include "../input/xpipsaxhandler.h"
#include "../input/xtpxpipsaxhandler.h"
#include "peptidematch.h"
#include "proteinmatch.h"
#include <QDebug>
#include <pappsomspp/exception/exceptionnotfound.h>

Project::Project()
{
}

Project::~Project()
{
  auto it = _identification_goup_list.begin();
  while(it != _identification_goup_list.end())
    {
      delete(*it);
      it++;
    }
}

bool
Project::checkPsimodCompliance() const
{
  return _peptide_store.checkPsimodCompliance();
}
void
Project::readResultFile(QString filename)
{
  IdentificationDataSourceSp ident_source =
    _identification_data_source_store.getInstance(filename);

  ident_source.get()->parseTo(this);
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__;
}

ProjectMode
Project::getProjectMode() const
{
  return _project_mode;
}
void
Project::setProjectMode(ProjectMode mode)
{
  _project_mode = mode;
}
std::vector<IdentificationGroup *>
Project::getIdentificationGroupList()
{
  return _identification_goup_list;
}

const std::vector<IdentificationGroup *>
Project::getIdentificationGroupList() const
{
  return _identification_goup_list;
}
GroupingType
Project::getGroupingType() const
{
  return m_groupingType;
}

FastaFileStore &
Project::getFastaFileStore()
{
  return _fasta_file_store;
}

const FastaFileStore &
Project::getFastaFileStore() const
{
  return _fasta_file_store;
}
MsRunStore &
Project::getMsRunStore()
{
  return _msrun_store;
}
const MsRunStore &
Project::getMsRunStore() const
{
  return _msrun_store;
}
PeptideStore &
Project::getPeptideStore()
{
  return _peptide_store;
}

ProteinStore &
Project::getProteinStore()
{
  return _protein_store;
}

const ProteinStore &
Project::getProteinStore() const
{
  return _protein_store;
}

IdentificationDataSourceStore &
Project::getIdentificationDataSourceStore()
{
  return _identification_data_source_store;
}
const IdentificationDataSourceStore &
Project::getIdentificationDataSourceStore() const
{
  return _identification_data_source_store;
}
const AutomaticFilterParameters &
Project::getAutomaticFilterParameters() const
{
  return _automatic_filter_parameters;
}

ContaminantRemovalMode
Project::getContaminantRemovalMode() const
{
  return m_contaminantRemovalMode;
}
void
Project::setContaminantRemovalMode(
  ContaminantRemovalMode contaminant_removal_mode)
{
  m_contaminantRemovalMode = contaminant_removal_mode;
}
void
Project::updateAutomaticFilters(
  const AutomaticFilterParameters &automatic_filter_parameters)
{

  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__;
  _automatic_filter_parameters = automatic_filter_parameters;
  for(auto &p_id_group : _identification_goup_list)
    {
      p_id_group->updateAutomaticFilters(_automatic_filter_parameters);
    }
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__;
}
ProjectSp
Project::makeProjectSp() const
{
  return std::make_shared<Project>(*this);
}

IdentificationGroup *
Project::newIdentificationGroup()
{
  _p_current_identification_group = new IdentificationGroup(this);
  _identification_goup_list.push_back(_p_current_identification_group);
  return _p_current_identification_group;
}
void
Project::readXpipFile(WorkMonitorInterface *p_monitor, QFileInfo xpip_fileinfo)
{
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__;

  XpipSaxHandler *parser_java_xpip = new XpipSaxHandler(p_monitor, this);

  QXmlSimpleReader simplereader;
  simplereader.setContentHandler(parser_java_xpip);
  simplereader.setErrorHandler(parser_java_xpip);
  qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__
           << " Read XPIP XML result file '" << xpip_fileinfo.absoluteFilePath()
           << "'";

  QFile qfile(xpip_fileinfo.absoluteFilePath());
  QXmlInputSource xmlInputSource(&qfile);

  if(simplereader.parse(xmlInputSource))
    {

      qfile.close();
    }
  else
    {
      qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__
               << parser_java_xpip->errorString();
      // throw PappsoException(
      //    QObject::tr("error reading tandem XML result file :\n").append(
      //         parser->errorString()));

      qfile.close();

      if(parser_java_xpip->isJavaXpip())
        {
          // delete parser_java_xpip;
          throw pappso::PappsoException(
            QObject::tr("Error reading %1 XPIP file :\n %2")
              .arg(xpip_fileinfo.absoluteFilePath())
              .arg(parser_java_xpip->errorString()));
        }
      else
        {
          XtpXpipSaxHandler *parser_xtp_xpip =
            new XtpXpipSaxHandler(p_monitor, this);

          QXmlSimpleReader simplereaderb;
          simplereaderb.setContentHandler(parser_xtp_xpip);
          simplereaderb.setErrorHandler(parser_xtp_xpip);

          qDebug() << __FILE__ << " " << __FUNCTION__ << " " << __LINE__
                   << " Read XPIP XML result file '"
                   << xpip_fileinfo.absoluteFilePath() << "'";

          QFile qfileb(xpip_fileinfo.absoluteFilePath());
          QXmlInputSource xmlInputSourceb(&qfileb);

          if(simplereaderb.parse(xmlInputSourceb))
            {
              delete parser_xtp_xpip;
              qfileb.close();
            }
          else
            {
              if(parser_xtp_xpip->isXtpXpip())
                {
                  throw pappso::PappsoException(
                    QObject::tr("Error reading %1 XPIP file :\n %2")
                      .arg(xpip_fileinfo.absoluteFilePath())
                      .arg(parser_xtp_xpip->errorString()));
                }
              else
                {
                  qDebug() << __FILE__ << " " << __FUNCTION__ << " "
                           << __LINE__;
                  throw pappso::PappsoException(
                    QObject::tr(
                      "Error reading %1 XPIP file :\n it is not an XPIP file")
                      .arg(xpip_fileinfo.absoluteFilePath()));
                }
            }
        }
    }

  delete parser_java_xpip;
}


void
Project::startGrouping(WorkMonitorInterface *p_work_monitor)
{
  qDebug();
  for(IdentificationGroup *p_id_group : _identification_goup_list)
    {
      p_id_group->startGrouping(
        m_contaminantRemovalMode, m_groupingType, p_work_monitor);
    }
  qDebug();
}
void
Project::setLabelingMethodSp(LabelingMethodSp labeling_method_sp)
{
  _labeling_method_sp = labeling_method_sp;
  _peptide_store.setLabelingMethodSp(labeling_method_sp);
}

LabelingMethodSp
Project::getLabelingMethodSp() const
{
  return _labeling_method_sp;
}

bool
Project::hasPtmExperiment() const
{
  if(getIdentificationGroupList().at(0)->getPtmGroupingExperiment() != nullptr)
    return true;
  return false;
}

void
Project::getSameXicPeptideEvidenceList(
  std::vector<const PeptideEvidence *> &peptide_evidence_list,
  const MsRun *p_msrun,
  const PeptideXtp *p_peptide,
  unsigned int charge) const
{
  for(const IdentificationGroup *p_ident_group : _identification_goup_list)
    {
      p_ident_group->getSameXicPeptideEvidenceList(
        peptide_evidence_list, p_msrun, p_peptide, charge);
    }
}

void
Project::prepareMsrunRetentionTimesForAlignment() const
{
  qDebug();

  for(auto &msrun_sp : this->getMsRunStore().getMsRunList())
    {
      msrun_sp.get()->clearMsRunRetentionTime();
    }

  qDebug();
  bool is_ok = true;
  PeptideEvidenceStore empty_store;
  for(IdentificationDataSourceSp p_ident_data_source :
      this->getIdentificationDataSourceStore()
        .getIdentificationDataSourceList())
    {


      std::map<MsRun *, std::vector<PeptideEvidence *>>
        peptide_evidence_list_by_msrun;
      for(auto &peptide_evidence :
          p_ident_data_source->getPeptideEvidenceStore()
            .getPeptideEvidenceList())
        {
          if(peptide_evidence.get()->isValid())
            {

              MsRun *p_msrun = peptide_evidence.get()->getMsRunPtr();
              auto ret       = peptide_evidence_list_by_msrun.insert(
                std::pair<MsRun *, std::vector<PeptideEvidence *>>(
                  p_msrun, std::vector<PeptideEvidence *>()));
              if(ret.second == false)
                {
                  // "element 'z' already existed";
                }

              ret.first->second.push_back(peptide_evidence.get());
              qDebug() << "msrun=" << p_msrun->getRunId()
                       << " size pe=" << ret.first->second.size();
            }
        }

      for(auto &msrun_list_element : peptide_evidence_list_by_msrun)
        {
          MsRun *p_msrun = msrun_list_element.first;

          qDebug();
          if(p_msrun->getMsRunRetentionTimePtr() == nullptr)
            {
              p_msrun->buildMsRunRetentionTime(empty_store);
            }

          p_msrun->getMsRunRetentionTimePtr()
            ->getMsRunReaderSPtr()
            .get()
            ->acquireDevice();
          qDebug();
          for(auto &peptide_evidence : msrun_list_element.second)
            {
              qDebug();
              try
                {
                  if(peptide_evidence->isValid())
                    {
                      std::size_t spectrum_index =
                        p_msrun->getMsRunRetentionTimePtr()
                          ->getMsRunReaderSPtr()
                          .get()
                          ->scanNumber2SpectrumIndex(
                            peptide_evidence->getScanNumber());

                      qDebug() << "spectrum_index=" << spectrum_index;
                      p_msrun->getMsRunRetentionTimePtr()->addPeptideAsSeamark(
                        peptide_evidence->getPeptideXtpSp()
                          .get()
                          ->getNativePeptideP(),
                        spectrum_index);
                    }
                }
              catch(pappso::PappsoException &error)
                {

                  throw pappso::PappsoException(
                    QString("Error while processing "
                            "peptide_evidence_list_by_msrun at "
                            "evidence %1, size=%2"
                            ":\n %3")
                      .arg(peptide_evidence->getPeptideXtpSp()
                             .get()
                             ->getLiAbsoluteString())
                      .arg(msrun_list_element.second.size())
                      .arg(error.qwhat()));
                }
              qDebug();
            }

          p_msrun->getMsRunRetentionTimePtr()
            ->getMsRunReaderSPtr()
            .get()
            ->releaseDevice();
          qDebug();
        }
    }
  qDebug();

  if(is_ok)
    {
      for(auto &msrun_sp : this->getMsRunStore().getMsRunList())
        {
          msrun_sp->computeMsRunRetentionTime();
        }
      // find the best reference
    }
  else
    {
      for(auto &msrun_sp : this->getMsRunStore().getMsRunList())
        {
          msrun_sp->clearMsRunRetentionTime();
        }
    }
  qDebug();
}

void
Project::setProjectName(const QString &name)
{
  m_project_name = QFileInfo(name).baseName();
}

QString
Project::getProjectName()
{
  return m_project_name;
}

void
Project::setProjectChangedStatus()
{
  m_project_changed = true;
}


bool
Project::getProjectChangedStatus() const
{
  return m_project_changed;
}

std::vector<MsRunAlignmentGroupSp>
Project::getMsRunAlignmentGroupList()
{
  return m_msRunAlignmentGroupList;
}

void
Project::addMsRunAlignmentGroupToList(MsRunAlignmentGroupSp new_group)
{
  m_msRunAlignmentGroupList.push_back(new_group);
}

MsRunAlignmentGroupSp
Project::getMsRunAlignmentGroupFromList(QString group_name)
{
  foreach(MsRunAlignmentGroupSp alignment_group, getMsRunAlignmentGroupList())
    {
      if(alignment_group->getMsRunAlignmentGroupName() == group_name)
        {
          return alignment_group;
        }
    }
  return nullptr;
}

PtmMode
Project::getPtmMode() const
{
  return m_ptmMode;
}

void
Project::setPtmMode(PtmMode mode)
{
  m_ptmMode = mode;
}
