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

 Copyright 202w 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 <map>
#include <string>
#include <vector>

#include <QBrush>
#include <QPen>
#include <QPixmap>
#include <QSize>
#include <QString>

#include "mars.h"

class MvRequest;
class MvIconClassCore;
class WmoWeatherSymbol;

class WsGroup
{
public:
    WsGroup(const MvRequest& r);
    WsGroup(QString name, QString label, QString desc);
    WsGroup(const WsGroup&) = delete;
    WsGroup& operator=(const WsGroup&) = delete;

    QString name() const { return name_; }
    QString label() const { return label_; }
    QString description() const { return desc_; }
    static const std::vector<WsGroup*>& items() { return items_; }

protected:
    QString name_;
    QString label_;
    QString desc_;
    static std::vector<WsGroup*> items_;
};

class WsType
{
public:
    enum Mode
    {
        NoMode,
        DesktopMode,
        PlotWindowMode,
        CodeGenerateMode
    };
    WsType() = default;
    WsType(const WsType&) = delete;
    WsType& operator=(const WsType&) = delete;
    virtual ~WsType() = default;

    virtual QString name() const = 0;
    virtual QString nameFromRequest(const MvRequest&) const = 0;
    virtual QString label() const = 0;
    virtual QString description() const = 0;
    virtual QString grItemType() const = 0;
    virtual QString reqVerb() const = 0;
    virtual QString geojsonType() const = 0;
    virtual QString group() const = 0;
    virtual QString subGroup() const = 0;
    virtual QPixmap defaultPixmap() const;
    virtual QPixmap pixmap(int width, int height, QColor fgCol = QColor(Qt::black), QPen boxPen = QPen(Qt::NoPen), QBrush boxBrush = QBrush(Qt::NoBrush)) const = 0;
    virtual QPixmap pixmapWithChar(int width, int height, QColor fg, QChar /*ch*/) const { return pixmap(width, height, fg); }
    virtual QSize sizeInPx() const { return {}; }
    virtual void updateTypeInReq(MvRequest&) = 0;

    static const std::vector<WsType*>& items() { return items_; }
    static WsType* find(QString reqVerb, QString name);
    static WsType* findByReq(const MvRequest&);
    static MvRequest expandRequest(const MvRequest&, long flags = EXPAND_DEFAULTS);
    static void init(Mode);
    static int defaultPixSize() { return defaultPixSize_; }

    // for SimpleLoader
    static void load(request* r);

protected:
    virtual bool matchReq(QString verb, QString reqType, QString reqUserType) const = 0;

    static Mode mode_;
    static int defaultPixSize_;
    mutable QPixmap pix_;
    static WsType* userImageAllItem_;
    static WsType* wmoAllItem_;

private:
    static void load_system_feature_items();
    static void load_user_feature_items();
    static void load_wmo_symbols();

    static std::vector<WsType*> items_;
    static std::map<std::string, MvIconClassCore*> cls_;
};

class WsStandardType : public WsType
{
public:
    WsStandardType(const MvRequest&);
    WsStandardType(const WsStandardType&) = delete;
    WsStandardType& operator=(const WsStandardType&) = delete;

    QString name() const override { return name_; }
    QString nameFromRequest(const MvRequest&) const override { return name_; }
    QString label() const override { return label_; }
    QString description() const override { return desc_; }
    QString grItemType() const override { return grItemType_; }
    QString reqVerb() const override { return reqVerb_; }
    QString geojsonType() const override { return geojsonType_; }
    QString group() const override { return group_; }
    QString subGroup() const override { return {}; }
    QPixmap pixmap(int width, int height, QColor fg, QPen boxPen, QBrush boxBrush) const override;
    void updateTypeInReq(MvRequest&) override {}

protected:
    bool matchReq(QString verb, QString reqType, QString reqUserType) const override;
    QString iconPath() const;

    QString name_;
    QString label_;
    QString desc_;
    QString grItemType_;
    QString geojsonType_;
    QString reqVerb_;
    QString iconName_;
    QString group_;
};

class WsStandardMultiType : public WsStandardType
{
public:
    using WsStandardType::WsStandardType;
    void updateTypeInReq(MvRequest&) override;

protected:
    bool matchReq(QString verb, QString reqType, QString reqUserType) const override;
};

class WsSvgImageType : public WsStandardMultiType
{
public:
    WsSvgImageType(const MvRequest&);
    QPixmap pixmap(int width, int height, QColor fg, QPen boxPen, QBrush boxBrush) const override;

protected:
    QString svgTemplateColour_;
};

class WsCharImageType : public WsStandardType
{
public:
    WsCharImageType(const MvRequest&);
    QPixmap pixmapWithChar(int width, int height, QColor fg, QChar ch) const override;

protected:
    QString svgTemplateColour_;
    QChar svgTemplateChar_;
};

class WsUserImageAllType : public WsStandardType
{
public:
    using WsStandardType::WsStandardType;
    QString nameFromRequest(const MvRequest&) const override;
};

class WsWmoAllType : public WsStandardType
{
public:
    using WsStandardType::WsStandardType;
    QString nameFromRequest(const MvRequest&) const override;
};


class WsUserImageSingleType : public WsType
{
    friend class WsType;

public:
    WsUserImageSingleType(const WsUserImageSingleType&) = delete;
    WsUserImageSingleType& operator=(const WsUserImageSingleType&) = delete;

    QString name() const override;
    QString nameFromRequest(const MvRequest&) const override;
    QString label() const override { return label_; }
    QString description() const override { return desc_; }
    QString grItemType() const override;
    QString reqVerb() const override;
    QString geojsonType() const override;
    QString group() const override;
    QString subGroup() const override { return {}; }
    QPixmap pixmap(int width, int height, QColor fg, QPen boxPen, QBrush boxBrush) const override;
    QSize sizeInPx() const override;
    void updateTypeInReq(MvRequest&) override;

protected:
    WsUserImageSingleType(QString iconName, QString iconDir);
    bool matchReq(QString reqVerb, QString reqType, QString reqUserType) const override;
    QString iconPath() const;

    QString name_;
    QString label_;
    QString desc_;
    QString iconName_;
    QString iconDir_;
};

class WsWmoSingleType : public WsType
{
public:
    WsWmoSingleType(WmoWeatherSymbol*);
    WsWmoSingleType(const WsWmoSingleType&) = delete;
    WsWmoSingleType& operator=(const WsWmoSingleType&) = delete;

    QString name() const override;
    QString nameFromRequest(const MvRequest&) const override;
    QString label() const override;
    QString description() const override;
    QString grItemType() const override;
    QString reqVerb() const override;
    QString geojsonType() const override;
    QString group() const override;
    QString subGroup() const override;
    QPixmap defaultPixmap() const override;
    QPixmap pixmap(int width, int height, QColor fg, QPen boxPen, QBrush boxBrush) const override;
    void updateTypeInReq(MvRequest&) override;

protected:
    bool matchReq(QString reqVerb, QString reqType, QString reqUserType) const override;

    WmoWeatherSymbol* symbol_{nullptr};
};
