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


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

namespace msXpSmineXpert
{


//! The DataPlotWidgetRelation class provides a data/widget relation.
/*!

  The DataPlotWidgetRelation class maintain logical links between various
  widgets and data set in the mineXpert program. This feature is essential in
  mineXpert because the plot widgets that might be created during a data
  mining session need to maintain logical links. For example\:

  - open a new file, the TIC chromatogram plot will be automatically displayed
  along with the color map widget (if the data are for an ion mobility mass
  spectrometry experiment).

  - make an integration from the TIC chromatogram plot to a mass spectrum. The
  new plot widget that is created to display the mass spectrum needs to know
  when it came\: that is, from which plot widget it arrived.

  - make an integration from the mass spectrum to a drift spectrum. A new plot
  widget is created to display the new drift spectrum.

  - make an integration from the drift spectrum to the TIC chromatogram (a XIC
  operation, in fact). A new TIC chromatogram plot widget is created to
  display the newly generated data.

  - do all the operations above again but with a new file.

  After all the operations above, there will be in the mineXpert application
  eight (10) plot widgets. In all the examples above, the plot widget in which
  the integration is started is the origin plot widget (\c
  mp_originPlotWidget) and the widget that is created to display the new data
  is the target plot widget (\c mp_targetPlotWidget).

  Now the user closes the first TIC chromatogram, that was created right after
  the data load from the first file. All the other plot widgets related to
  that specific plot widget will need to be removed. This is made possible
  because the DataPlotWidgetRelation  class maintains a relation between
  various widget.

*/
class DataPlotWidgetRelation : public QObject
{
  Q_OBJECT

  friend class DataPlotWidgetRelationer;

  private:
  //! Pointer to the MassSpecDataSet instance holding the mass data.
  const MassSpecDataSet *mp_massSpecDataSet = Q_NULLPTR;

  //! Pointer to the origin AbstractPlotWidget instance.
  AbstractPlotWidget *mp_originPlotWidget = Q_NULLPTR;

  //! Pointer to the target AbstractPlotWidget instance.
  AbstractPlotWidget *mp_targetPlotWidget = Q_NULLPTR;

  //! Pointer to the QListWidgetItem instance that represents the origin plot
  //! widget.
  QListWidgetItem *mp_openSpectraListWidgetItem = Q_NULLPTR;

  public:
  DataPlotWidgetRelation();
  ~DataPlotWidgetRelation();

  const AbstractPlotWidget *originPlotWidget() const;
  const AbstractPlotWidget *targetPlotWidget() const;
  const QListWidgetItem *openSpectraListWidgetItem() const;

  QString asText();
};

//! The DataPlotWidgetRelation class provides a data/widget relation manager.
/*!

  The DataPlotWidgetRelationer class is in charge of maintaining logical links

*/
class DataPlotWidgetRelationer : public QObject
{
  Q_OBJECT

  friend class DataPlotWidgetRelation;

  public:
  QList<DataPlotWidgetRelation *> m_relationList;

  DataPlotWidgetRelationer();
  ~DataPlotWidgetRelationer();

  Q_INVOKABLE QString asText();

  void newRelation(const MassSpecDataSet *massSpecDataSet,
                   AbstractPlotWidget *origin,
                   AbstractPlotWidget *target,
                   QListWidgetItem *widgetItem);

  void removeRelation(DataPlotWidgetRelation *relation);
  void clearRelation(DataPlotWidgetRelation *relation);

  void getRelationsByOrigin(AbstractPlotWidget *origin,
                            QList<DataPlotWidgetRelation *> *list);
  void
  getRelationsByOriginRecursive(AbstractPlotWidget *origin,
                                QList<DataPlotWidgetRelation *> *list) const;

  void getRelationsByTarget(AbstractPlotWidget *target,
                            QList<DataPlotWidgetRelation *> *list);
  void getRelationsByData(const MassSpecDataSet *massSpecDataSet,
                          QList<DataPlotWidgetRelation *> *list);
  void getRelationsByOpenSpectraListWidgetItem(
    QListWidgetItem *item, QList<DataPlotWidgetRelation *> *list);

  AbstractPlotWidget *origin(AbstractPlotWidget *target);
  AbstractPlotWidget *origin(const MassSpecDataSet *massSpecDataSet);
  AbstractPlotWidget *origin(QListWidgetItem *item);

  int targets(AbstractPlotWidget *origin, QList<AbstractPlotWidget *> *list);
  int targetsRecursive(AbstractPlotWidget *origin,
                       QList<AbstractPlotWidget *> *list);

  bool isLeafPlotWidget(AbstractPlotWidget *widget,
                        DataPlotWidgetRelation **pp_relation);

  QListWidgetItem *listWidgetItem(AbstractPlotWidget *origin);

  AbstractPlotWidget *rootPlotWidget(AbstractPlotWidget *target,
                                     DataPlotWidgetRelation **pp_rootRelation);

  int removeOrigin(AbstractPlotWidget *origin);
};

} // namespace msXpSmineXpert
