/*******************************************************************************
 * Copyright (c) 2023 Filippo Rusconi
 *<filippo.rusconi@universite-paris-saclay.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/>.
 *
 ******************************************************************************/

#include "msrunreadconfig.h"
#include <QDebug>

namespace pappso
{

MsRunReadConfig::MsRunReadConfig()
{
  // Set these two levels to true by default.
  m_msLevels[1] = true;
  m_msLevels[2] = true;
}

MsRunReadConfig::MsRunReadConfig(const MsRunReadConfig &other)
  : m_retentionTimeStartSeconds(other.m_retentionTimeStartSeconds),
    m_retentionTimeEndSeconds(other.m_retentionTimeEndSeconds),
    m_paramsMap(other.m_paramsMap)
{
  for(std::size_t index = 0; index < MAX_MS_LEVELS; ++index)
    m_msLevels[index] = other.m_msLevels[index];
}

MsRunReadConfig::~MsRunReadConfig()
{
}

MsRunReadConfig &
MsRunReadConfig::operator=(const MsRunReadConfig &other)
{
  if(&other == this)
    return *this;

  m_retentionTimeStartSeconds = other.m_retentionTimeStartSeconds;
  m_retentionTimeEndSeconds   = other.m_retentionTimeEndSeconds;
  m_paramsMap                 = other.m_paramsMap;

  for(std::size_t index = 0; index < MAX_MS_LEVELS; ++index)
    m_msLevels[index] = other.m_msLevels[index];

  return *this;
}

void
MsRunReadConfig::setRetentionTimeStartInSeconds(
  double retention_time_start_in_seconds)
{
  m_retentionTimeStartSeconds = retention_time_start_in_seconds;
}

double
MsRunReadConfig::getRetentionTimeStartInSeconds() const
{
  return m_retentionTimeStartSeconds;
}

void
MsRunReadConfig::setRetentionTimeEndInSeconds(
  double retention_time_end_in_seconds)
{
  m_retentionTimeEndSeconds = retention_time_end_in_seconds;
}

double
MsRunReadConfig::getRetentionTimeEndInSeconds() const
{
  return m_retentionTimeEndSeconds;
}

void
MsRunReadConfig::setMsLevels(std::vector<std::size_t> ms_levels)
{
  // First reset all the levels to false, this time, since we'll fill the array
  // with explicit values.
  for(std::size_t index = 0; index < MAX_MS_LEVELS; ++index)
    m_msLevels[index] = false;

  // And now actually fill with true values the proper array cells.
  for(auto ms_level : ms_levels)
    {
      if(ms_level >= MAX_MS_LEVELS)
        {
          qDebug() << "The passed vector of MS levels holds a value that is "
                      "not correct:"
                   << ms_level << ": skipping it.";

          continue;
        }
      m_msLevels[ms_level] = true;
    }
}

const bool *
MsRunReadConfig::getMsLevels(void) const
{
  return m_msLevels;
}

QString
MsRunReadConfig::getMsLevelsAsString() const
{
  QString text = "";

  for(std::size_t index = 0; index < MAX_MS_LEVELS; ++index)
    {
      if(m_msLevels[index] == true)
        text += QString("%1 ").arg(index);
    }

  return text;
}


bool
MsRunReadConfig::acceptMsLevel(std::size_t ms_level) const
{
  if(ms_level >= MAX_MS_LEVELS)
    return false;

  return m_msLevels[ms_level];
}

bool
MsRunReadConfig::acceptRetentionTimeInSeconds(
  double retention_time_in_seconds) const
{
  // qDebug() << "Requested retention_time_in_seconds:"
  //          << retention_time_in_seconds;

  // Whatever the member datum below, if it is equal to -1
  // then that means that RT is not a selection criterion.
  if(m_retentionTimeStartSeconds == -1 || m_retentionTimeEndSeconds == -1)
    {
      return true;
    }

  // We use inclusive RT ranges.
  if(retention_time_in_seconds >= m_retentionTimeStartSeconds)
    {
      if(retention_time_in_seconds <= m_retentionTimeEndSeconds)
        {
          return true;
        }
    }

  return false;
}

bool
MsRunReadConfig::needPeakList() const
{
  return m_isPeakListNeeded;
}

void
MsRunReadConfig::setNeedPeakList(bool need_peak_list)
{
  m_isPeakListNeeded = need_peak_list;
}

void
MsRunReadConfig::setParameterValue(pappso::MsRunReadConfigParameter parameter,
                                   const QVariant &value)
{

  auto ret = m_paramsMap.insert(
    std::pair<MsRunReadConfigParameter, QVariant>(parameter, value));

  if(ret.second == false)
    {
      ret.first->second = value;
    }
}

const QVariant
MsRunReadConfig::getParameterValue(
  pappso::MsRunReadConfigParameter parameter) const
{
  auto it = m_paramsMap.find(parameter);
  if(it == m_paramsMap.end())
    {
      return QVariant();
    }
  else
    {
      return it->second;
    }
}


void
MsRunReadConfig::reset()
{
  m_retentionTimeStartSeconds = -1;
  m_retentionTimeEndSeconds   = -1;
  m_isPeakListNeeded          = true;

  for(std::size_t index = 0; index < MAX_MS_LEVELS; ++index)
    {
      m_msLevels[index] = false;
    }
  // Set these two levels to true by default.
  m_msLevels[1] = true;
  m_msLevels[2] = true;

  m_paramsMap.clear();
}

QString
MsRunReadConfig::toString() const
{
  QString text = QString("MsRunReadConfig\n: RT start: %1, RT end: %2\n")
                   .arg(m_retentionTimeStartSeconds)
                   .arg(m_retentionTimeEndSeconds);

  text += "MS level(s): ";

  for(std::size_t index = 0; index < MAX_MS_LEVELS; ++index)
    {
      if(m_msLevels[index] == true)
        text += QString("%1 ").arg(index);
    }

  text += " \n";

  if(!getParameterValue(
        MsRunReadConfigParameter::TimsFrameIonMobScanIndexBegin)
        .isNull())
    {
      text +=
        QString("Mobility index range: [%1-%2]\n")
          .arg(getParameterValue(MsRunReadConfigParameter::
                                   TimsFrameIonMobScanIndexBegin)
                 .toUInt())
          .arg(getParameterValue(MsRunReadConfigParameter::
                                   TimsFrameIonMobScanIndexEnd)
                 .toUInt());
    }

  if(!getParameterValue(MsRunReadConfigParameter::
                          TimsFrameIonMobOneOverK0Begin)
        .isNull())
    {
      text += QString("Mobility 1/K0 range: [%1-%2]\n")
                .arg(getParameterValue(
                       MsRunReadConfigParameter::
                         TimsFrameIonMobOneOverK0Begin)
                       .toDouble())
                .arg(getParameterValue(
                       MsRunReadConfigParameter::
                         TimsFrameIonMobOneOverK0End)
                       .toDouble());
    }

  if(!getParameterValue(
        MsRunReadConfigParameter::MzRangeBegin)
        .isNull())
    {
      text += QString("m/z range: [%1-%2]\n")
                .arg(getParameterValue(
                       MsRunReadConfigParameter::MzRangeBegin)
                       .toDouble())
                .arg(getParameterValue(
                       MsRunReadConfigParameter::MzRangeEnd)
                       .toDouble());
    }

  if(!getParameterValue(
        MsRunReadConfigParameter::TimsFrameMzIndexMergeWindow)
        .isNull())
    {
      text +=
        QString("m/z merge window %1\n")
          .arg(getParameterValue(MsRunReadConfigParameter::
                                   TimsFrameMzIndexMergeWindow)
                 .toUInt());
    }

  return text;
}
} // namespace pappso
