/**********************************************************************************************
    Copyright (C) 2014-2015 Oliver Eichler <oliver.eichler@gmx.de>
    Copyright (C) 2018 Norbert Truchsess <norbert.truchsess@t-online.de>

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

**********************************************************************************************/

#ifndef ILINEOP_H
#define ILINEOP_H

#include <QBrush>
#include <QCursor>
#include <QObject>
#include <QPen>
#include <QRect>

#include "gis/IGisLine.h"

class QMouseEvent;
class QPinchGesture;
class CCanvas;
class QPainter;
class IMouseEditLine;

class ILineOp : public QObject {
  Q_OBJECT
 public:
  ILineOp(SGisLine& points, CGisDraw* gis, CCanvas* canvas, IMouseEditLine* parent);
  virtual ~ILineOp();

  virtual void leftClick(const QPoint& pos) = 0;
  virtual void mouseMove(const QPoint& pos);
  virtual void leftButtonDown(const QPoint& pos);
  virtual void rightButtonDown(const QPoint& pos) {}
  virtual void scaleChanged();

  virtual void drawFg(QPainter& p) = 0;
  virtual void drawBg(QPainter& p);

  const QCursor& getCursor() const { return cursor; }

  /**
     @brief   (try to) abort a step in the current operation

     Method called, if a step in the current operation should be aborted, such as
     adding or moving a(n already) selected waypoint.
     This dummy implementation does not do anything and therefore always returns `false`.

     @return  `true` if a step in the current operation was  successfully, `false` otherwise
   */
  virtual bool abortStep() { return false; }

  void updateStatus();
  void showRoutingErrorMessage(const QString& msg) const;

 protected slots:
  void slotTimeoutRouting();

 protected:
  virtual void cancelDelayedRouting();
  virtual void startDelayedRouting();
  virtual void finalizeOperation(qint32 idx);
  qint32 isCloseTo(const QPoint& pos) const;
  qint32 isCloseToLine(const QPoint& pos) const;

  void drawSinglePointSmall(const QPointF& pt, QPainter& p);
  void drawSinglePointLarge(const QPointF& pt, QPainter& p);
  void drawLeadLine(const QPolygonF& line, QPainter& p) const;
  void updateLeadLines(qint32 idx);

  void startMouseMove(const QPointF& point);

  IMouseEditLine* parentHandler;
  SGisLine& points;
  CCanvas* canvas;
  CGisDraw* gis;

  QCursor cursor;

  qint32 idxFocus = NOIDX;

  QPoint lastPos;
  QPoint firstPos;

  QRect rectPoint{0, 0, 9, 9};
  const QPen penBgPoint{Qt::white, 4};
  const QPen penFgPoint{Qt::red, 2};
  const QBrush brushBgPoint{Qt::white};
  const QBrush brushFgPoint{Qt::red};

  QPolygonF leadLineCoord1;
  QPolygonF leadLineCoord2;
  QPolygonF leadLinePixel1;
  QPolygonF leadLinePixel2;

  QPolygonF subLineCoord1;
  QPolygonF subLineCoord2;
  QPolygonF subLinePixel1;
  QPolygonF subLinePixel2;

 private:
  void tryRouting(IGisLine::point_t& pt1, IGisLine::point_t& pt2) const;

  QTimer* timerRouting;
  QTime buttonPressTime;

  bool ignoreClick = false;
  bool mapMove = false;
  bool mouseDidMove = false;
};

#endif  // ILINEOP_H
