/*******************************************************************************
 * Copyright (c) 2020 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:
 *     Thomas Renne <thomas.renne@u-psud.fr> - initial API and
 *implementation
 ***************************/


#include "alignmentgroup.h"
#include <QDir>
#include "identification_sources/identificationdatasource.h"
#include "msrun.h"
#include "project.h"
#include <pappsomspp/core/exception/exceptionnotfound.h>


MsRunAlignmentGroup::MsRunAlignmentGroup(Project *project, QString group_name)
{
  m_groupName = group_name;
  mp_project  = project;
  m_status    = AlignmentGroupStatus::created;
}

MsRunAlignmentGroup::~MsRunAlignmentGroup()
{
}

const QString &
MsRunAlignmentGroup::getMsRunAlignmentGroupName() const
{
  return m_groupName;
}

void
MsRunAlignmentGroup::setMsRunAlignmentGroupName(QString group_name)
{
  m_groupName = group_name;
}

const std::vector<MsRunSp> &
MsRunAlignmentGroup::getMsRunsInAlignmentGroup() const
{
  return m_msrunAlignmentGroupList;
}

void
MsRunAlignmentGroup::addMsRunToMsRunAlignmentGroupList(MsRunSp new_msrun)
{
  m_msrunAlignmentGroupList.push_back(new_msrun);
}

void
MsRunAlignmentGroup::removeMsRunFromMsRunAlignmentGroupList(
  MsRunSp removed_msrun)
{
  if(removed_msrun.get()->getAlignmentGroup() != nullptr)
    {
      auto itend = remove_if(m_msrunAlignmentGroupList.begin(),
                             m_msrunAlignmentGroupList.end(),
                             [removed_msrun](const MsRunSp &a) {
                               if(a.get() == removed_msrun.get())
                                 return true;
                               return false;
                             });

      m_msrunAlignmentGroupList.erase(itend, m_msrunAlignmentGroupList.end());
    }
}

MsRunSp
MsRunAlignmentGroup::getMsRunReference() const
{
  return msp_msRunReference;
}

void
MsRunAlignmentGroup::setMsRunReference(MsRunSp reference)
{
  msp_msRunReference = reference;
}

void
MsRunAlignmentGroup::prepareMsrunRetentionTimesForAlignment() const
{
  qDebug() << "begin";

  for(auto &msrun_sp : getMsRunsInAlignmentGroup())
    {
      msrun_sp.get()->clearMsRunRetentionTime();
    }

  std::vector<IdentificationDataSourceSp> p_ident_data_sources;

  for(IdentificationDataSourceSp p_ident_data_source :
      mp_project->getIdentificationDataSourceStore()
        .getIdentificationDataSourceList())
    {
      if(std::find(m_msrunAlignmentGroupList.begin(),
                   m_msrunAlignmentGroupList.end(),
                   p_ident_data_source->getMsRunSp()) !=
         m_msrunAlignmentGroupList.end())
        {
          p_ident_data_sources.push_back(p_ident_data_source);
        }
    }

  bool is_ok = true;
  PeptideEvidenceStore empty_store;
  for(IdentificationDataSourceSp p_ident_data_source : p_ident_data_sources)
    {
      for(auto &peptide_evidence :
          p_ident_data_source->getPeptideEvidenceStore()
            .getPeptideEvidenceList())
        {
          if(peptide_evidence.get()->isValid())
            {
              MsRun *p_msrun = peptide_evidence.get()->getMsRunPtr();
              if(p_msrun->getMsRunRetentionTimePtr() == nullptr)
                {

                  p_msrun->buildMsRunRetentionTime(empty_store);
                  /*
                                    throw pappso::PappsoException(
                                      QObject::tr(
                                        "Error preparing msrun retention
                                        time
                     for %1 :\n " "p_msrun->getMsRunRetentionTimePtr() ==
                     nullptr") .arg(p_msrun->getXmlId()));
                                        */
                }
              p_msrun->getMsRunReaderSPtr()->acquireDevice();
              p_msrun->getMsRunRetentionTimePtr()->addPeptideAsSeamark(
                peptide_evidence.get()
                  ->getPeptideXtpSp()
                  .get()
                  ->getNativePeptideP(),peptide_evidence.get()->getRetentionTime(), 1);
              p_msrun->getMsRunReaderSPtr()->releaseDevice();
            }
        }
    }
  if(is_ok)
    {
      for(auto &msrun_sp : getMsRunsInAlignmentGroup())
        {
          msrun_sp->computeMsRunRetentionTime();
        }
      // find the best reference
    }
  else
    {
      for(auto &msrun_sp : getMsRunsInAlignmentGroup())
        {
          msrun_sp->clearMsRunRetentionTime();
        }
    }
  qDebug() << "end";
}

void
MsRunAlignmentGroup::savePostMassChroqmlParameters(QString masschroqml_file)
{
  m_masschroqmlPath = masschroqml_file;
}

void
MsRunAlignmentGroup::setMassChroQRunStatus(AlignmentGroupStatus status)
{
  m_status = status;
}

void
MsRunAlignmentGroup::setMassChroQRunStatusFromInt(int status)
{
  m_status = static_cast<AlignmentGroupStatus>(status);
}

AlignmentGroupStatus
MsRunAlignmentGroup::getGroupStatus()
{
  return m_status;
}


const QString &
MsRunAlignmentGroup::getMassChroqmlPath() const
{
  return m_masschroqmlPath;
}


void
MsRunAlignmentGroup::setMassChroqmlPath(QString masschroqml_path)
{
  m_masschroqmlPath = masschroqml_path;
}


const QString
MsRunAlignmentGroup::getMassChroqmlRdataPath() const
{

  QString masschroqml_rdata_path =
    QFileInfo(m_masschroqmlPath).absoluteDir().absolutePath() + "/rdata_" +
    QFileInfo(m_masschroqmlPath).baseName();
  return masschroqml_rdata_path;
}

const QString
MsRunAlignmentGroup::getMassChroqmlResultTsvDirectoryPath() const
{
  QString xic_directory_path =
    QFileInfo(m_masschroqmlPath).absoluteDir().absolutePath() + "/result_" +
    QFileInfo(m_masschroqmlPath).baseName() + ".d";

  const QFileInfo resultDir(xic_directory_path);
  if((!resultDir.exists()) || (!resultDir.isDir()) || (!resultDir.isReadable()))
    {
      throw pappso::ExceptionNotFound(
        QObject::tr("MassChroQ TSV output directory \"%1\" does not exist, is "
                    "not a directory, or is not readable. Check that MassChroQ "
                    "ran using the TSV output.")
          .arg(resultDir.absoluteFilePath()));
    }
  return xic_directory_path;
}

const QString
MsRunAlignmentGroup::getMassChroqmlResultProteinListPath() const
{
  QString protein_list_file;

  const QDir resultDir(getMassChroqmlResultTsvDirectoryPath());
  for(QFileInfo &file_info : resultDir.entryInfoList())
    {
      //_proteins.tsv
      if(file_info.absoluteFilePath().endsWith("_proteins.tsv"))
        {
          if(!protein_list_file.isEmpty())
            {
              throw pappso::ExceptionNotFound(
                QObject::tr("MassChroQ TSV output directory \"%1\" does "
                            "contains more than one "
                            "protein tsv file.")
                  .arg(resultDir.absolutePath()));
            }
          protein_list_file = file_info.absoluteFilePath();
        }
    }
  if(protein_list_file.isEmpty())
    {
      throw pappso::ExceptionNotFound(
        QObject::tr("MassChroQ TSV output directory \"%1\" does not contain "
                    "protein tsv file.")
          .arg(resultDir.absolutePath()));
    }
  return protein_list_file;
}

const QString
MsRunAlignmentGroup::getMassChroqmlResultPeptideListPath() const
{
  QString peptide_list_file;

  const QDir resultDir(getMassChroqmlResultTsvDirectoryPath());
  for(QFileInfo &file_info : resultDir.entryInfoList())
    {
      //_proteins.tsv
      if(file_info.fileName().startsWith("peptides_q1_"))
        {
          if(!peptide_list_file.isEmpty())
            {
              throw pappso::ExceptionNotFound(
                QObject::tr("MassChroQ TSV output directory \"%1\" does "
                            "contains more than one "
                            "peptide tsv file.")
                  .arg(resultDir.absolutePath()));
            }
          peptide_list_file = file_info.absoluteFilePath();
        }
    }
  if(peptide_list_file.isEmpty())
    {
      throw pappso::ExceptionNotFound(
        QObject::tr("MassChroQ TSV output directory \"%1\" does not contain "
                    "peptide tsv file.")
          .arg(resultDir.absolutePath()));
    }
  return peptide_list_file;
}
