/* BEGIN software license
 *
 * msXpertSuite - mass spectrometry software suite
 * -----------------------------------------------
 * Copyright(C) 2009,...,2019 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
 */


#pragma once

/////////////////////// StdLib includes
#include <map>
#include <vector>


/////////////////////// Qt includes
#include <QString>
#include <QDateTime>


/////////////////////// pappsomspp includes
#include <pappsomspp/core/processing/combiners/mzintegrationparams.h>
#include <pappsomspp/core/processing/combiners/selectionpolygon.h>
#include <pappsomspp/core/processing/combiners/integrationscopebase.h>

/////////////////////// Local includes
#include "ProcessingType.hpp"
// #include "ProcessingFlow.hpp"
#include "MsFragmentationSpec.hpp"

namespace MsXpS
{
namespace MineXpert
{

class ProcessingStep
{

  friend struct ProcessingStepCompare;

  friend class ProcessingFlow;

  public:
  ProcessingStep();

  ProcessingStep(const MsFragmentationSpec &ms_fragmentation_spec);

  ProcessingStep(const ProcessingStep &other);

  virtual ~ProcessingStep();

  ProcessingStep &operator=(const ProcessingStep &other);

  void setProcessingType(const QString &processing_type);
  void setProcessingType(const ProcessingType &processing_type);
  ProcessingType getProcessingType() const;

  void setSrcProcessingType(pappso::Enums::Axis axis,
                            const ProcessingType &processing_type);
  void setSrcProcessingType(pappso::Enums::Axis axis,
                            const QString &processing_type);
  ProcessingType getSrcProcessingType(pappso::Enums::Axis axis) const;

  void setDestProcessingType(const ProcessingType &processing_type);
  void setDestProcessingType(const QString &processing_type);
  ProcessingType getDestProcessingType() const;

  void setIntegrationScope(
    pappso::IntegrationScopeBaseCstSPtr integration_scope_csp);
  pappso::IntegrationScopeBaseCstSPtr getIntegrationScope() const;
  void resetIntegrationScope();

  void setDataKind(pappso::Enums::Axis axis, pappso::Enums::DataKind data_kind);
  pappso::Enums::DataKind getDataKind(pappso::Enums::Axis axis) const;

  bool getRangeForAxis(pappso::Enums::Axis axis,
                       double &range_start,
                       double &range_end) const;
  bool getRangeForAxisX(double &range_start, double &range_end) const;
  bool getRangeForAxisY(double &range_start, double &range_end) const;

  void setMzIntegrationParams(
    const pappso::MzIntegrationParams &mz_integration_params);

  void
  setMzIntegrationParams(pappso::MzIntegrationParams *mz_integration_params_p);

  const pappso::MzIntegrationParams *getMzIntegrationParams() const;

  void setMsFragmentationSpec(const MsFragmentationSpec &fragmentation_spec);
  MsFragmentationSpec getMsFragmentationSpec() const;
  MsFragmentationSpec *getMsFragmentationSpecPtr();
  size_t getMsLevel() const;

  bool hasValidFragmentationSpec() const;

  bool isValid() const;

  bool srcMatches(std::bitset<32> bit_set) const;
  bool srcMatches(const ProcessingType &processing_type) const;
  bool srcMatches(const QString &brief_desc) const;

  bool destMatches(std::bitset<32> bit_set) const;
  bool destMatches(const ProcessingType &processing_type) const;
  bool destMatches(const QString &brief_desc) const;

  QString toString(int offset = 0, const QString &spacer = QString()) const;

  protected:
  QDateTime m_dateAndTime;

  ProcessingType m_xSrcType = ProcessingType("NOT_SET");
  ProcessingType m_ySrcType = ProcessingType("NOT_SET");

  ProcessingType m_destType = ProcessingType("NOT_SET");

  pappso::IntegrationScopeBaseCstSPtr msp_integrationScope = nullptr;

  // We need to know which kind of data are along the axes that make the
  // integration scope..
  pappso::Enums::DataKind m_xAxisDataKind = pappso::Enums::DataKind::unset;
  pappso::Enums::DataKind m_yAxisDataKind = pappso::Enums::DataKind::unset;

  // When integrating to m/z spectra we need to configure the integration. This
  // class instance allows to do so. Because not all the specs need such
  // parameters, we do not make a member variable of that type, but we provide a
  // means to store a pointer.
  pappso::MzIntegrationParams *mpa_mzIntegrationParams = nullptr;

  // The ms fragmentation pattern is optional here. If non-nullptr it is
  // considered to be enforceable.
  MsFragmentationSpec *mpa_msFragmentationSpec = nullptr;
};

typedef std::shared_ptr<ProcessingStep> ProcessingStepSPtr;
typedef std::shared_ptr<const ProcessingStep> ProcessingStepCstSPtr;

struct ProcessingStepCompare
{
  bool
  operator()(const ProcessingStep &a, const ProcessingStep &b) const
  {
    // The data and time has a second granulometry. That should be sufficient
    // to ascertain if a and be are identical.

    return a.m_dateAndTime < b.m_dateAndTime;
  }
};


} // namespace MineXpert

} // namespace MsXpS
