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


/////////////////////// Qt includes
#include <QWidget>

/////////////////////// QCustomPlot


/////////////////////// pappsomspp includes
#include <pappsomspp/widget/plotwidget/baseplotwidget.h>
#include <pappsomspp/processing/combiners/mzintegrationparams.h>


/////////////////////// Local includes
#include "ui_BasePlotCompositeWidget.h"
#include "../nongui/MsRunDataSet.hpp"
#include "../nongui/ProcessingFlow.hpp"
#include "../nongui/AnalysisPreferences.hpp"
#include "MzIntegrationParamsDlg.hpp"


namespace MsXpS
{
namespace minexpert
{

class BasePlotWnd;
class MsFragmentationSpecDlg;
class ProcessingFlowViewerDlg;


enum class NewTraceHandlingMethod
{
  NOT_SET = 0,
  NEW_PLOT,
  REPLACE,
  OVERLAY,
  PLUS_COMBINE,
  MINUS_COMBINE,
  LAST,
};

enum class TraceCombinationSign
{
  NOT_SET = 0,
  MINUS,
  PLUS,
};

// The BasePlotCompositeWidget class is aimed at implementing all the basic
// features that are required to plot any kind of QCustomPlot-based plots, like
// QCPGraph_s or QCPColorMap_s. Since all these plots all derive from
// QCPAbstractPlottable, we can develop a plot widget hierarchy that manages a
// lot of these plots' functionalities into the base class.
class BasePlotCompositeWidget : public QWidget
{
  Q_OBJECT

  friend class BasePlotWnd;

  public:
  explicit BasePlotCompositeWidget(QWidget *parent,
                                   const QString &x_axis_label,
                                   const QString &y_axis_label);

  virtual ~BasePlotCompositeWidget();

  BasePlotWnd *getParentWnd();
  BasePlotWnd *getParent();

  virtual void
  msFragmentationSpecReady(const MsFragmentationSpec &ms_fragmentation_spec);
  void setMzIntegrationParams(
    const pappso::MzIntegrationParams &mz_integration_params);

  public slots:

  virtual void lastCursorHoveredPoint(const QPointF &pointf);

  virtual void plotRangesChanged(const pappso::BasePlotContext &context);
  void xAxisMeasurement(const pappso::BasePlotContext& context);

  virtual void plotWidgetKeyPressEvent(const pappso::BasePlotContext &context);
  virtual void
  plotWidgetKeyReleaseEvent(const pappso::BasePlotContext &context);
  virtual void
  plotWidgetMouseReleaseEvent(const pappso::BasePlotContext &context);
  virtual void plottableSelectionChanged(QCPAbstractPlottable *plottable_p,
                                         bool is_selected);

  void
  mzIntegrationParamsChanged(pappso::MzIntegrationParams mz_integration_params);

  virtual void newTicIntensityCalculated(double tic_intensity, const QColor &color) const;
  virtual void resetTicIntensity();

  pappso::MzIntegrationParams
  getMzIntegrationParams(const QCPAbstractPlottable *plottable_p);
  void msFragmentationSpecChanged(MsFragmentationSpec ms_fragmentation_spec);

  pappso::FilterNameInterfaceCstSPtr
  filter(const QString filter_name,
         const QCPAbstractPlottable *plottable_p) const;

  void pinDown(bool push_pinned);
  bool isPinnedDown() const;

  virtual const pappso::BasePlotWidget *getPlotWidget() const;

  virtual ProcessingFlow
  getProcessingFlowForPlottable(const QCPAbstractPlottable *plottable_p) const;
  virtual ProcessingFlow *
  getProcessingFlowPtrForPlottable(const QCPAbstractPlottable *plottable_p);

  virtual void
  removePlottableProcessingFlowMapItem(const QCPAbstractPlottable *plottable_p);

  virtual MsRunDataSetCstSPtr getMsRunDataSetCstSPtrForPlottable(
    const QCPAbstractPlottable *plottable_p) const;

  QCPAbstractPlottable *plottableToBeUsedAsIntegrationSource() const;
  QCPAbstractPlottable *firstPlottable() const;
  QList<QCPAbstractPlottable *>
  plottablesToBeUsedAsIntegrationDestination() const;

  void mainMenuPushButtonClicked();
  void showMsFragmentationSpecDlg();
  void showMzIntegrationParamsDlg();

  void redrawBackground(bool has_focus);

  bool savePlotToPdfFile(const QString &file_name,
                         bool no_cosmetic_pen,
                         int width,
                         int height,
                         const QString &pdf_creator,
                         const QString &title) const;

  bool savePlotToSvgFile(const QString &file_name);

  bool saveSvgPlotToClipboard();
  bool saveRasterPlotToClipboard();

  bool savePlotToPngFile(const QString &file_name,
                         int width,
                         int height,
                         int scale,
                         int quality = 100) const;

  bool savePlotToJpgFile(const QString &file_name,
                         int width,
                         int height,
                         int scale,
                         int quality = 100) const;

  std::pair<int, int> computePlotSize(std::pair<int, int> requested,
                                      std::pair<int, int> actual) const;

  void showProcessingFlow();

  void resetPlotRangesHistory();

  QString getAnalysisStanza();
  QString craftAnalysisStanza(const pappso::BasePlotContext &context);

  void setPlottingColor(QCPAbstractPlottable *plottable_p, const QColor &color);
  void setSampleNameColor(const QColor &color);

  void msLevelValueChanged(int value);

  signals:

  void plotWidgetMouseReleaseEventSignal(QMouseEvent *event);

  void plotRangesChangedSignal(const pappso::BasePlotContext &context);

  protected:
  NewTraceHandlingMethod m_newTraceHandlingMethod =
    NewTraceHandlingMethod::NEW_PLOT;

  // This is the plot widget that is immediately derived from QCustomPlot, it is
  // not a composite widget it is a QCustomPlot-derived widget in which I coded
  // all the specific behaviour we need to work with trace of different types:
  // tic chromatograms, mass spectra, drift spectra...
  pappso::BasePlotWidget *mp_plotWidget = nullptr;

  BasePlotWnd *mp_parentWnd = nullptr;

  QString m_axisLabelX;
  QString m_axisLabelY;

  mutable double m_lastTicIntensity = 0;

  MsFragmentationSpec m_msFragmentationSpec;
  MsFragmentationSpecDlg *mp_msFragmentationSpecifDlg = nullptr;

  MzIntegrationParamsDlg *mp_mzIntegrationParamsDlg = nullptr;

  ProcessingFlowViewerDlg *mp_processingFlowViewerDlg = nullptr;

  Ui::BasePlotCompositeWidget m_ui;

  //! Color used for the background of unfocused plot.
  QColor m_unfocusedColor = QColor("lightgray");
  //! Color used for the background of unfocused plot.
  QBrush m_unfocusedBrush = QBrush(m_unfocusedColor);

  //! Color used for the background of focused plot.
  QColor m_focusedColor = QColor(Qt::transparent);
  //! Color used for the background of focused plot.
  QBrush m_focusedBrush = QBrush(m_focusedColor);

  //! Key code of the last keyboard key being pressed.
  int m_plotWidgetPressedKeyCode;

  //! Key code of the last keyboard key being released.
  int m_plotWidgetReleasedKeyCode;

  // We can have as many graphs (plottable) as necessary in the
  // QCustomPlot-derived plot widget. Each graph will have its own "raison
  // d'être", that is, its own ProcessingFlow. To connect back any graph to the
  // matching MsRunDataSet, the ProcessingFlow instance that is related to it
  // via this map contains a pointer to that ms run data set, which in turn
  // contains all that is necessary to get to the original file, the ms run id
  // and the ms run reader.
  std::map<QCPAbstractPlottable *, ProcessingFlow> m_plottableProcessingFlowMap;

  QMenu *mp_mainMenu         = nullptr;
  QMenu *mp_plotGraphicsMenu = nullptr;

  virtual void setupWidget() = 0;
  virtual void createMainMenu();
  QFile *getAnalysisFilePtr();
  AnalysisPreferences *getAnalysisPreferences();

  QString m_analysisStanza;
};


} // namespace minexpert

} // namespace MsXpS
