/*
 * Copyright (C) 2001-2015 Klaralvdalens Datakonsult AB.  All rights reserved.
 *
 * This file is part of the KD Chart library.
 *
 * 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.
 *
 * 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 <https://www.gnu.org/licenses/>.
 */

#ifndef KCHARTLEGEND_H
#define KCHARTLEGEND_H

#include "KChartAbstractAreaWidget.h"
#include "KChartPosition.h"
#include "KChartMarkerAttributes.h"

class QTextTable;

namespace KChart {

class AbstractDiagram;
typedef QList<AbstractDiagram*> DiagramList;
typedef QList<const AbstractDiagram*> ConstDiagramList;

/**
  * @brief Legend defines the interface for the legend drawing class.
  *
  * Legend is the class for drawing legends for all kinds of diagrams ("chart types").
  *
  * Legend is drawn on chart level, not per diagram, but you can have more than one
  * legend per chart, using KChart::Chart::addLegend().
  *
  * \note Legend is different from all other classes of KChart, since it can be
  * displayed outside of the Chart's area.  If you want to, you can embedd the legend
  * into your own widget, or into another part of a bigger layout, into which you might
  * have inserted the Chart.
  *
  * On the other hand, please note that you MUST call Chart::addLegend to get your
  * legend positioned into the correct place of your chart - if you want to have
  * the legend shown inside of the chart (that's probably true for most cases).
  */
class KCHART_EXPORT Legend : public AbstractAreaWidget
{
    Q_OBJECT

    Q_DISABLE_COPY( Legend )
    KCHART_DECLARE_PRIVATE_DERIVED_QWIDGET( Legend )

public:
    explicit Legend( QWidget* parent = nullptr );
    explicit Legend( KChart::AbstractDiagram* diagram, QWidget* parent = nullptr );
    virtual ~Legend();


    enum LegendStyle { MarkersOnly     = 0,
                       LinesOnly       = 1,
                       MarkersAndLines = 2 };


    void setLegendStyle( LegendStyle style );
    LegendStyle legendStyle() const;



    /**
      * Creates an exact copy of this legend.
      */
    virtual Legend * clone() const;

    /**
     * Returns true if both legends have the same settings.
     */
    bool compare( const Legend* other ) const;

    void resizeEvent( QResizeEvent * event ) override; // TODO: should be protected

    virtual void paint( QPainter* painter ) override;
    void paint( QPainter* painter, const QRect &rect);
    void setVisible( bool visible ) override;

    /**
        Specifies the reference area for font size of title text,
        and for font size of the item texts, IF automatic area
        detection is set.

        \note This parameter is ignored, if the Measure given for
        setTitleTextAttributes (or setTextAttributes, resp.) is
        not specifying automatic area detection.

        If no reference area is specified, but automatic area
        detection is set, then the size of the legend's parent
        widget will be used.

        \sa KChart::Measure, KChartEnums::MeasureCalculationMode
    */
    void setReferenceArea( const QWidget* area );
    /**
        Returns the reference area, that is used for font size of title text,
        and for font size of the item texts, IF automatic area
        detection is set.

        \sa setReferenceArea
    */
    const QWidget* referenceArea() const;

    /**
      * The first diagram of the legend or 0 if there was none added to the legend.
      * @return The first diagram of the legend or 0.
      *
      * \sa diagrams, addDiagram, removeDiagram, removeDiagrams, replaceDiagram, setDiagram
      */
    KChart::AbstractDiagram* diagram() const;

    /**
      * The list of all diagrams associated with the legend.
      * @return The list of all diagrams associated with the legend.
      *
      * \sa diagram, addDiagram, removeDiagram, removeDiagrams, replaceDiagram, setDiagram
      */
    DiagramList diagrams() const;

    /**
     * @return The list of diagrams associated with this legend.
     */
    ConstDiagramList constDiagrams() const;

    /**
      * Add the given diagram to the legend.
      * @param newDiagram The diagram to add.
      *
      * \sa diagram, diagrams, removeDiagram, removeDiagrams, replaceDiagram, setDiagram
      */
    void addDiagram( KChart::AbstractDiagram* newDiagram );

    /**
      * Removes the diagram from the legend's list of diagrams.
      *
      * \sa diagram, diagrams, addDiagram, removeDiagrams, replaceDiagram, setDiagram
      */
    void removeDiagram( KChart::AbstractDiagram* oldDiagram );

    /**
      * Removes all diagrams from the legend's list of diagrams.
      *
      * \sa diagram, diagrams, addDiagram, removeDiagram, replaceDiagram, setDiagram
      */
    void removeDiagrams();

    /**
      * Replaces the old diagram, or appends the
      * new diagram, it there is none yet.
      *
      * @param newDiagram The diagram to be used instead of the old one.
      * If this parameter is zero, the first diagram will just be removed.
      *
      * @param oldDiagram The diagram to be removed by the new one. This
      * diagram will be deleted automatically. If the parameter is omitted,
      * the very first diagram will be replaced. In case, there was no
      * diagram yet, the new diagram will just be added.
      *
      * \sa diagram, diagrams, addDiagram, removeDiagram, removeDiagrams, setDiagram
      */
    void replaceDiagram( KChart::AbstractDiagram* newDiagram,
                         KChart::AbstractDiagram* oldDiagram = nullptr );

    /**
      * Returns the offset of the first dataset of \c diagram.
      *
      */
    uint dataSetOffset( KChart::AbstractDiagram* diagram );

    /**
      * @brief A convenience method doing the same as replaceDiagram( newDiagram, 0 );
      *
      * Replaces the first diagram by the given diagram.
      * If the legend's list of diagram is empty the given diagram is added to the list.
      *
      * \sa diagram, diagrams, addDiagram, removeDiagram, removeDiagrams, replaceDiagram
      */
    void setDiagram( KChart::AbstractDiagram* newDiagram );

    /**
     * \brief Specify the position of a non-floating legend.
     *
     * Use setFloatingPosition to set position and alignment
     * if your legend is floating.
     *
     * \sa setAlignment, setFloatingPosition
     */
    void setPosition( Position position );

    /**
     * Returns the position of a non-floating legend.
     * \sa setPosition
     */
    Position position() const;

    /**
     * \brief Specify the alignment of a non-floating legend.
     *
     * Use setFloatingPosition to set position and alignment
     * if your legend is floating.
     *
     * \sa alignment, setPosition, setFloatingPosition
     */
    void setAlignment( Qt::Alignment );

    /**
     * Returns the alignment of a non-floating legend.
     * \sa setAlignment
     */
    Qt::Alignment alignment() const;

    /**
     * \brief Specify the alignment of the text elements within the legend
     *
     * \sa textAlignment()
     */
    void setTextAlignment( Qt::Alignment );

    /**
     * \brief Returns the alignment used while rendering text elements within the legend.
     *
     * \sa setTextAlignment()
     */
     Qt::Alignment textAlignment() const;

     /**
      * \brief Specify the alignment of the legend symbol( alignment of Legend::LinesOnly)
      *  within the legend
      *
      * \sa legendSymbolAlignment()
      */
     void setLegendSymbolAlignment(Qt::Alignment);

     /**
      * \brief Returns the alignment used while drawing legend symbol(alignment of Legend::LinesOnly)
      * within the legend.
      *
      * \sa setLegendSymbolAlignment()
      */
     Qt::Alignment legendSymbolAlignment() const;

    /**
     * \brief Specify the position and alignment of a floating legend.
     *
     * Use setPosition and setAlignment to set position and alignment
     * if your legend is non-floating.
     *
     * \note When setFloatingPosition is called, the Legend's position value is set to
     * KChart::Position::Floating automatically.
     *
     * If your Chart is pointed to by m_chart, your could have the floating legend
     * aligned exactly to the chart's coordinate plane's top-right corner
     * with the following commands:
\verbatim
KChart::RelativePosition relativePosition;
relativePosition.setReferenceArea( m_chart->coordinatePlane() );
relativePosition.setReferencePosition( Position::NorthEast );
relativePosition.setAlignment( Qt::AlignTop | Qt::AlignRight );
relativePosition.setHorizontalPadding(
    KChart::Measure( -1.0, KChartEnums::MeasureCalculationModeAbsolute ) );
relativePosition.setVerticalPadding(
    KChart::Measure( 0.0, KChartEnums::MeasureCalculationModeAbsolute ) );
m_legend->setFloatingPosition( relativePosition );
\endverbatim
     *
     * To have the legend positioned at a fixed point, measured from the QPainter's top left corner,
     * you could use the following code code:
     *
\verbatim
KChart::RelativePosition relativePosition;
relativePosition.setReferencePoints( PositionPoints( QPointF( 0.0, 0.0 ) ) );
relativePosition.setReferencePosition( Position::NorthWest );
relativePosition.setAlignment( Qt::AlignTop | Qt::AlignLeft );
relativePosition.setHorizontalPadding(
    KChart::Measure( 4.0, KChartEnums::MeasureCalculationModeAbsolute ) );
relativePosition.setVerticalPadding(
    KChart::Measure( 4.0, KChartEnums::MeasureCalculationModeAbsolute ) );
m_legend->setFloatingPosition( relativePosition );
\endverbatim
     * Actually that's exactly the code KChart is using as default position for any floating legends,
     * so if you just say setPosition( KChart::Position::Floating ) without calling setFloatingPosition
     * your legend will be positioned at point 4/4.
     *
     * \sa setPosition, setAlignment
     */
    void setFloatingPosition( const RelativePosition& relativePosition );

    /**
     * Returns the position of a floating legend.
     * \sa setFloatingPosition
     */
    const RelativePosition floatingPosition() const;

    void setOrientation( Qt::Orientation orientation );
    Qt::Orientation orientation() const;


    void setSortOrder( Qt::SortOrder order );
    Qt::SortOrder sortOrder() const;

    void setShowLines( bool legendShowLines );
    bool showLines() const;


    /**
        \brief Removes all legend texts that might have been set by setText.

        This resets the Legend to default behaviour: Texts are created automatically.
    */
    void resetTexts();
    void setText( uint dataset, const QString& text );
    QString text( uint dataset ) const;
    const QMap<uint,QString> texts() const;

    /**
     * Sets a list of datasets that are to be hidden in the legend.
     *
     * By passing an empty list, you show all datasets.
     * All datasets are shown by default, which means
     * that hiddenDatasets() returns an empty list.
     */
    void setHiddenDatasets( const QList<uint> hiddenDatasets );
    const QList<uint> hiddenDatasets() const;
    void setDatasetHidden( uint dataset, bool hidden );
    bool datasetIsHidden( uint dataset ) const;

    uint datasetCount() const;

    void setDefaultColors();
    void setRainbowColors();
    void setSubduedColors( bool ordered = false );

    void setBrushesFromDiagram( KChart::AbstractDiagram* diagram );

    /**
     * Note: there is no color() getter method, since setColor
     * just sets a QBrush with the respective color, so the
     * brush() getter method is sufficient.
     */
    void setColor( uint dataset, const QColor& color );

    void setBrush( uint dataset, const QBrush& brush );
    QBrush brush( uint dataset ) const;
    const QMap<uint,QBrush> brushes() const;

    void setPen( uint dataset, const QPen& pen );
    QPen pen( uint dataset ) const;
    const QMap<uint,QPen> pens() const;

    /**
     * Note that any sizes specified via setMarkerAttributes are ignored,
     * unless you disable the automatic size calculation, by saying
     * setUseAutomaticMarkerSize( false )
     */
    void setMarkerAttributes( uint dataset, const MarkerAttributes& );
    MarkerAttributes markerAttributes( uint dataset ) const;
    const QMap<uint, MarkerAttributes> markerAttributes() const;

    /**
     * This option is on by default, it means that Marker sizes in the Legend
     * will be the same as the font height used for their respective label texts.
     *
     * Set this to false, if you want to specify the marker sizes via setMarkerAttributes
     * or if you want the Legend to use the same marker sizes as they are used in the Diagrams.
     */
    void setUseAutomaticMarkerSize( bool useAutomaticMarkerSize );
    bool useAutomaticMarkerSize() const;

    void setTextAttributes( const TextAttributes &a );
    TextAttributes textAttributes() const;

    void setTitleText( const QString& text );
    QString titleText() const;

    void setTitleTextAttributes( const TextAttributes &a );
    TextAttributes titleTextAttributes() const;

    void setSpacing( uint space );
    uint spacing() const;

    // called internally by KChart::Chart, when painting into a custom QPainter
    void forceRebuild() override;

    QSize minimumSizeHint() const override;
    QSize sizeHint() const override;
    bool hasHeightForWidth() const override;
    int heightForWidth( int width ) const override;
    void needSizeHint() override;
    void resizeLayout( const QSize& size ) override;

Q_SIGNALS:
    void destroyedLegend( Legend* );
    /** Emitted upon change of a property of the Legend or any of its components. */
    void propertiesChanged();

private Q_SLOTS:
    void emitPositionChanged();
    void resetDiagram( AbstractDiagram* );
    void activateTheLayout();
    void setNeedRebuild();
    void buildLegend();
}; // End of class Legend

}


#endif // KCHARTLEGEND_H
