/***************************************************************************
    qgseditorwidgetwrapper.h
     --------------------------------------
    Date                 : 20.4.2013
    Copyright            : (C) 2013 Matthias Kuhn
    Email                : matthias at opengis dot ch
 ***************************************************************************
 *                                                                         *
 *   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 QGSEDITORWIDGETWRAPPER_H
#define QGSEDITORWIDGETWRAPPER_H

#include <QObject>
#include <QMap>
#include <QVariant>

class QgsVectorLayer;
class QgsField;

#include "qgseditorwidgetconfig.h"
#include "qgsattributeeditorcontext.h"
#include "qgswidgetwrapper.h"

/** \ingroup gui
 * Manages an editor widget
 * Widget and wrapper share the same parent
 *
 * A wrapper controls one attribute editor widget and is able to create a default
 * widget or use a pre-existent widget. It is able to set the widget to the value implied
 * by a field of a vector layer, or return the value it currently holds. Every time it is changed
 * it has to emit a valueChanged signal. If it fails to do so, there is no guarantee that the
 * changed status of the widget will be saved.
 *
 */
class GUI_EXPORT QgsEditorWidgetWrapper : public QgsWidgetWrapper
{
    Q_OBJECT
  public:
    /**
     * Create a new widget wrapper
     *
     * @param vl        The layer on which the field is
     * @param fieldIdx  The field which will be controlled
     * @param editor    An editor widget. Can be NULL if one should be autogenerated.
     * @param parent    A parent widget for this widget wrapper and the created widget.
     */
    explicit QgsEditorWidgetWrapper( QgsVectorLayer* vl, int fieldIdx, QWidget* editor = nullptr, QWidget* parent = nullptr );

    /**
     * Will be used to access the widget's value. Read the value from the widget and
     * return it properly formatted to be saved in the attribute.
     *
     * If an invalid variant is returned this will be interpreted as no change.
     * Be sure to return a NULL QVariant if it should be set to NULL.
     *
     * @return The current value the widget represents
     */
    virtual QVariant value() const = 0;

    /**
     * Access the field index.
     *
     * @return The index of the field you are working on
     *
     * @see layer()
     */
    int fieldIdx() const;

    /**
     * Access the field.
     *
     * @return The field you are working on
     *
     * @see layer()
     */
    QgsField field() const;

    /**
     * Access the default value of the field.
     *
     * @return the default value of the field
     *
     * @see layer()
     */
    QVariant defaultValue() const;

    /**
     * Will return a wrapper for a given widget
     * @param widget The widget which was created by a wrapper
     * @return The wrapper for the widget or NULL
     */
    static QgsEditorWidgetWrapper* fromWidget( QWidget* widget );

    /**
     * Is used to enable or disable the edit functionality of the managed widget.
     * By default this will enable or disable the whole widget
     *
     * @param enabled  Enable or Disable?
     */
    void setEnabled( bool enabled ) override;

    /** Sets the widget to display in an indeterminate "mixed value" state.
     * @note added in QGIS 2.16
     */
    virtual void showIndeterminateState() {}

    /**
     * Update constraint.
     * @param featureContext the feature to use to evaluate the constraint
     * @note added in QGIS 2.16
     */
    void updateConstraint( const QgsFeature &featureContext );

    /**
     * Get the current constraint status.
     * @return true if the constraint is valid or if there's not constraint,
     * false otherwise
     * @note added in QGIS 2.16
     */
    bool isValidConstraint() const;

  signals:
    /**
     * Emit this signal, whenever the value changed.
     *
     * @param value The new value
     */
    void valueChanged( const QVariant& value );

    /**
     * Emit this signal when the constraint status changed.
     * @brief constraintStatusChanged
     * @param constraint represented as a string
     * @param desc is the constraint description
     * @param err the error represented as a string. Empty if none.
     * @param status
     */
    void constraintStatusChanged( const QString& constraint, const QString &desc, const QString& err, bool status );

  public slots:
    /**
     * Will be called when the feature changes
     *
     * Is forwarded to the slot \link setValue() \endlink
     *
     * @param feature The new feature
     */
    void setFeature( const QgsFeature& feature ) override;

    /**
     * Is called, when the value of the widget needs to be changed. Update the widget representation
     * to reflect the new value.
     *
     * @param value The new value of the attribute
     */
    virtual void setValue( const QVariant& value ) = 0;

  protected slots:
    /**
     * If you emit to this slot in your implementation, an appropriate change notification
     * will be broadcasted. Helper for string type widgets.
     *
     * @param value The value
     */
    void valueChanged( const QString& value );

    /**
     * If you emit to this slot in your implementation, an appropriate change notification
     * will be broadcasted. Helper for int type widgets.
     *
     * @param value The value
     * @note python name valueChangedInt
     */
    void valueChanged( int value );

    /**
     * If you emit to this slot in your implementation, an appropriate change notification
     * will be broadcasted. Helper for double type widgets.
     *
     * @param value The value
     * @note python name valueChangedDouble
     */
    void valueChanged( double value );

    /**
     * If you emit to this slot in your implementation, an appropriate change notification
     * will be broadcasted. Helper for bool type widgets.
     *
     * @param value The value
     * @note python name valueChangedBool
     */
    void valueChanged( bool value );

    /**
     * If you emit to this slot in your implementation, an appropriate change notification
     * will be broadcasted. Helper for longlong type widgets.
     *
     * @param value The value
     */
    void valueChanged( qlonglong value );

    /**
     * Will call the value() method to determine the emitted value
     */
    void valueChanged();

  protected:
    /**
     * This should update the widget with a visual cue if a constraint status
     * changed.
     *
     * By default a stylesheet will be applied on the widget that changes the
     * background color to red.
     *
     * This can be overwritten in subclasses to allow individual widgets to
     * change the visual cue.
     *
     * @param constraintValid The current constraint status.
     *
     * @note added in QGIS 2.16
     */
    virtual void updateConstraintWidgetStatus( bool constraintValid );

  private:

    /**
     * Boolean storing the current validity of the constraint for this widget.
     */
    bool mValidConstraint;

    int mFieldIdx;
    QgsFeature mFeature;
    mutable QVariant mDefaultValue; // Cache default value, we don't want to retrieve different serial numbers if called repeatedly
};

// We'll use this class inside a QVariant in the widgets properties
Q_DECLARE_METATYPE( QgsEditorWidgetWrapper* )

#endif // QGSEDITORWIDGETWRAPPER_H
