/***************************** LICENSE START ***********************************

 Copyright 2021 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#pragma once

#include <QFont>
#include <QHBoxLayout>
#include <QList>
#include <QMap>
#include <QStringList>
#include <QWidget>

#include "MvRequest.h"
#include "MvIconLanguage.h"
#include "MvIconParameter.h"
#include "MvQFeatureItemObserver.h"
#include "MvQFeatureFwd.h"

class QAbstractButton;
class QButtonGroup;
class QComboBox;
class QLabel;
class QPushButton;
class QToolButton;
class QSpinBox;

class ColourSelector;
class MvQFeatureItem;
class MvQCompactColourGrid;
class TransparencyWidget;

class RibbonEditItem : public QObject
{
    Q_OBJECT

public:
    RibbonEditItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);
    virtual ~RibbonEditItem() = default;

    virtual void setValue(const MvRequest& req) = 0;
    virtual void updateRequest(MvRequest& req)  = 0;
    virtual void setControlParam(const std::string& rc) { controlParam_ = rc; }
    virtual void grey(bool) = 0;
    QString paramName() const { return name_; }
    void addLabel();
    static void fixedFontAndHeight(QFont& font, int& h);

Q_SIGNALS:
    void edited();
    void transparencyEdited();

protected:
    const MvIconParameter& param_;
    QString name_;
    QString idKey_;
    QWidget* parentWidget_;
    QLayout* layout_;
    QLabel* label_{nullptr};
    bool ignoreChange_{false};
    std::string controlParam_;
};

class RibbonControlItem : public RibbonEditItem, ParameterScanner
{
    Q_OBJECT

public:
    RibbonControlItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);
    void setValue(const MvRequest& req) override;
    void updateRequest(MvRequest& req) override;
    void next(const MvIconParameter&, const char*, const char*) override;
    void grey(bool) override;

protected Q_SLOTS:
    void buttonClicked(bool);

protected:
    QToolButton* tb_{nullptr};
    QStringList values_;
    int index_{0};
    bool onIndex_{0};
    QString tooltipChecked_;
    QString tooltipUnchecked_;
};

class RibbonBoldFontControlItem : public RibbonControlItem
{
public:
    RibbonBoldFontControlItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);
};

class RibbonItalicFontControlItem : public RibbonControlItem
{
public:
    RibbonItalicFontControlItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);
};

class RibbonUnderlineFontControlItem : public RibbonControlItem
{
public:
    RibbonUnderlineFontControlItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);
};

class RibbonOutlineControlItem : public RibbonControlItem
{
public:
    RibbonOutlineControlItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);
};

class RibbonFillControlItem : public RibbonControlItem
{
public:
    RibbonFillControlItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);
};


class RibbonFlipStateItem : public RibbonEditItem, ParameterScanner
{
    Q_OBJECT

public:
    RibbonFlipStateItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);
    void setValue(const MvRequest& req) override;
    void updateRequest(MvRequest& req) override;
    void next(const MvIconParameter&, const char*, const char*) override;
    void grey(bool) override;

protected Q_SLOTS:
    void buttonClicked();

protected:
    QPushButton* pb_{nullptr};
    QStringList values_;
    int index_{0};
};

class RibbonSizeSpinItem : public RibbonEditItem
{
    Q_OBJECT

public:
    RibbonSizeSpinItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);
    void setValue(const MvRequest& req) override;
    void updateRequest(MvRequest& req) override;
    void grey(bool) override;

protected Q_SLOTS:
    void valueChanged(int);

protected:
    QSpinBox* spin_{nullptr};
};


class RibbonComboBoxItem : public RibbonEditItem, ParameterScanner
{
    Q_OBJECT

public:
    RibbonComboBoxItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);
    void setValue(const MvRequest& req) override;
    void updateRequest(MvRequest& req) override;
    void next(const MvIconParameter&, const char*, const char*) override;
    void grey(bool) override;

protected Q_SLOTS:
    void valueChanged(QString v);

protected:
    QString value() const;
    void setClosestIndex(QString s);
    virtual void loadPixmaps() {}

    bool useClosest_{false};
    QComboBox* cb_{nullptr};
};

class RibbonFontFamilyItem : public RibbonComboBoxItem
{
public:
    RibbonFontFamilyItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);
};

class RibbonFontSizeItem : public RibbonComboBoxItem
{
public:
    RibbonFontSizeItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);
};

class RibbonFontStyleItem : public RibbonEditItem
{
    Q_OBJECT
public:
    RibbonFontStyleItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);
    void setValue(const MvRequest& req) override;
    void updateRequest(MvRequest& req) override;
    void grey(bool) override;

protected Q_SLOTS:
    void valueChanged(bool);

protected:
    QToolButton* boldTb_;
    QToolButton* italicTb_;
    QToolButton* underlineTb_;
};

class RibbonTextAlignmentItem : public RibbonEditItem
{
    Q_OBJECT
public:
    RibbonTextAlignmentItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);
    void setValue(const MvRequest& req) override;
    void updateRequest(MvRequest& req) override;
    void grey(bool) override;

protected Q_SLOTS:
    void buttonClicked(QAbstractButton*);

protected:
    QButtonGroup* bGroup_;
    QStringList keys_;
};


class RibbonLineStyleItem : public RibbonComboBoxItem
{
public:
    RibbonLineStyleItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);

protected:
    void loadPixmaps() override;
    void renderLine(QPixmap* pix, Qt::PenStyle penStyle);
};

class RibbonLineWidthItem : public RibbonComboBoxItem
{
public:
    RibbonLineWidthItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);

protected:
    void loadPixmaps() override;
    void renderLine(QPixmap* pix, int);
};

class RibbonLineStartEndItem : public RibbonComboBoxItem
{
public:
    RibbonLineStartEndItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey, bool start);

protected:
    void loadPixmaps() override;
    void renderLine(QPixmap* pix, QString);

    bool start_{false};
};

class RibbonLineStartItem : public RibbonLineStartEndItem
{
public:
    RibbonLineStartItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey) :
        RibbonLineStartEndItem(param, layout, parent, typeKey, true) {}
};

class RibbonLineEndItem : public RibbonLineStartEndItem
{
public:
    RibbonLineEndItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey) :
        RibbonLineStartEndItem(param, layout, parent, typeKey, false) {}
};

class RibbonColourItem : public RibbonEditItem
{
    Q_OBJECT
public:
    RibbonColourItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);
    void setValue(const MvRequest& req) override;
    void updateRequest(MvRequest& req) override;
    void grey(bool) override;

protected Q_SLOTS:
    void colourSelected(QColor);
    void transparencySelected(QColor);

protected:
    virtual void updatePixmap();

    QToolButton* tb_;
    ColourSelector* selector_;
    QColor colour_;
    QPixmap pix_;
};

class RibbonColourFontItem : public RibbonColourItem
{
public:
    RibbonColourFontItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);

protected:
    void updatePixmap() override;

    int basePixId_{0};
};

class RibbonGeolockControlItem : public RibbonControlItem
{
public:
    RibbonGeolockControlItem(const MvIconParameter& param, QLayout* layout, QWidget* parent, QString typeKey);
};


class ColourSelector : public QWidget
{
    Q_OBJECT
public:
    ColourSelector(QString, QWidget* parent);
    void init(QColor);

protected Q_SLOTS:
    void valueChanged(QColor col);
    void recentChanged(QColor col);
    void transparencyChanged(int);
    void addCustomColour();
    void addSeparator(QVBoxLayout* vb);
    void delayedCustomColourCall();

signals:
    void selected(QColor);
    void transparencySelected(QColor);

protected:
    void addToRecent(QColor);

    MvQCompactColourGrid* recentGrid_;
    TransparencyWidget* tr_;
    static QMap<QString, QList<QColor>> recentCols_;
    const int maxRecentNum_{10};
    QString idKey_;
    QColor currentColour_;
};


class MvQFeatureRibbonEditor : public QWidget, MvIconLanguageScanner, MvQFeatureItemObserver
{
    Q_OBJECT
public:
    MvQFeatureRibbonEditor(QWidget* parent);
    ~MvQFeatureRibbonEditor();

    void next(const MvIconParameter& p) override;
    void edit(MvQFeatureItemPtr feature);
    void finishEdit();
    void notifyFeatureRequestChanged(MvQFeatureItemPtr) override;

protected Q_SLOTS:
    void itemEdited();
    void itemTransparencyEdited();

protected:
    void showEmpty();
    void clear();
    void clearItems();
    void build();
    void load();
    void addItem(const std::string& rType, const MvIconParameter& p);
    void checkRules(const MvRequest& r);
    void addSeparator();
    void buildRequest(MvRequest& req);

    QHBoxLayout* layout_{nullptr};
    std::string verb_;
    QList<RibbonEditItem*> items_;
    MvQFeatureItemPtr feature_{nullptr};
};
