#pragma once

#include <QFutureWatcher>
#include <QVector>

#include "SettingsFact.h"
#include "TransectStyleComplexItem.h"

class CircularSurvey : public TransectStyleComplexItem {
  Q_OBJECT
public:
  /// @param vehicle Vehicle which this is being contructed for
  /// @param flyView true: Created for use in the Fly View, false: Created for
  /// use in the Plan View
  /// @param kmlOrShpFile Polygon comes from this file, empty for default
  /// polygon
  CircularSurvey(Vehicle *vehicle, bool flyView, const QString &kmlOrShpFile,
                 QObject *parent);

  Q_PROPERTY(QGeoCoordinate refPoint READ refPoint WRITE setRefPoint NOTIFY
                 refPointChanged)
  Q_PROPERTY(Fact *deltaR READ deltaR CONSTANT)
  Q_PROPERTY(Fact *deltaAlpha READ deltaAlpha CONSTANT)
  Q_PROPERTY(Fact *transectMinLength READ transectMinLength CONSTANT)
  Q_PROPERTY(Fact *reverse READ reverse CONSTANT)
  Q_PROPERTY(Fact *maxWaypoints READ maxWaypoints CONSTANT)
  Q_PROPERTY(bool isInitialized READ isInitialized WRITE setIsInitialized NOTIFY
                 isInitializedChanged)
  Q_PROPERTY(bool calculating READ calculating NOTIFY calculatingChanged)

  Q_INVOKABLE void resetReference(void);

  // Property setters
  void setRefPoint(const QGeoCoordinate &refPt);
  // Set this to true if survey was automatically generated, prevents
  // initialisation from gui.
  void setIsInitialized(bool isInitialized);

  // Property getters
  QGeoCoordinate refPoint() const;
  Fact *deltaR();
  Fact *deltaAlpha();
  Fact *transectMinLength();
  Fact *reverse();
  Fact *maxWaypoints();
  bool calculating();
  // Is true if survey was automatically generated, prevents initialisation from
  // gui.
  bool isInitialized();

  // Overrides from ComplexMissionItem
  bool load(const QJsonObject &complexObject, int sequenceNumber,
            QString &errorString) final;
  QString mapVisualQML(void) const final;

  // Overrides from TransectStyleComplexItem
  void save(QJsonArray &planItems) final;
  bool specifiesCoordinate(void) const final;
  void appendMissionItems(QList<MissionItem *> &items,
                          QObject *missionItemParent) final;
  void applyNewAltitude(double newAltitude) final;
  double timeBetweenShots(void) final;

  // Overrides from VisualMissionionItem
  QString commandDescription(void) const final;
  QString commandName(void) const final;
  QString abbreviation(void) const final;
  bool readyForSave(void) const final;
  double additionalTimeDelay(void) const final;

  static const char *settingsGroup;
  static const char *deltaRName;
  static const char *deltaAlphaName;
  static const char *transectMinLengthName;
  static const char *reverseName;
  static const char *maxWaypointsName;
  static const char *CircularSurveyName;
  static const char *refPointLongitudeName;
  static const char *refPointLatitudeName;
  static const char *refPointAltitudeName;

signals:
  void refPointChanged();
  void isInitializedChanged();
  void calculatingChanged();

private slots:
  // Overrides from TransectStyleComplexItem
  void _rebuildTransectsPhase1(void) final;
  void _recalcComplexDistance(void) final;
  void _recalcCameraShots(void) final;
  void _deferUpdate();

private:
  void _appendLoadedMissionItems(QList<MissionItem *> &items,
                                 QObject *missionItemParent);
  void _buildAndAppendMissionItems(QList<MissionItem *> &items,
                                   QObject *missionItemParent);

  // center of the circular lanes, e.g. base station
  QGeoCoordinate _referencePoint;

  QMap<QString, FactMetaData *> _metaDataMap;
  // distance between two neighbour circles
  SettingsFact _deltaR;
  // angle discretisation of the circles
  SettingsFact _deltaAlpha;
  // minimal transect lenght, transects are rejected if they are shorter than
  // this value
  SettingsFact _minLength;
  // reverses the _transects path
  SettingsFact _reverse;
  // the maximum number of waypoints _transects (TransectStyleComplexItem) can
  // contain (to avoid performance hits)
  SettingsFact _maxWaypoints;
  // Timer to defer recalc
  QTimer _timer;
  // indicates if the polygon and refpoint etc. are initialized, prevents
  // reinitialisation from gui and execution of _rebuildTransectsPhase1 during
  // init from gui
  bool _isInitialized;

  using PtrTransects = std::shared_ptr<Transects>;
  using Watcher = QFutureWatcher<PtrTransects>;
  Watcher _watcher;
  bool _calculating;
  bool _cancle;
};
