// Copyright 2021 Filippo Rusconi
// GPL3+

#pragma once

/////////////////////// StdLib includes


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

////////////////////// Other includes
#include "qcustomplot.h"

/////////////////////// Local includes
#include "../../types.h"
#include "../../exportinmportconfig.h"
#include "../../processing/combiners/integrationscopebase.h"
#include "../../processing/combiners/selectionpolygon.h"


namespace pappso
{

enum class DragDirections
{
  NOT_SET       = 0x0000,
  LEFT_TO_RIGHT = 1 << 0,
  RIGHT_TO_LEFT = 1 << 1,
  TOP_TO_BOTTOM = 1 << 2,
  BOTTOM_TO_TOP = 1 << 3
};


class PMSPP_LIB_DECL BasePlotContext
{
  public:
  BasePlotContext();
  BasePlotContext(const BasePlotContext &other);
  virtual ~BasePlotContext();
    
  DataKind m_dataKind = DataKind::unset;

  bool m_isMouseDragging  = false;
  bool m_wasMouseDragging = false;

  bool m_isKeyBoardDragging            = false;
  bool m_isLeftPseudoButtonKeyPressed  = false;
  bool m_isRightPseudoButtonKeyPressed = false;
  bool m_wassKeyBoardDragging          = false;

  QPointF m_startDragPoint;
  QPointF m_currentDragPoint;
  QPointF m_lastCursorHoveredPoint;
  DragDirections m_dragDirections = DragDirections::NOT_SET;

  IntegrationScopeBaseCstSPtr msp_integrationScope = nullptr;
  SelectionPolygon m_selectionPolygon;
  double m_integrationScopeRhombWidth = 0;
  double m_integrationScopeRhombHeight = 0;

  // The effective range of the axes.
  QCPRange m_xRange;
  QCPRange m_yRange;

  // Tell if the mouse move was started onto either axis, because that will
  // condition if some calculations needs to be performed or not (for example,
  // if the mouse cursor motion was started on an axis, there is no point to
  // perform deconvolutions).
  bool m_wasClickOnXAxis = false;
  bool m_wasClickOnYAxis = false;

  bool m_isMeasuringDistance = false;

  // The user-selected region over the plot.
  // Note that we cannot use QCPRange structures because these are normalized by
  // QCustomPlot in such a manner that lower is actually < upper. But we need
  // for a number of our calculations (specifically for the deconvolutions) to
  // actually have the lower value be start drag point.x even if the drag
  // direction was from right to left.
  double m_xRegionRangeStart = std::numeric_limits<double>::min();
  double m_xRegionRangeEnd   = std::numeric_limits<double>::min();

  double m_yRegionRangeStart = std::numeric_limits<double>::min();
  double m_yRegionRangeEnd   = std::numeric_limits<double>::min();

  double m_xDelta = 0;
  double m_yDelta = 0;

  int m_pressedKeyCode;
  int m_releasedKeyCode;

  Qt::KeyboardModifiers m_keyboardModifiers;

  Qt::MouseButtons m_lastPressedMouseButton;
  Qt::MouseButtons m_lastReleasedMouseButton;

  Qt::MouseButtons m_pressedMouseButtons;

  Qt::MouseButtons m_mouseButtonsAtMousePress;
  Qt::MouseButtons m_mouseButtonsAtMouseRelease;
  
  void updateIntegrationScope();
  void updateIntegrationScopeRect();
  void updateIntegrationScopeRhomb();
  void updateIntegrationScopeRhombHorizontal();
  void updateIntegrationScopeRhombVertical();
  
  BasePlotContext &operator=(const BasePlotContext &other);
  
  DragDirections recordDragDirections();
    
  QString toString() const;
};


} // namespace pappso
