/* BEGIN software license
 *
 * msXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright(C) 2009,...,2018 Filippo Rusconi
 *
 * http://www.msxpertsuite.org
 *
 * This file is part of the msXpertSuite project.
 *
 * The msXpertSuite project is the successor of the massXpert project. This
 * project now includes various independent modules:
 *
 * - massXpert, model polymer chemistries and simulate mass spectrometric data;
 * - mineXpert, a powerful TIC chromatogram/mass spectrum viewer/miner;
 *
 * This program 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.
 *
 * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
 *
 * END software license
 */


/////////////////////// Qt includes
#include <QDebug>

/////////////////////// Local includes
#include <minexpert/nongui/MzIntegrationParams.hpp>


int mzIntegrationParamsMetaTypeId =
  qRegisterMetaType<msXpSmineXpert::MzIntegrationParams>(
    "msXpSmineXpert::MzIntegrationParams");


namespace msXpSmineXpert
{


MzIntegrationParams::MzIntegrationParams()
{
}


MzIntegrationParams::MzIntegrationParams(msXpS::BinningType binningType,
                                         double binSize,
                                         msXpS::MassToleranceType binSizeType,
                                         bool applyMzShift,
                                         bool removeZeroValDataPoints)
  : m_binningType{binningType},
    m_binSize{binSize},
    m_binSizeType{binSizeType},
    m_applyMzShift{applyMzShift},
    m_removeZeroValDataPoints{removeZeroValDataPoints}
{
}


MzIntegrationParams::MzIntegrationParams(const MzIntegrationParams &other)
{
  m_binningType = other.m_binningType;

  m_binSize                 = other.m_binSize;
  m_binSizeType             = other.m_binSizeType;
  m_applyMzShift            = other.m_applyMzShift;
  m_removeZeroValDataPoints = other.m_removeZeroValDataPoints;

  m_savGolParams.nL             = other.m_savGolParams.nL;
  m_savGolParams.nR             = other.m_savGolParams.nR;
  m_savGolParams.m              = other.m_savGolParams.m;
  m_savGolParams.lD             = other.m_savGolParams.lD;
  m_savGolParams.convolveWithNr = other.m_savGolParams.convolveWithNr;

  m_applySavGolFilter = other.m_applySavGolFilter;
}


MzIntegrationParams::MzIntegrationParams(const SavGolParams &savGolParams)
{
  initializeSavGolParams(savGolParams);
}


MzIntegrationParams::~MzIntegrationParams()
{
}


void
MzIntegrationParams::initializeSavGolParams(
  int nL, int nR, int m, int lD, bool convolveWithNr)
{
  m_savGolParams.nL             = nL;
  m_savGolParams.nR             = nR;
  m_savGolParams.m              = m;
  m_savGolParams.lD             = lD;
  m_savGolParams.convolveWithNr = convolveWithNr;
}


void
MzIntegrationParams::initializeSavGolParams(const SavGolParams &params)
{
  m_savGolParams.nL             = params.nL;
  m_savGolParams.nR             = params.nR;
  m_savGolParams.m              = params.m;
  m_savGolParams.lD             = params.lD;
  m_savGolParams.convolveWithNr = params.convolveWithNr;
}


MzIntegrationParams &
MzIntegrationParams::operator=(const MzIntegrationParams &other)
{
  return initialize(other);
}


MzIntegrationParams &
MzIntegrationParams::initialize(const MzIntegrationParams &other)
{
  if(this == &other)
    return *this;

  m_binningType             = other.m_binningType;
  m_binSize                 = other.m_binSize;
  m_binSizeType             = other.m_binSizeType;
  m_applyMzShift            = other.m_applyMzShift;
  m_removeZeroValDataPoints = other.m_removeZeroValDataPoints;

  initializeSavGolParams(other.m_savGolParams);

  m_applySavGolFilter = other.m_applySavGolFilter;

  return *this;
}

//! Reset the instance to default values.
void
MzIntegrationParams::reset()
{
  m_binningType             = msXpS::BinningType::BINNING_TYPE_NONE;
  m_binSize                 = qSNaN();
  m_binSizeType             = msXpS::MassToleranceType::MASS_TOLERANCE_NONE;
  m_applyMzShift            = false;
  m_removeZeroValDataPoints = false;

  m_savGolParams.nL             = 15;
  m_savGolParams.nR             = 15;
  m_savGolParams.m              = 4;
  m_savGolParams.lD             = 0;
  m_savGolParams.convolveWithNr = false;

  m_applySavGolFilter = false;
}


bool
MzIntegrationParams::isValid()
{
  int errors = 0;

  if(m_binningType)
    {
      errors += (qIsNaN(m_binSize) ? 1 : 0);
      errors +=
        (m_binSizeType == msXpS::MassToleranceType::MASS_TOLERANCE_NONE ? 1
                                                                        : 0);
    }

  if(errors)
    qDebug()
      << __FILE__ << __LINE__ << __FUNCTION__ << "()"
      << "The m/z integration parameters are not valid or do not apply...";

  return !errors;
}


QString
MzIntegrationParams::asText() const
{
  QString text = "m/z integration parameters:\n";

  text.append(QString::asprintf(
    "\tBinning type: %s\n",
    msXpS::binningTypeMap.value(m_binningType).toLatin1().data()));

  // Only provide the details relative to the ARBITRARY binning type.

  if(m_binningType == msXpS::BinningType::BINNING_TYPE_ARBITRARY)
    {
      text.append(QString::asprintf(
        "\tBin nominal size: %.6f\n"
        "\tBin size type: %s\n",
        m_binSize,
        msXpS::massToleranceTypeMap.value(m_binSizeType).toLatin1().data()));
    }

  // Now other data that are independent of the bin settings.

  text.append(
    QString::asprintf("\tApply m/z shift: %s\n"
                      "\tRemove 0-val data points: %s\n",
                      (m_applyMzShift ? "true" : "false"),
                      (m_removeZeroValDataPoints ? "true" : "false")));

  // Finally the Savitzy-Golay parameters (if requested)

  if(m_applySavGolFilter)
    {
      text.append(QString::asprintf(
        "Savitzky-Golay parameters\n"
        "nL = %d ; nR = %d ; m = %d ; lD = %d ; convolveWithNr = %s\n",
        m_savGolParams.nL,
        m_savGolParams.nR,
        m_savGolParams.m,
        m_savGolParams.lD,
        (m_savGolParams.convolveWithNr ? "true" : "false")));
    }

  return text;
}


} // namespace msXpSmineXpert
