/***************************************************************************
    qgsdiagram.h
    ---------------------
    begin                : March 2011
    copyright            : (C) 2011 by Marco Hugentobler
    email                : marco dot hugentobler at sourcepole 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 QGSDIAGRAM_H
#define QGSDIAGRAM_H

#include "qgis.h"
#include "qgis_core.h"
#include "qgsexpression.h"

#include <QBrush>
#include <QPen>
#include <QString>

using namespace Qt::StringLiterals;

class QPainter;
class QPointF;
class QgsDiagramSettings;
class QgsDiagramInterpolationSettings;
class QgsFeature;
class QgsRenderContext;
class QgsExpressionContext;
class QgsFields;
class QgsAttributes;


/**
 * \ingroup core
 * \brief Base class for all diagram types.
*/
class CORE_EXPORT QgsDiagram SIP_NODEFAULTCTORS
{
  public:
#ifdef SIP_RUN
    SIP_CONVERT_TO_SUBCLASS_CODE
    if ( sipCpp->diagramName() == "Pie"_L1 )
      sipType = sipType_QgsPieDiagram;
    else if ( sipCpp->diagramName() == "Histogram"_L1 )
      sipType = sipType_QgsHistogramDiagram;
    else if ( sipCpp->diagramName() == "Text"_L1 )
      sipType = sipType_QgsTextDiagram;
    else if ( sipCpp->diagramName() == "Stacked"_L1 )
      sipType = sipType_QgsStackedBarDiagram;
    else if ( sipCpp->diagramName() == "StackedDiagram"_L1 )
      sipType = sipType_QgsStackedDiagram;
    else
      sipType = NULL;
    SIP_END
#endif

    virtual ~QgsDiagram()
    {
      clearCache();
    }

    /**
     * Returns an instance that is equivalent to this one
    */
    virtual QgsDiagram *clone() const = 0 SIP_FACTORY;

    void clearCache();

    /**
     * Returns a prepared expression for the specified context.
     * \param expression expression string
     * \param context expression context
     */
    QgsExpression *getExpression( const QString &expression, const QgsExpressionContext &context );

    //! Draws the diagram at the given position (in pixel coordinates)
    virtual void renderDiagram( const QgsFeature &feature, QgsRenderContext &c, const QgsDiagramSettings &s, QPointF position ) = 0;

    /**
     * Gets a descriptive name for this diagram type.
     */
    virtual QString diagramName() const = 0;
    //! Returns the size in map units the diagram will use to render.
    virtual QSizeF diagramSize( const QgsAttributes &attributes, const QgsRenderContext &c, const QgsDiagramSettings &s ) = 0;
    //! Returns the size in map units the diagram will use to render. Interpolate size
    virtual QSizeF diagramSize( const QgsFeature &feature, const QgsRenderContext &c, const QgsDiagramSettings &s, const QgsDiagramInterpolationSettings &interpolationSettings ) = 0;

    /**
     * Returns the size of the legend item for the diagram corresponding to a specified value.
     * \param value value to return legend item size for
     * \param s diagram settings
     * \param interpolationSettings interpolation settings
     */
    virtual double legendSize( double value, const QgsDiagramSettings &s, const QgsDiagramInterpolationSettings &interpolationSettings ) const = 0;

  protected:
    QgsDiagram() = default;
    QgsDiagram( const QgsDiagram &other );

    /**
     * Changes the pen width to match the current settings and rendering context
     *  \param pen The pen to modify
     *  \param s   The settings that specify the pen width
     *  \param c   The rendering specifying the proper scale units for pixel conversion
     */
    void setPenWidth( QPen &pen, const QgsDiagramSettings &s, const QgsRenderContext &c );

    /**
     * Calculates a size to match the current settings and rendering context
     *  \param size The size to convert
     *  \param s    The settings that specify the size type
     *  \param c    The rendering specifying the proper scale units for pixel conversion
     *
     *  \returns The converted size for rendering
     */
    QSizeF sizePainterUnits( QSizeF size, const QgsDiagramSettings &s, const QgsRenderContext &c );

    /**
     * Calculates a length to match the current settings and rendering context
     *  \param l    The length to convert
     *  \param s    The settings that specify the size type
     *  \param c    The rendering specifying the proper scale units for pixel conversion
     *
     *  \returns The converted length for rendering
     */
    double sizePainterUnits( double l, const QgsDiagramSettings &s, const QgsRenderContext &c );

    /**
     * Calculates a size to match the current settings and rendering context
     *  \param s    The settings that contain the font size and size type
     *  \param c    The rendering specifying the proper scale units for pixel conversion
     *
     *  \returns The properly scaled font for rendering
     */
    QFont scaledFont( const QgsDiagramSettings &s, const QgsRenderContext &c );

    /**
     * Returns the scaled size of a diagram for a value, respecting the specified diagram interpolation settings.
     * \param value value to calculate corresponding circular size for
     * \param s diagram settings
     * \param interpolationSettings interpolation settings
     */
    QSizeF sizeForValue( double value, const QgsDiagramSettings &s, const QgsDiagramInterpolationSettings &interpolationSettings ) const;

  private:
    QMap<QString, QgsExpression *> mExpressions;
    QgsDiagram &operator=( const QgsDiagram & ) = delete;
};

#endif // QGSDIAGRAM_H
