/**
 * \file output/exportfastafile.cpp
 * \date 15/01/2019
 * \author Olivier Langella
 * \brief FASTA file writer
 */

/*******************************************************************************
 * Copyright (c) 2019 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/>.
 *
 ******************************************************************************/

#include "exportfastafile.h"
#include <pappsomspp/core/pappsoexception.h>

ExportFastaFile::ExportFastaFile(QString filename, ExportFastaType type)
{
  mp_outputFastaFile = new QFile(filename);
  m_exportType       = type;
}

ExportFastaFile::~ExportFastaFile()
{
  close();
}


void
ExportFastaFile::write(ProjectSp project_sp)
{
  qDebug();
  if(mp_outputFastaFile == nullptr)
    {
      throw pappso::PappsoException(
        QObject::tr("error : mp_outputFastaFile is null\n"));
    }
  mp_outputFastaFile->open(QIODevice::WriteOnly);
  QTextStream *p_outputStream = new QTextStream(mp_outputFastaFile);


  pappso::FastaOutputStream fasta_output(*p_outputStream);

  for(IdentificationGroup *identification :
      project_sp.get()->getIdentificationGroupList())
    {
      if(m_exportType == ExportFastaType::allValidTargetProteins)
        {
          for(auto protein_match : identification->getProteinMatchList())
            {
              //all valid and target proteins
              if(protein_match->isValid())
                {
                  ProteinXtpSp p_protein = protein_match->getProteinXtpSp();
                  if(!protein_match->getProteinXtpSp().get()->isDecoy())
                    {

                      pappso::Protein protein(
                        QString("%1 %2")
                          .arg(p_protein->getAccession())
                          .arg(p_protein->getDescription()),
                        p_protein->getSequence());
                      fasta_output.writeProtein(protein);
                    }
                }
            }
        }
      else
        {
          writeIdentificationGroup(fasta_output, identification);
        }
    }
  qDebug();
  mp_outputFastaFile->flush();
  mp_outputFastaFile->close();
  close();
}

void
ExportFastaFile::close()
{
  if(mp_outputFastaFile != nullptr)
    {
      delete mp_outputFastaFile;
      mp_outputFastaFile = nullptr;
    }
}


void
ExportFastaFile::writeIdentificationGroup(
  pappso::FastaOutputStream &fasta_output, IdentificationGroup *p_ident)
{
  qDebug();
  for(const std::pair<const unsigned int, GroupingGroupSp> &group_pair :
      p_ident->getGroupStore().getGroupMap())
    {
      // unsigned int protein_rank        = 0;
      unsigned int group_number        = 0;
      unsigned int subgroup_number     = 0;
      unsigned int old_group_number    = 0;
      unsigned int old_subgroup_number = 0;

      std::vector<const ProteinMatch *> protein_match_list =
        group_pair.second.get()->getProteinMatchList();

      std::sort(protein_match_list.begin(),
                protein_match_list.end(),
                [](const ProteinMatch *a, const ProteinMatch *b) {
                  return a->getGrpProteinSp().get()->getGroupingId() <
                         b->getGrpProteinSp().get()->getGroupingId();
                });

      for(auto &protein_match : protein_match_list)
        {
          pappso::GrpProtein *p_grp_protein =
            protein_match->getGrpProteinSp().get();
          ProteinXtp *p_protein = protein_match->getProteinXtpSp().get();

          group_number    = p_grp_protein->getGroupNumber();
          subgroup_number = p_grp_protein->getSubGroupNumber();

          if((m_exportType == ExportFastaType::oneBySubgroup) &&
             (group_number == old_group_number) &&
             (subgroup_number == old_subgroup_number) &&
             (p_grp_protein->getRank() > 1))
            continue;

          if((m_exportType == ExportFastaType::oneByGroup) &&
             (group_number == old_group_number))
            continue;

          old_group_number    = group_number;
          old_subgroup_number = subgroup_number;

          pappso::Protein protein(QString("%1|%2 %3")
                                    .arg(p_grp_protein->getGroupingId())
                                    .arg(p_protein->getAccession())
                                    .arg(p_protein->getDescription()),
                                  p_protein->getSequence());
          fasta_output.writeProtein(protein);
        }
    }
  qDebug();
}
