/* 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
 */


#pragma once

///////////////////////////// Qt includes
#include <QtCore/QVariant>
#include <QtWidgets/QAction>
#include <QtWidgets/QApplication>
#include <QtWidgets/QButtonGroup>
#include <QtWidgets/QGridLayout>
#include <QtWidgets/QHeaderView>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QMenuBar>
#include <QtWidgets/QStatusBar>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>
#include <QFile>


///////////////////////////// Local includes
#include <minexpert/gui/AbstractPlotWidget.hpp>
#include <minexpert/nongui/MassSpecDataSet.hpp>


namespace msXpSmineXpert
{

class AnalysisPreferences;
class MzIntegrationParams;
class MzIntegrationParamsWnd;


//! The AbstractMultiPlotWnd class provides a base class for plot windows.
/*!

  The GUI of mineXpert is mainly based on three fundamental windows that
  display plots:

  - the mass spectrum window that displays mass spectra in plot widgets.

  - the drift spectrum window that displays drift spectra in plot widgets.

  - the tic/xic chromatogram window that displays TIC/XIC chromatograms in
  plot widgets.

  - the mz=f(dt) color map window that displays color maps in plot widget.

  This class serves as a base class for the specialized classes above.

  All the multiplot window classes (but the color map one) share the same
  pattern\: a top part of the window and a bottom part of the window. Both
  parts are separated by a sliding splitter widget. The top part of the window
  contains a single plot widget in which multiple graphs can be plotted (thus
  the multigraph qualificator). The bottom part of the window has as many
  plots are necessary. These plot widgets can only contain a single graph
  (thus the monograph qualificator). Each monograph plot widget has its graph
  replicated in the multigraph plot widget.

  This dual plotting system allows for two views of the plots: one uncluttered
  monograph view for each plot (bottom, as many plot widgets as necessary) and
  one top plot widget with all the graphs plotted one on top of the other,
  which allows for easy comparison of the graph).

*/
class AbstractMultiPlotWnd : public QMainWindow
{
  Q_OBJECT

  friend class AbstractPlotWidget;

  protected:
  ////// Setting up the window layout.

  QWidget *mp_centralWidget               = Q_NULLPTR;
  QGridLayout *mp_centralWidgetGridLayout = Q_NULLPTR;
  QSplitter *mp_splitter                  = Q_NULLPTR;
  QScrollArea *mp_scrollArea              = Q_NULLPTR;

  QWidget *mp_scrollAreaWidgetContents               = Q_NULLPTR;
  QGridLayout *mp_scrollAreaWidgetContentsGridLayout = Q_NULLPTR;
  QVBoxLayout *mp_scrollAreaVBoxLayout               = Q_NULLPTR;

  QLabel *mp_statusBarLabel                 = Q_NULLPTR;
  QProgressBar *mp_statusBarProgressBar     = Q_NULLPTR;
  QPushButton *mp_statusBarCancelPushButton = Q_NULLPTR;

  QMenuBar *mp_menubar     = Q_NULLPTR;
  QStatusBar *mp_statusbar = Q_NULLPTR;
  QToolBar *mp_toolbar     = Q_NULLPTR;

  QAction *mp_lockXRangeAct = Q_NULLPTR;
  bool m_lockXRange         = false;

  QAction *mp_lockYRangeAct = Q_NULLPTR;
  bool m_lockYRange         = false;

  QAction *mp_plotHelperAct = Q_NULLPTR;

  //! List of all the monograph plot widgets.
  QList<AbstractPlotWidget *> m_plotWidgetList;

  //! Pointer to the plot widget that was focused last.
  QWidget *mp_lastFocusedPlotWidget = Q_NULLPTR;

  //! Map relating any monograph plot widget and the corresponding graph in the
  //! multigraph plot widget.
  /*!

    Because it will be necessary to relate any given plot widget in the bottom
    part of the window to its corresponding graph in the multigraph plot
    widget (in the top part of the window), we register that pair in this map.

*/
  QMap<AbstractPlotWidget *, QCPGraph *> m_plotWidgetGraphMap;

  //! Name associated to \c this window instance.
  QString m_name = "NOT_SET";
  Q_PROPERTY(QString m_name WRITE setName READ name);

  //! Description associated to \c this window instance.
  QString m_desc = "NOT_SET";
  Q_PROPERTY(QString m_desc WRITE setDesc READ desc);

  //! Tells if the running calculation should be cancelled.
  bool m_isOperationCancelled = false;

  //! Pointer to the file in which to store the analysis steps.
  QFile *mp_analysisFile = Q_NULLPTR;

  //! Pointer to the AnalysisPreferences instance.
  AnalysisPreferences *mp_analysisPreferences = Q_NULLPTR;

  //! Widget in which to set the MZ integration parameters
  MzIntegrationParamsWnd *mp_mzIntegrationParamsWnd = Q_NULLPTR;

  public:
  AbstractMultiPlotWnd(QWidget *parent,
                       const QString &name,
                       const QString &desc);
  virtual ~AbstractMultiPlotWnd();

  void writeSettings();
  void readSettings();

  void closeEvent(QCloseEvent *event) override;

  bool setupWindow();

  virtual AbstractPlotWidget *
  addPlotWidget(const QVector<double> &keyVector,
                const QVector<double> &valVector,
                const QString &desc                    = QString(),
                const QColor &color                    = Qt::black,
                const MassSpecDataSet *massSpecDataSet = Q_NULLPTR,
                bool isMultiGraph                      = false) = 0;

  AbstractPlotWidget *plotWidgetAt(int index);
  int plotWidgetIndex(AbstractPlotWidget *plotWidget);

  QCPGraph *multiGraph(AbstractPlotWidget *plotWidget);
  AbstractPlotWidget *monoGraphPlot(QCPGraph *graph);

  virtual void toggleMultiGraph(AbstractPlotWidget *widget);
  virtual void showMultiGraph(AbstractPlotWidget *widget);
  virtual void hideMultiGraph(AbstractPlotWidget *widget);

  void setMzIntegrationParamsWnd(MzIntegrationParamsWnd *wnd);
  void updateMzIntegrationParams(MzIntegrationParams params,
                                 const QColor &color = QColor());
  void mzIntegrationParamsChanged(MzIntegrationParams params);

  void removeMultiGraph(AbstractPlotWidget *widget);

  bool delistPlotWidget(AbstractPlotWidget *plotWidget);

  virtual void clearPlots();

  void updateFeedback(QString msg,
                      int currentValue,
                      bool setVisible = true,
                      int logType     = LogType::LOG_TO_CONSOLE,
                      int startValue  = 1,
                      int endValue    = 1);

  void updateStatusBar(QString msg);

  void lockXRangeToggle(bool checked);
  void lockYRangeToggle(bool checked);

  void keyReleaseEvent(QKeyEvent *event) override;
  virtual void emitReplotSignal(QCPRange xAxisRange, QCPRange yAxisRange);
  virtual void emitRedrawPlotBackground(QWidget *focusedPlotWidget);

  void setAnalysisPreferences(AnalysisPreferences *preferences);
  const AnalysisPreferences *analysisPreferences() const;

  void setAnalysisFile(QFile *analysisFile);

  void cancelPushButtonClicked();

  public slots:
  void setName(QString name);
  QString name();

  void setDesc(QString desc);
  QString desc();

  signals:
  void aboutToDestroyPlotWidget(AbstractPlotWidget *widget);

  void
  replotWithAxisRange(QCPRange xAxisRange, QCPRange yAxisRange, int whichAxis);

  void redrawPlotBackground(QWidget *focusedPlotWidget);
  void recyclePlottingColor(QColor color);
  void cancelOperationSignal();
  void showHelpSummarySignal();
};


} // namespace msXpSmineXpert
