/***************************************************************************
    qgsadvanceddigitizingfloater.cpp  -  floater for CAD tools
    ----------------------
    begin                : May 2019
    copyright            : (C) Olivier Dalang
    email                : olivier.dalang@gmail.com
 ***************************************************************************
 *                                                                         *
 *   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 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef QGSADVANCEDDIGITIZINGFLOATER
#define QGSADVANCEDDIGITIZINGFLOATER

#include "ui_qgsadvanceddigitizingfloaterbase.h"

#include "qgis_gui.h"
#include "qgis_sip.h"
#include "qgsadvanceddigitizingdockwidget.h"

#include <QPointer>
#include <QString>
#include <QWidget>

class QgsMapCanvas;
class QgsAdvancedDigitizingDockWidget;

/**
* \ingroup gui
* \brief A widget that floats next to the mouse pointer, and allows interaction with the AdvancedDigitizing
* feature.
*
* It proxies display and actions to QgsMapToolAdvancedDigitizingDockWidget.
*
* \note This class is a technology preview and unstable API.
* \since QGIS 3.8
*/
class GUI_EXPORT QgsAdvancedDigitizingFloater : public QWidget, private Ui::QgsAdvancedDigitizingFloaterBase
{
    Q_OBJECT

  public:
    //! Available floater items
    enum class FloaterItem : int SIP_ENUM_BASETYPE( IntFlag )
    {
      XCoordinate = 1 << 1,         //!< X coordinate
      YCoordinate = 1 << 2,         //!< Y coordinate
      MCoordinate = 1 << 3,         //!< M coordinate
      ZCoordinate = 1 << 4,         //!< Z coordinate
      Angle = 1 << 5,               //!< Angle between segments
      CommonAngleSnapping = 1 << 6, //!< Common angles
      Distance = 1 << 7,            //!< Distance (segment length)
      Bearing = 1 << 8,             //!< Segment bearing
      Weight = 1 << 9,              //!< Weight for NURBSCurve \since QGIS 4.0
      Area = 1 << 10,               //!< Total area \since QGIS 4.0
      TotalLength = 1 << 11,        //!< Total length (or perimeter) \since QGIS 4.0
    };
    Q_DECLARE_FLAGS( FloaterItems, FloaterItem )
    Q_FLAG( FloaterItem )

    /**
     * Create an advanced digitizing floater widget
     * \param canvas The map canvas on which the widget operates
     * \param cadDockWidget The cadDockWidget to which the floater belongs
     * \since QGIS 3.8
     */
    explicit QgsAdvancedDigitizingFloater( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget );

    /**
    * Whether the floater is active or not.
    * Note that the floater may be active but not visible (e.g. if the mouse is not over the canvas).
    * \since QGIS 3.8
    */
    bool active();

    /**
    * Returns TRUE if the floater \a item visibility setting is enabled.
    *
    * \param item floater item
    * \since QGIS 3.32
    */
    bool itemVisibility( QgsAdvancedDigitizingFloater::FloaterItem item ) const;

    /**
     * Returns the measurement display type for a floater \a item.
     *
     * If the \a item does not support measurement types (see itemSupportsMeasurementType()), Qgis::CadMeasurementDisplayType::Hidden will
     * be returned. For these items use itemVisibility() instead.
     *
     * \since QGIS 4.0
     */
    Qgis::CadMeasurementDisplayType itemMeasurementDisplayType( QgsAdvancedDigitizingFloater::FloaterItem item ) const;

    /**
     * Returns TRUE if a floater \a item supports display in different Qgis::CadMeasurementDisplayType values.
     *
     * \since QGIS 4.0
     */
    static bool itemSupportsMeasurementType( QgsAdvancedDigitizingFloater::FloaterItem item );

  public slots:

    /**
    * Set whether the floater should be active or not.
    * Note that the floater may be active but not visible (e.g. if the mouse is not over the canvas).
    *
    * \param active
    * \since QGIS 3.8
    */
    void setActive( bool active );

    /**
    * Set whether the floater \a item should be visible or not.
    *
    * \param item floater item
    * \param visible
    * \since QGIS 3.32
    */
    void setItemVisibility( QgsAdvancedDigitizingFloater::FloaterItem item, bool visible );

    /**
     * Set whether the measurement display \a type for a floater \a item.
     *
     * \since QGIS 4.0
     */
    void setItemMeasurementType( QgsAdvancedDigitizingFloater::FloaterItem item, Qgis::CadMeasurementDisplayType type );

  public slots:
    /**
    * Updates the weight value displayed in the floater for NURBSCurve.
    * \param text The weight value as a string
    * \since QGIS 4.0
    */
    void changeWeight( const QString &text );

    /**
    * Shows or hides the weight widget in the floater for NURBSCurve.
    * \param enabled Whether weight editing is active
    * \since QGIS 4.0
    */
    void enabledChangedWeight( bool enabled );

    /**
    * Requests focus on the weight input field for NURBSCurve.
    * \since QGIS 4.0
    */
    void focusOnWeight();

  private slots:

    void changeX( const QString &text );
    void changeY( const QString &text );
    void changeZ( const QString &text );
    void changeM( const QString &text );
    void changeCommonAngleSnapping( double angle );
    void changeDistance( const QString &text );
    void changeAngle( const QString &text );
    void changeBearing( const QString &text );
    void changeArea( const QString &text );
    void changeTotalLength( const QString &text );
    void changeLockX( bool locked );
    void changeLockY( bool locked );
    void changeLockZ( bool locked );
    void changeLockM( bool locked );
    void changeLockDistance( bool locked );
    void changeLockAngle( bool locked );
    void changeRelativeX( bool relative );
    void changeRelativeY( bool relative );
    void changeRelativeZ( bool relative );
    void changeRelativeM( bool relative );
    // void changeRelativeDistance( bool relative );  // doesn't happen
    void changeRelativeAngle( bool relative );
    void focusOnX();
    void focusOnY();
    void focusOnZ();
    void focusOnM();
    void focusOnAngle();
    void focusOnDistance();
    void enabledChangedX( bool enabled );
    void enabledChangedY( bool enabled );
    void enabledChangedZ( bool enabled );
    void enabledChangedM( bool enabled );
    void enabledChangedAngle( bool enabled );
    void enabledChangedDistance( bool enabled );
    void enabledCommonAngleSnapping( bool enabled );
    void enabledChangedBearing( bool enabled );

  private:
    //! pointer to map canvas
    QgsMapCanvas *mMapCanvas = nullptr;

    //! pointer to map cad docker widget
    QPointer<QgsAdvancedDigitizingDockWidget> mCadDockWidget;

    /**
    * event filter to track mouse position
    * \note defined as private in Python bindings
    */
    bool eventFilter( QObject *obj, QEvent *event ) override SIP_FORCE;

    /**
    * Move the widget to a new cursor position. A hard-coded offset will be added.
    * \param pos position of the cursor
    */
    void updatePos( const QPoint &pos );

    /**
    * Hides the widget if either the floater or the cadDockWidget is disabled.
    */
    void hideIfDisabled();

    //! Whether the floater is enabled.
    bool mActive = false;

    FloaterItems mItemsVisibility;
};

#endif // QGSADVANCEDDIGITIZINGFLOATER_H
