/***************************** 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 *************************************/

#ifndef MVQFEATUREITEM_H
#define MVQFEATUREITEM_H

#include "MvRequest.h"

#include <QElapsedTimer>
#include <QGraphicsItem>
#include <QMimeData>
#include <QPixmap>
#include <QPen>
#include <QStringList>
#include <QTextStream>
#include <QUndoCommand>

class QMouseEvent;
class MgQLayoutItem;
class MvQFeatureCommandTarget;
class MvQFeatureHandler;
class MvQFeatureType;
class MvQFeatureItem;
class MvQFeatureSelector;
class MvQPlotView;


namespace MvQ {
const int FeatureItemType = QGraphicsItem::UserType + 1;
}

class MvQFeatureItemObserver;

class MvQFeatureGeometry
{
public:
    QRectF bRect_;
    QRectF itemRect_;
    QRectF textRect_;
    QPointF pos_;
    QPointF geoCoord_{QPointF(0., 0.)};
    QVector<QPointF> pointsScenePos_;
    QVector<QPointF> pointsGeoCoord_;
};

class MvQFeatureDescriber
{
public:
    MvQFeatureDescriber();
    QString text() const {return txt_;}
    void addTitle(QString val);
    void add(QString label, void* p);
    void add(QString label, QVariant val);

private:
    QString txt_;
    QTextStream s_;
    static QString indent_;
};

class MvQFeatureItem : public QGraphicsItem
{
    friend class SelectorState;
    friend class SelectorPointEditState;
    friend class MvQFeatureSelector;
    friend class MvQFeatureHandler;
    friend class MvQFeatureToFrontCommand;
    friend class MvQFeatureToForwardCommand;
    friend class MvQFeatureToBackCommand;
    friend class MvQFeatureToBackwardCommand;
    friend class MvQFeatureFlipCommand;
    friend class MvQFeatureAddNodeCommand;
    friend class MvQFeatureRemoveNodeCommand;
    friend class MvQFeatureMoveNodeCommand;

public:
    enum CurrentAction {NoAction, MoveAction, ResizeAction, CreationAction, InsertAction, PointEditEnterAction, PointEditAction};
    enum AnchorPosition { CentreAnchor, BottomCentreAnchor};
    enum
    {
        Type = MvQ::FeatureItemType
    };

    enum StyleEditInfo {StandardStyleEdit, TransparencyStyleEdit, SizeStyleEdit};

    MvQFeatureItem(MvQFeatureType* ,MvQPlotView*, QGraphicsItem* parent=nullptr, QString typeName=QString());
    virtual ~MvQFeatureItem();

    virtual MvQFeatureItem* clone() const {return nullptr;}
    const MvQFeatureItem& operator=(const MvQFeatureItem&) = delete;

    QRectF boundingRect() const override {return bRect_;}
    int type() const override { return Type; }
    QString typeName() const;
    QString typeDescription() const;
    QRectF itemRect() const {return itemRect_;}
    QPointF scenePos() const;
    QPointF copiedScenePos() const {return copiedScenePos_;}

    MvQPlotView* plotView() const {return plotView_;}
    MvQFeatureType* feature() const {return feature_;}
    MgQLayoutItem* dataLayout() const {return dataLayout_;}
    bool highlighted() const { return highlighted_; }
    virtual bool canBeCreatedOutOfView() const { return true;}
    virtual bool canBePastedOutOfView() const { return true;}
    const std::string& sceneId() const {return sceneId_;}

    CurrentAction currentAction() const {return currentAction_;}
    const MvRequest& styleRequest() const {return req_;}
    virtual void setStyle(const MvRequest& req={});

    virtual QPointF geoCoord() const { return geoCoord_; }
    void initScenePosition(MgQLayoutItem*, const QPointF&);
    virtual void prepareForProjectionChange() {}
    virtual void projectionChanged(MgQLayoutItem*);
    virtual void checkLayoutOnMove();

    void setHighlighted(bool);

    virtual void moveBy(QPointF);
    virtual void moveTo(const MvQFeatureGeometry&);
    virtual void resize(QRectF rect)=0;
    virtual void resizeTo(const MvQFeatureGeometry&)=0;
    void adjustSizeToSelector(QRectF rectNew, QRectF rectOri);
    virtual void resizeFinished() {}

    virtual QString text() const {return {};}
    virtual void setText(QString) {}

    virtual QStringList disabledCommands(int /*nodeIdx=-1*/) const {return {};}
    bool identifyCommandTarget(MvQFeatureCommandTarget* s);
    void styleEdited(MvRequest& req);
    void styleEditedInRibbon(MvRequest& req, StyleEditInfo info=StandardStyleEdit);
    bool keepAspectRatio() const {return keepAspectRatio_;}
    virtual void initContents() {}
    virtual QSizeF minSize() const;
    qint64  elapsedSinceLastPressed() const {return lastPressed_.elapsed();}

    virtual bool isPoint() const {return false;}
    virtual bool hasPoints() const {return false;}
    virtual bool hasEditableText() const {return false;}
    virtual bool isLine() const {return false;}
    virtual void enterPointEdit() {}
    virtual void startPointEdit() {}
    virtual void leavePointEdit() {}
    virtual bool hasEditedPoint() {return false;}
    virtual void editText() {}

    static float bottomZValue() {return bottomZValue_;}
    static float topZValue() {return topZValue_;}
    static float zValueIncrement() {return zValueIncrement_;}
    static float nextZValue() {return nextZValue_;}

    virtual const std::string& frontSubType() const {static std::string emptyStr; return emptyStr;}
    virtual void setFrontSubType(const std::string&) {}

    virtual MvQFeatureGeometry getGeometry() const;
    virtual QString describe() const;

    void addObserver(MvQFeatureItemObserver*);
    void removeObserver(MvQFeatureItemObserver*);

protected:
    MvQFeatureItem(const MvQFeatureItem&);
    void mousePressEvent(QGraphicsSceneMouseEvent* event) override;
    void mouseMoveEvent(QGraphicsSceneMouseEvent* event) override;
    void mouseReleaseEvent(QGraphicsSceneMouseEvent* event) override;
    void hoverEnterEvent(QGraphicsSceneHoverEvent*) override;
    void hoverLeaveEvent(QGraphicsSceneHoverEvent*) override;
    QVariant itemChange(GraphicsItemChange change, const QVariant& value) override;
    QRectF rectToSelector(QRectF rectNew, QRectF rectOri);

    void adjustGeoCoord();
    QPointF computeGeoCoord();
    QPointF computeGeoCoord(QPointF scPos);
    static bool isValidPoint(QPointF p);
    virtual void initAtGeoCoord(QPointF);
    virtual void initAtScenePos(const QPointF&);
    virtual void reproject();
    void inspectProjection();

    virtual void makePixmap() {}
    virtual void updateSymbols() {}
    virtual void adjustBRect() {}
    void editStyle();
    void initStyle();
    virtual double halo() const {return 0.;}

    virtual void moveNodeTo(int /*nodeIndex*/, const QPointF& /*scenePos*/) {}
    virtual void addNode(int /*node*/, bool) {}
    virtual void addNode(int /*node*/, const QPointF&) {}
    virtual void removeNode(int /*nodeIdx*/) {}
    virtual int nodeForContextMenu(const QPointF&) {return -1;}

    virtual double realZValue() const;
    virtual void setRealZValue(double z);

    virtual void flipSymbolDirection() {}
    virtual bool getRequestParameters() {return false;}
    void setClipping(QPainter* painter);

    void broadcastRequestChanged();
    void broadcastDelete();

    MvQFeatureType *feature_{nullptr};
    MvQPlotView* plotView_{nullptr};
    MvQFeatureHandler* featureHandler_{nullptr};
    MvQFeatureSelector* selector_{nullptr};
    CurrentAction currentAction_{NoAction};
    MgQLayoutItem* dataLayout_{nullptr};
    QRectF bRect_;
    QRectF itemRect_;
    QPointF dragPos_;
    QPointF copiedScenePos_;
    bool outOfView_{true};
    bool highlighted_{false};
    bool keepAspectRatio_{false};
    AnchorPosition anchorPos_{CentreAnchor};
    QPointF geoCoord_{QPointF(0., 0.)};
    bool hasValidGeoCoord_{false};
    bool projPeriodic_{false};
    std::string sceneId_;
    MvRequest req_;
    static const float bottomZValue_;
    static const float topZValue_;
    static const float zValueIncrement_;
    static float nextZValue_;
    QString typeName_;
    QElapsedTimer lastPressed_;
    QPointF lastPressedPos_;
    std::vector<MvQFeatureItemObserver*> observers_;
    static QColor devModeColor_;

private:
    void initInner();
};


#endif // MVQFEATUREITEM_H

