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


/////////////////////// Local includes
#include <minexpert/gui/DataPlotWidgetRelation.hpp>


namespace msXpSmineXpert
{

//! Construct a DataPlotWidgetRelation instance.
DataPlotWidgetRelation::DataPlotWidgetRelation()
{
}

//! Destruct a DataPlotWidgetRelation instance.
DataPlotWidgetRelation::~DataPlotWidgetRelation()
{
}


//! Return the origin plot widget.
const AbstractPlotWidget *
DataPlotWidgetRelation::originPlotWidget() const
{
  return mp_originPlotWidget;
}


//! Return the target plot widget.
const AbstractPlotWidget *
DataPlotWidgetRelation::targetPlotWidget() const
{
  return mp_targetPlotWidget;
}


//! Return the list widget item that represents the origin plot wigdet.
/*!

  \sa OpenSpectraDlg

*/
const QListWidgetItem *
DataPlotWidgetRelation::openSpectraListWidgetItem() const
{
  return mp_openSpectraListWidgetItem;
}


//! Craft a textual representation of the relation members.
QString
DataPlotWidgetRelation::asText()
{
  QString text;

  text += QString("Relation: 0x%2 --")
            .arg((quintptr)this, QT_POINTER_SIZE * 2, 16, QChar('0'));

  text +=
    QString("%1: 0x%2 --")
      .arg("mp_massSpecDataSet")
      .arg((quintptr)mp_massSpecDataSet, QT_POINTER_SIZE * 2, 16, QChar('0'));

  text +=
    QString("%1: 0x%2 --")
      .arg("mp_originPlotWidget")
      .arg((quintptr)mp_originPlotWidget, QT_POINTER_SIZE * 2, 16, QChar('0'));

  text +=
    QString("%1: 0x%2 --")
      .arg("mp_targetPlotWidget")
      .arg((quintptr)mp_targetPlotWidget, QT_POINTER_SIZE * 2, 16, QChar('0'));

  text += QString("%1: 0x%2 --")
            .arg("mp_openSpectraListWidgetItem")
            .arg((quintptr)mp_openSpectraListWidgetItem,
                 QT_POINTER_SIZE * 2,
                 16,
                 QChar('0'));

  return text;
}


//! Construct an empty DataPlotWidgetRelationer instance.
DataPlotWidgetRelationer::DataPlotWidgetRelationer()
{
}


//! Destruct \c this DataPlotWidgetRelationer instance.
/*!

  All the allocated DataPlotWidgetRelation instances are deleted.

*/
DataPlotWidgetRelationer::~DataPlotWidgetRelationer()
{
  // Free all the relations that were allocated on the heap.
  for(int iter = 0; iter < m_relationList.size(); ++iter)
    delete m_relationList.at(iter);
}


//! Craft a textual representation of all the members of \c this instance.
QString
DataPlotWidgetRelationer::asText()
{
  QString text;

  for(int iter = 0; iter < m_relationList.size(); ++iter)
    {
      text += m_relationList.at(iter)->asText();
      text += "\n";
    }

  return text;
}


//! Allocate a new DataPlotWidgetRelation and append it to \c this instance.
/*!

  \param massSpecDataSet pointer to the MassSpecDataSet instance storing all the
  mass data. Cannot be Q_NULLPTR.

  \param orig origin plot widget. Can be Q_NULLPTR if the relation is to
  document the root plot widget, in which case there is no actual relation,
  and this is materialized by the fact that the origin pointer is Q_NULLPTR.

  \param target target plot widget. Cannot be Q_NULLPTR. Indeed, as soon as a
  relation is created, it needs to have at least one plot widget. When the
  root plot widget is created, right after having read the data from file, for
  example, that plot widget is assigned to \p mp_targetPlotWidget.

  \param widgetItem list widget item that represents the origin plot widget.

*/
void
DataPlotWidgetRelationer::newRelation(const MassSpecDataSet *massSpecDataSet,
                                      AbstractPlotWidget *orig,
                                      AbstractPlotWidget *target,
                                      QListWidgetItem *widgetItem)
{
  // Only two data members cannot be Q_NULLPTR when calling this function:
  if(massSpecDataSet == Q_NULLPTR || target == Q_NULLPTR)
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

  DataPlotWidgetRelation *p_relation = new DataPlotWidgetRelation;

  p_relation->mp_massSpecDataSet           = massSpecDataSet;
  p_relation->mp_originPlotWidget          = orig;
  p_relation->mp_targetPlotWidget          = target;
  p_relation->mp_openSpectraListWidgetItem = widgetItem;

  // QString msg =
  // QString("New relation: 0x%1\n"
  //"\tmassSpecDataSet: 0x%2\n"
  //"\torigin plot widget: 0x%3\n"
  //"\ttarget plot widget: 0x%4\n"
  //"\ttarget name: %5\n")
  //.arg((quintptr)p_relation, QT_POINTER_SIZE * 2, 16, QChar('0'))
  //.arg((quintptr)p_relation->mp_massSpecDataSet, QT_POINTER_SIZE * 2, 16,
  //QChar('0')) .arg((quintptr)p_relation->mp_originPlotWidget, QT_POINTER_SIZE
  //* 2, 16, QChar('0')) .arg((quintptr)p_relation->mp_targetPlotWidget,
  //QT_POINTER_SIZE * 2, 16, QChar('0')) .arg(target->desc()); qDebug() <<
  // __FILE__ << __LINE__ << __FUNCTION__ << "()"; fprintf(stderr, "%s",
  // msg.toLatin1().data());

  m_relationList.append(p_relation);
}


#if 0
	// Returns true if the relation was updated and false if a new one was added.

	bool
		DataPlotWidgetRelationer::updateOrAddRelation(MassSpecDataSet *massSpecDataSet,
				AbstractPlotWidget *origin,
				AbstractPlotWidget *target,
				QListWidgetItem *widgetItem) {
			if (massSpecDataSet == Q_NULLPTR || origin == Q_NULLPTR || target == Q_NULLPTR)
				qFatal("Fatal error at %s@%d. Program aborted.",
						__FILE__, __LINE__);

			for (int iter = 0; iter < m_relationList.size(); ++iter) {
				DataPlotWidgetRelation *p_relation = m_relationList.at(iter);

				// We only update the relation if the target plot widget pointer is
				// Q_NULLPTR ! This is it: we had created a new relation, typically when
				// opening a new mass spec file. But the user had not had the
				// opportunity to make an integration operation, so the target is
				// Q_NULLPTR. But, eventually, such an integration would occur. Then, yes,
				// we update. Now, after the first relation object has been updated,
				// there won't be any relation object that has its target pointer with
				// value Q_NULLPTR, which means we have to actually duplicate the found
				// object and fill-in the target value.
				if (p_relation->mp_massSpecDataSet == massSpecDataSet &&
						p_relation->mp_originPlotWidget == origin &&
						p_relation->mp_targetPlotWidget == Q_NULLPTR) {
					if (widgetItem != Q_NULLPTR) {
						if (p_relation->mp_openSpectraListWidgetItem != widgetItem)
							qFatal("Fatal error at %s@%d. Program aborted.",
									__FILE__, __LINE__);
					}

					p_relation->mp_targetPlotWidget = target;
					return true;
				}
			}

			// There was no matching object with a Q_NULLPTR target value. Then we
			// need to create one.

			// First, we need to get a pointer to the QListWidgetItem.
			QListWidgetItem *item = listWidgetItem(origin);

			newRelation(massSpecDataSet, origin, target, item);

			return false;
		}
#endif


//! Remove the \p relation from the member list. \p relation is not deleted.
void
DataPlotWidgetRelationer::removeRelation(DataPlotWidgetRelation *relation)
{
  if(relation == Q_NULLPTR)
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

  if(!m_relationList.removeOne(relation))
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);
}


//! Remove the \p relation from the member list and delete it.
void
DataPlotWidgetRelationer::clearRelation(DataPlotWidgetRelation *relation)
{
  if(relation == Q_NULLPTR)
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

  // Only actually delete the relation if it was indeed found in the list
  // and removed from it.
  if(m_relationList.removeOne(relation))
    {
      delete relation;
      relation = Q_NULLPTR;
    }
  else
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);
}


//! Get all the relations the have \p origin as the origin plot widget.
/*!

  The member list of DataPlotWidgetRelation instances is iterated in and for
  each DataPlotWidgetRelation instance having \c mp_originPlotWidget identical
  to \p origin, append that instance to \p list.

  This function will allow to identify all the plot widgets that have a common
  immediate ancestor\: origin. That, is the function allows to identify
  siblings.

  \param origin origin plot widget to be searched for. Cannot be Q_NULLPTR.

  \param list list in which to append all the found relations. Cannot be
  Q_NULLPTR.

  \sa getRelationsByOriginRecursive().

*/
void
DataPlotWidgetRelationer::getRelationsByOrigin(
  AbstractPlotWidget *origin, QList<DataPlotWidgetRelation *> *list)
{
  if(origin == Q_NULLPTR || list == Q_NULLPTR)
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

  for(int iter = 0; iter < m_relationList.size(); ++iter)
    {
      DataPlotWidgetRelation *p_relation = m_relationList.at(iter);

      if(p_relation->mp_originPlotWidget == origin)
        list->append(p_relation);
    }
}


//! Get all the relations that have \p origin as the origin plot widget. Perform
//! a recursive search.
/*!

  The member list of DataPlotWidgetRelation instances is iterated in and for
  each DataPlotWidgetRelation instance having \c mp_originPlotWidget identical
  to \p origin, append that instance to \p list. The target plot widget
  stored in the iterated relations that have a matching origin plot widget
  corresponds to the siblings of \p origin (at first round). For the next
  rounds, the target plot widget is used as the origin plot widget to do a
  nested call to this functions.

  Note that there is only one reasong a matching relation would have a Q_NULLPTR
  target plot widget member: if \p origin were the root plot widget.

  Because the search is recursive, the list is searched also in such a way
  that when a DataPlotWidgetRelation instance is found, its \c
  m_targetPlotWidget is used as an origin target and this function is
  called again againt that plot widget.

  This way, all the downward relations of any given plot widget might be
  determined.

  \param origin origin plot widget to be searched for. Cannot be Q_NULLPTR.

  \param list list in which to append all the found relations. Cannot be
  Q_NULLPTR.

  \sa getRelationsByOrigin().

*/
void
DataPlotWidgetRelationer::getRelationsByOriginRecursive(
  AbstractPlotWidget *origin, QList<DataPlotWidgetRelation *> *list) const
{
  if(origin == Q_NULLPTR || list == Q_NULLPTR)
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

  QString msg =
    QString("Entering getRelationsByOriginRecursive with origin 0x%1\n")
      .arg((quintptr)origin, QT_POINTER_SIZE * 2, 16, QChar('0'));
  printf("%s", msg.toLatin1().data());

  for(int iter = 0; iter < m_relationList.size(); ++iter)
    {
      DataPlotWidgetRelation *p_relation = m_relationList.at(iter);

      printf("iter: %d relation: %s\n",
             iter,
             p_relation->asText().toLatin1().data());

      if(p_relation->mp_originPlotWidget == origin)
        {
          printf("\tmatching origin %s\n",
                 p_relation->asText().toLatin1().data());

          list->append(p_relation);

          // Because we want recursively all the targets, we can now consider
          // that this matching origin plot widget's target widget is now an
          // origin plot widget:
          if(p_relation->mp_targetPlotWidget != Q_NULLPTR)
            getRelationsByOriginRecursive(p_relation->mp_targetPlotWidget,
                                          list);
        }
    }
}


//! Get all the relations that have \p target as the target plot widget.
/*!

  The member list of DataPlotWidgetRelation instances is iterated in and for
  each DataPlotWidgetRelation instance having \c mp_targetPlotWidget identical
  to \p target, append that instance to \p list.

  \param target target plot widget to be searched for. Cannot be Q_NULLPTR.

  \param list list in which to append all the found relations. Cannot be
  Q_NULLPTR.

  \sa getRelationsByOrigin().
  \sa getRelationsByOriginRecursive().

*/
void
DataPlotWidgetRelationer::getRelationsByTarget(
  AbstractPlotWidget *target, QList<DataPlotWidgetRelation *> *list)
{
  if(target == Q_NULLPTR || list == Q_NULLPTR)
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

  for(int iter = 0; iter < m_relationList.size(); ++iter)
    {
      DataPlotWidgetRelation *p_relation = m_relationList.at(iter);

      if(p_relation->mp_targetPlotWidget == target)
        list->append(p_relation);
    }

  // FIXME, if I think correctly, by definition there can only be one and
  // only one relation that has a matching target. A given origin cannot
  // indeed, create two target having the same address in memory (pointer).

  if(list->size() > 1)
    qFatal(
      "Fatal error at %s@%d -- %s. "
      "It cannot be possible that a given target be matched by more than one "
      "relation."
      "Program aborted.",
      __FILE__,
      __LINE__,
      __FUNCTION__);
}


//! Get all the relations the have \p massSpecDataSet as the data set member.
/*!

  The member list of DataPlotWidgetRelation instances is iterated in and for
  each DataPlotWidgetRelation instance having \c mp_massSpecDataSet identical
  to \p massSpecDataSet, append that instance to \p list.

  \param massSpecDataSet massSpecDataSet to be searched for. Cannot be
  Q_NULLPTR.

  \param list list in which to append all the found relations. Cannot be
  Q_NULLPTR.

  \sa getRelationsByOrigin().
  \sa getRelationsByOriginRecursive().
  \sa getRelationsByTarget().

*/
void
DataPlotWidgetRelationer::getRelationsByData(
  const MassSpecDataSet *massSpecDataSet, QList<DataPlotWidgetRelation *> *list)
{
  if(massSpecDataSet == Q_NULLPTR || list == Q_NULLPTR)
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

  for(int iter = 0; iter < m_relationList.size(); ++iter)
    {
      DataPlotWidgetRelation *p_relation = m_relationList.at(iter);

      if(p_relation->mp_massSpecDataSet == massSpecDataSet)
        list->append(p_relation);
    }
}


//! Get all the relations the have \p item as the list widget item member.
void
DataPlotWidgetRelationer::getRelationsByOpenSpectraListWidgetItem(
  QListWidgetItem *item, QList<DataPlotWidgetRelation *> *list)
{
  if(item == Q_NULLPTR || list == Q_NULLPTR)
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

  for(int iter = 0; iter < m_relationList.size(); ++iter)
    {
      DataPlotWidgetRelation *p_relation = m_relationList.at(iter);

      if(p_relation->mp_openSpectraListWidgetItem == item)
        list->append(p_relation);
    }
}


//! Return the relation that has \p target as the target plot widget member.
/*!

  The found relation by definition will have the origin member pointing to the
  origin plot widget that gave rise to \p target.

  Note that while a single origin plot widget may give rise to multiple
  immediate target plot widgets (simply making more than one integration inside
  the same origin plot widget), a given target plot widget can only have one
  immediate origin plot widget.

*/
AbstractPlotWidget *
DataPlotWidgetRelationer::origin(AbstractPlotWidget *target)
{
  for(int iter = 0; iter < m_relationList.size(); ++iter)
    {
      DataPlotWidgetRelation *p_relation = m_relationList.at(iter);

      if(p_relation->mp_targetPlotWidget == target)
        return p_relation->mp_originPlotWidget;
    }

  return Q_NULLPTR;
}

AbstractPlotWidget *
DataPlotWidgetRelationer::origin(const MassSpecDataSet *massSpecDataSet)
{
  for(int iter = 0; iter < m_relationList.size(); ++iter)
    {
      DataPlotWidgetRelation *p_relation = m_relationList.at(iter);

      if(p_relation->mp_massSpecDataSet == massSpecDataSet)
        return p_relation->mp_originPlotWidget;
    }

  return Q_NULLPTR;
}

AbstractPlotWidget *
DataPlotWidgetRelationer::origin(QListWidgetItem *item)
{
  for(int iter = 0; iter < m_relationList.size(); ++iter)
    {
      DataPlotWidgetRelation *p_relation = m_relationList.at(iter);

      if(p_relation->mp_openSpectraListWidgetItem == item)
        return p_relation->mp_originPlotWidget;
    }

  return Q_NULLPTR;
}


int
DataPlotWidgetRelationer::targets(AbstractPlotWidget *origin,
                                  QList<AbstractPlotWidget *> *list)
{
  if(origin == Q_NULLPTR || list == Q_NULLPTR)
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

  int count = 0;

  for(int iter = 0; iter < m_relationList.size(); ++iter)
    {
      DataPlotWidgetRelation *p_relation = m_relationList.at(iter);

      if(p_relation->mp_originPlotWidget == origin)
        {
          // There might be a root plot widget that has a non-Q_NULLPTR origin
          // but
          // that has a Q_NULLPTR target, we do not return it.
          if(p_relation->mp_targetPlotWidget != Q_NULLPTR)
            {
              list->append(p_relation->mp_targetPlotWidget);
              ++count;
            }
        }
    }

  return count;
}

int
DataPlotWidgetRelationer::targetsRecursive(AbstractPlotWidget *origin,
                                           QList<AbstractPlotWidget *> *list)
{
  if(origin == Q_NULLPTR || list == Q_NULLPTR)
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

  int count = 0;

  for(int iter = 0; iter < m_relationList.size(); ++iter)
    {
      DataPlotWidgetRelation *p_relation = m_relationList.at(iter);

      if(p_relation->mp_originPlotWidget == origin)
        {
          // There might be a root plot widget that has a non-Q_NULLPTR origin
          // but
          // that has a Q_NULLPTR target, we do not return it.
          if(p_relation->mp_targetPlotWidget != Q_NULLPTR)
            {
              list->append(p_relation->mp_targetPlotWidget);
              ++count;

              // Because we are asked for a recursive search of all the
              // targets of
              // origin, we must now turn this found target into an origin:
              targetsRecursive(p_relation->mp_targetPlotWidget, list);
            }
        }
    }

  return count;
}

bool
DataPlotWidgetRelationer::isLeafPlotWidget(AbstractPlotWidget *widget,
                                           DataPlotWidgetRelation **pp_relation)
{
  if(pp_relation == Q_NULLPTR)
    qFatal(
      "Fatal error at %s@%d -- %s(). "
      "Pointer cannot be NULL."
      "Program aborted.",
      __FILE__,
      __LINE__,
      __FUNCTION__);

  // If the widget is the last of a branch, that is, it has no target
  // widget, in the sense that precisely it is only a target plot widget,
  // then we should return true.

  QList<DataPlotWidgetRelation *> relationList;
  getRelationsByOrigin(widget, &relationList);

  if(relationList.size())
    {
      // qDebug() << __FILE__ << __LINE__
      // << "The plot widget is an origin plot widget, thus not leaf.
      // Returning false.";

      return false;
    }

  // If the widget is not part of any relation as an origin, then it must be
  // part of exactly one relation as a target plot widget.
  getRelationsByTarget(widget, &relationList);

  if(relationList.size() == 1)
    {
      *pp_relation = relationList.first();

      return true;
    }
  else
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

  return false;
}

QListWidgetItem *
DataPlotWidgetRelationer::listWidgetItem(AbstractPlotWidget *origin)
{
  if(origin == Q_NULLPTR)
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

  for(int iter = 0; iter < m_relationList.size(); ++iter)
    {
      DataPlotWidgetRelation *p_relation = m_relationList.at(iter);

      if(p_relation->mp_originPlotWidget == origin)
        return p_relation->mp_openSpectraListWidgetItem;
    }

  return Q_NULLPTR;
}


AbstractPlotWidget *
DataPlotWidgetRelationer::rootPlotWidget(
  AbstractPlotWidget *target, DataPlotWidgetRelation **pp_rootRelation)
{
  if(target == Q_NULLPTR)
    qFatal(
      "Fatal error at %s@%d -- %s. "
      "Pointer cannot be Q_NULLPTR."
      "Program aborted.",
      __FILE__,
      __LINE__,
      __FUNCTION__);

  if(pp_rootRelation == Q_NULLPTR)
    qFatal(
      "Fatal error at %s@%d -- %s(). "
      "Pointer cannot be NULL."
      "Program aborted.",
      __FILE__,
      __LINE__,
      __FUNCTION__);


  // We want to go back to the root TIC chromatogram plot widget which is
  // the root ancestor of target. That root TIC chromatogram is the plot
  // that is automatically created when a mass data file is loaded. Upon
  // that creation, the relation object that is instanciated contains that
  // widget as the target plot widget and Q_NULLPTR as the origin plot widget.
  // This is how all the root origin plot widgets can be traced back.

  // QString msg =
  // QString("Entering rootPlotWidget() with target 0x%1\n"
  //"with name: %2 ")
  //.arg((quintptr)target, QT_POINTER_SIZE * 2, 16, QChar('0'))
  //.arg(target->desc());
  // printf("%s\n", msg.toLatin1().data());

  for(int iter = 0; iter < m_relationList.size(); ++iter)
    {
      DataPlotWidgetRelation *p_relation = m_relationList.at(iter);

      // printf("iterating in relation (index %d): %s\n", iter,
      // p_relation->asText().toLatin1().data());

      // If the target widget passed as parameter is indeed a target widget,
      // which means it must have an origin plot widget, then, the target
      // parameter should be found as the mp_targetPlotWidget member of a
      // relation. Test that:

      if(p_relation->mp_targetPlotWidget == target)
        {
          // printf("\tmatching target %s\n",
          // p_relation->asText().toLatin1().data());

          // By definition, if the mp_originPlotWidget member of the relation is
          // Q_NULLPTR, then we have reached to top of the plot widget hierarchy
          // and we now know that the target parameter *is* the root plot
          // widget.

          if(p_relation->mp_originPlotWidget == Q_NULLPTR)
            {
              *pp_rootRelation = p_relation;

              // printf("\tbecause origin plot widget is nullptr, return target
              // that is root plog widgt\n");

              return target;
            }

          // At this point we know we have not reached the root plot widget.
          // Simply run this function again, by considering that
          // p_relation->mp_originPlotWidget is actually a target plot widget:

          // qDebug() << __FILE__ << __LINE__ << __FUNCTION__
          //<< "Not yet found the root plot widget."
          //<< "Recursively call with the matching origin plot "
          //"widget used this time as the target widget: going one level up.";

          return rootPlotWidget(p_relation->mp_originPlotWidget,
                                pp_rootRelation);
        }
    }

  // If we are here, that means that we have gone through
  qFatal(
    "Fatal error at %s@%d -- %s. "
    "Cannot be that a plot widget has no origin."
    "Program aborted.",
    __FILE__,
    __LINE__,
    __FUNCTION__);

  return Q_NULLPTR;
}


int
DataPlotWidgetRelationer::removeOrigin(AbstractPlotWidget *origin)
{
  qDebug() << __FILE__ << __LINE__ << __FUNCTION__;

  if(origin == Q_NULLPTR)
    qFatal("Fatal error at %s@%d. Program aborted.", __FILE__, __LINE__);

  // When we remove an origin, that is, a TicChromPlotwidget for example, we
  // may have many such items because there are as many such items as there
  // were plot widgets created by integrating in the TIC chrom plot widget,
  // either once or more to MassSpec or one or more to DriftSpec, for
  // example. We need to remove all the items in m_relationList that math
  // origin.

  // Get a list of relations for which m_originPlotWidget equals the origin
  // parameter. That is, get a list of relations where we can look for
  // targets of origin.

  QList<DataPlotWidgetRelation *> list;
  getRelationsByOrigin(origin, &list);

  int count = 0;

  // Now iterate in that list and for each matching relation in the member
  // m_relationList, remove it from there.
  for(int iter = 0; iter < list.size(); ++iter)
    {
      DataPlotWidgetRelation *curRelation = list.at(iter);

      for(int jter = 0; jter < m_relationList.size(); ++jter)
        {
          if(curRelation == m_relationList.at(jter))
            {

              QString msg =
                QString(
                  "Deleting relation: 0x%1\n"
                  "\tmassSpecDataSet: 0x%2\n"
                  "\torigin plot widget: 0x%3\n"
                  "\ttarget plot widget: 0x%4.\n")
                  .arg(
                    (quintptr)curRelation, QT_POINTER_SIZE * 2, 16, QChar('0'))
                  .arg((quintptr)curRelation->mp_massSpecDataSet,
                       QT_POINTER_SIZE * 2,
                       16,
                       QChar('0'))
                  .arg((quintptr)curRelation->mp_originPlotWidget,
                       QT_POINTER_SIZE * 2,
                       16,
                       QChar('0'))
                  .arg((quintptr)curRelation->mp_targetPlotWidget,
                       QT_POINTER_SIZE * 2,
                       16,
                       QChar('0'));

              printf("%s", msg.toLatin1().data());

              delete m_relationList.takeAt(jter);

              --jter;
              ++count;
            }
        }
    }

  return count;
}


} // namespace msXpSmineXpert
