// Copyright 2021 Filippo Rusconi
// GPLv3+

#pragma once

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

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


/////////////////////// Local includes
#include "pappsomspp/export-import-config.h"
#include "../../types.h"
#include "integrationscopebase.h"

namespace pappso
{ 
 
// This class represents the case where the user draws a rhomboid in a colormap
// plot widget, with the aim of integrating data in two-dimension manner (over a
// range in the X axis and a range in the Y axis). The rhomboid typically
// would try to delineate the signal shown in a m/z vs im colormap.


// There are two kinds of rhomboid integration scopes:

/*
 *              4 +-----------+3
 *                |          |
 *              |          |
 *            |          |
 *          |          |
 *        |          |
 *       |          |
 *     |          |
 *    1+----------+2
 *     ----width---
 */

// As visible here, the fixed size of the rhomboid (using the S key in the
// plot widget) is the *horizontal* side (this is the plot context's
// m_integrationScopeRhombWidth). In this case the height of the scope is 0.

// and


/*
 *                                       +3
 *                                     . |
 *                                   .   |
 *                                 .     |
 *                               .       +2
 *                             .       .
 *                           .       .
 *                         .       .
 *                      4+       .
 *                     | |     .
 *            height   | |   .
 *                     | | .
 *                      1+
 *
 */


// In this implementation we just provide a vector of points and a
// complete set of functions that define the kind of scope depending
// on the position of the points. Note that the points are defined
// by the user of the scope according to their own logic (left to right
// and bottom to top mouse movement, for example. See the BasePlotWidget class
// for a thorough use of this kind of scope.

class PMSPP_LIB_DECL IntegrationScopeRhomb : public IntegrationScopeBase
{
  public:
  IntegrationScopeRhomb();
  explicit IntegrationScopeRhomb(const std::vector<QPointF> &points);
  explicit IntegrationScopeRhomb(const std::vector<QPointF> &points,
                                 Enums::DataKind data_kind_x,
                                 Enums::DataKind data_kind_y);
  IntegrationScopeRhomb(const IntegrationScopeRhomb &other);

  virtual ~IntegrationScopeRhomb() override;

  virtual IntegrationScopeRhomb &operator=(const IntegrationScopeRhomb &other);

  virtual std::size_t addPoint(QPointF point);

  virtual bool getPoint(QPointF &point) const override;
  virtual bool getPoints(std::vector<QPointF> &points) const override;

  virtual IntegrationScopeFeatures getTopMostPoint(QPointF &point) const override;
  virtual IntegrationScopeFeatures getTopMostPoints(std::vector<QPointF> &points) const override;
  virtual IntegrationScopeFeatures getBottomMostPoint(QPointF &point) const override;
  virtual IntegrationScopeFeatures getBottomMostPoints(std::vector<QPointF> &points) const override;

  // These functions are specific for the current implementation
  // of the IntegrationScopeRhomb, that is a rhomboid, aka a
  // skewed rectangle, with four points.
  virtual IntegrationScopeFeatures getLeftMostPoint(QPointF &point) const override;
  virtual IntegrationScopeFeatures getLeftMostPoints(std::vector<QPointF> &points) const override;
  virtual IntegrationScopeFeatures getLeftMostTopPoint(QPointF &point) const override;
  virtual IntegrationScopeFeatures getLeftMostBottomPoint(QPointF &point) const override;
  virtual IntegrationScopeFeatures getRightMostPoint(QPointF &point) const override;
  virtual IntegrationScopeFeatures getRightMostPoints(std::vector<QPointF> &points) const override;
  virtual IntegrationScopeFeatures getRightMostTopPoint(QPointF &point) const override;
  virtual IntegrationScopeFeatures getRightMostBottomPoint(QPointF &point) const override;

  virtual IntegrationScopeFeatures getWidth(double &width) const override;
  virtual IntegrationScopeFeatures getHeight(double &height) const override;
  
  virtual IntegrationScopeFeatures getRhombHorizontalSize(double &size) const override;
  virtual IntegrationScopeFeatures getRhombVerticalSize(double &size) const override;
  
  virtual bool range(Enums::Axis axis, double &start, double &end) const override;

  virtual void setDataKindX(Enums::DataKind data_kind) override;
  virtual bool getDataKindX(Enums::DataKind &data_kind) override;

  virtual void setDataKindY(Enums::DataKind data_kind) override;
  virtual bool getDataKindY(Enums::DataKind &data_kind) override;

  bool is1D() const override;
  bool is2D() const override;

  virtual bool isRectangle() const override;
  virtual bool isRhomboid() const override;

  virtual bool transpose() override;

  virtual bool contains(const QPointF &point) const override;

  virtual QString toString() const override;

  virtual void reset() override;

  protected:
   
  std::vector<QPointF> m_points;
  Enums::DataKind m_dataKindX = Enums::DataKind::unset;
  Enums::DataKind m_dataKindY = Enums::DataKind::unset;
};

typedef std::shared_ptr<IntegrationScopeRhomb> IntegrationScopeRhombSPtr;
typedef std::shared_ptr<const IntegrationScopeRhomb>
  IntegrationScopeRhombCstSPtr;

} // namespace pappso
