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

 Copyright 2012 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 <QColor>
#include <QDate>
#include <QFont>
#include <QList>
#include <QVariant>

#include <vector>

class MvQProperty;

class MvQPropertyObserver
{
public:
    MvQPropertyObserver() = default;
    virtual ~MvQPropertyObserver() = default;

    virtual void notifyChange(MvQProperty*) = 0;
};

// This class defines a property storing its value as a QVariant.
// Properties are used to store the viewer's configuration. Editable properties
// store all the information needed to display them in a property editor.
// Properties can have children so trees can be built up from them.

class MvQProperty : public MvQPropertyObserver
{
public:
    explicit MvQProperty(const std::string& name);
    ~MvQProperty() override;

    enum Type
    {
        StringType,
        IntType,
        BoolType,
        ColourType,
        FontType,
        SoundType,
        DateType,
        AreaType
    };

    enum GuiType
    {
        StringGui,
        IntGui,
        BoolGui,
        ColourGui,
        FontGui,
        SoundGui,
        DateGui,
        StringComboGui,
        MultiStringComboGui,
        SoundComboGui,
        AreaGui,
        AddRemoveGui,
        ConditionGui,
        MultiConditionGui,
        SeparatorGui,
        LabelGui
    };

    QString name() const { return name_; }
    const std::string& strName() const { return strName_; }
    QVariant defaultValue() const { return defaultValue_; }
    QVariant value() const;
    std::string valueAsString() const;
    Type type() const { return type_; }
    GuiType guiType() const { return guiType_; }
    QString param(QString name);
    QColor paramToColour(QString name) { return toColour(param(name).toStdString()); }

    void setDefaultValue(const std::string&);
    void setValue(const std::string&);
    void setValue(QVariant);
    void setParam(QString, QString);
    void adjustAfterLoad();

    std::string path();
    MvQProperty* parent() const { return parent_; }
    void setParent(MvQProperty* p) { parent_ = p; }
    bool hasChildren() const { return children_.count() > 0; }
    QList<MvQProperty*> children() const { return children_; }
    void addChild(MvQProperty*);
    MvQProperty* findChild(QString name);
    MvQProperty* find(const std::string& fullPath);
    void collectChildren(std::vector<MvQProperty*>&) const;

    bool changed() const;
    void collectLinks(std::vector<MvQProperty*>&);

    void setLink(MvQProperty* p) { link_ = p; }
    MvQProperty* link() const { return link_; }

    void setMaster(MvQProperty*, bool useMaster = false);
    MvQProperty* master() const { return master_; }
    void setUseMaster(bool);
    bool useMaster() const { return useMaster_; }
    MvQProperty* clone(bool addLink, bool setMaster, bool useMaster = false);

    void addObserver(MvQPropertyObserver*);
    void removeObserver(MvQPropertyObserver*);

    void notifyChange(MvQProperty*) override;

    static bool isColour(const std::string&);
    static bool isFont(const std::string&);
    static bool isSound(const std::string&);
    static bool isDate(const std::string&);
    static bool isArea(const std::string&);
    static bool isNumber(const std::string&);
    static bool isBool(const std::string&);

    static QColor toColour(const std::string&);
    static QFont toFont(const std::string&);
    static QDate toDate(const std::string&);
    static int toNumber(const std::string&);
    static bool toBool(const std::string&);

    static QString toString(QColor col);
    static QString toString(QFont f);

    static void parseArea(QString, QString&, QString&, QString&, QString&);

private:
    void dispatchChange();
    MvQProperty* find(const std::vector<std::string>& pathVec);

    std::string strName_;    // The name of the property as an std::string
    QString name_;           // The name of the property. Used as an id.
    QVariant defaultValue_;  // The default value
    QVariant value_;         // The current value

    MvQProperty* parent_;
    QList<MvQProperty*> children_;
    QList<MvQPropertyObserver*> observers_;
    MvQProperty* master_;
    bool useMaster_;
    Type type_;
    GuiType guiType_;
    QMap<QString, QString> params_;
    MvQProperty* link_;
};
