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

#include <QList>
#include <QPoint>
#include <QRectF>

#include "MvRequest.h"

#include "MvQFeatureFwd.h"

class QLabel;
class QMouseEvent;
class QGraphicsItem;
class QJsonDocument;
class QJsonArray;
class QJsonObject;
class QPlainTextEdit;
class QUndoStack;
class MgQLayoutItem;
class MvQFeatureCommandTarget;
class MvQFeatureCurveBaseItem;
class MvQFeatureSelector;
class MvQPlotView;
class MvQFeatureHandler;
class MvQFeatureRibbonEditor;
class MvQFeatureTextItem;
class MvQFeatureTextEditor;
class WsType;
struct FeatureAddSpec;

class MvQFeatureHandler
{
public:
    MvQFeatureHandler(const MvQFeatureHandler&) = delete;
    MvQFeatureHandler& operator=(const MvQFeatureHandler&) = delete;
    static MvQFeatureHandler* Instance();

    void setView(MvQPlotView*);
    void setUndoStack(QUndoStack* s);
    void setRibbonEditor(MvQFeatureRibbonEditor*);
    void setInfoWidget(QPlainTextEdit*);
    MvQPlotView* view() const { return view_; }

    void clearSelection();
    void checkSelection();
    void adjustSelection();

    void currentLayout(MvQFeatureItemPtr item, MgQLayoutItem** layoutItem) const;

    void removeFromScene(MvQFeatureItemList item);
    void addToScene(MvQFeatureItemPtr item);
    void addToScene(MvQFeatureItemList item, bool visible = false);

    void registerToAddAtClick(WsType*);
    void registerToAddAtClick(const QJsonDocument& doc);
    void addFromView(QPoint pos);

    MvQFeatureItemList performDuplicate(MvQFeatureItemList item);
    void addFromJson(const QJsonDocument&);
    void addFromRequest(const MvRequest&);
    void addFromClipboard(const QPointF& pos);
    void runCommand(const MvQFeatureCommandTarget& sel, QString cmd);
    void identifyComandTarget(MvQFeatureCommandTarget* ct);

    MvQFeatureSelector* selector() const { return selector_; }
    const MvQFeatureItemList& features() const { return features_; }
    void swapByZValue(MvQFeatureItemPtr item, float z);

    void updateStyle(MvQFeatureItemPtr item, const MvRequest& req, StyleEditInfo info = StyleEditInfo::StandardStyleEdit);

    void setText(MvQFeatureItemPtr item, QString text);
    void editText(MvQFeatureItemPtr item);
    bool checkMousePressForTextEditor(const QPointF& scenePos);
    void checkMouseMove(QMouseEvent* viewEvent);
    void dragTextEditor(MvQFeatureTextEditor*);

    void moveNode(MvQFeatureItemPtr curve, const QPointF& pp, int nodeIndex, bool start);
    void moveBy(MvQFeatureItemList items, const QPointF& delta, bool start);
    void resize(MvQFeatureItemList items, const QRectF& newRect, const QRectF& oriRect, bool start);

    void resetBegin();
    void resetEnd();

    bool canAcceptMouseEvent() const;

    // should handle the cursor setting for all the features
    void setDragCursor() const;
    void setCurvePointCursor() const;
    void resetCursor() const;

protected:
    MvQFeatureHandler() = default;

    void init();
    QGraphicsItem* rootItem() const;
    void makeSelector();
    MgQLayoutItem* layoutItemAt(const QPointF& scPos) const;
    bool isOutOfView(const QPointF& scPos, MgQLayoutItem* layoutItem) const;
    bool canBeAddedToScene(MvQFeatureItemPtr item, const QPointF& scPos, MgQLayoutItem** layoutItem) const;
    bool canBePastedToScene(MvQFeatureItemPtr item, const QPointF& scPos, MgQLayoutItem** layoutItem) const;
    bool hasLayout() const;
    void removeTextEditor();
    void add(WsType*, QPoint pos);
    void addFromJson(const QJsonArray&);
    void addFromJson(const QJsonObject&);
    void paste(const QJsonDocument& doc, const QPointF& scPos);
    void handleItemCommand(MvQFeatureItemPtr targetItem, QString cmd, int nodeIndex,
                           const QPointF& scenePos);
    void handleSelectorCommand(QString cmd, const QPointF& scenePos);
    void updateFeatureInfo(MvQFeatureItemPtr);
    void saveItemToDisk(MvQFeatureItemPtr item);
    void saveSceneToDisk(const QPointF& scPos);
    void saveToDisk(const QJsonDocument& doc);

    static MvQFeatureHandler* instance_;
    bool initDone_{false};
    MvQPlotView* view_{nullptr};
    MvQFeatureSelector* selector_{nullptr};
    MvQFeatureItemList features_;
    QUndoStack* undoStack_{nullptr};
    MvQFeatureRibbonEditor* ribbonEditor_{nullptr};
    MvQFeatureTextEditor* textEditor_{nullptr};
    QPlainTextEdit* infoWidget_{nullptr};
    std::shared_ptr<FeatureAddSpec> featureToAddAtClick_;
    std::shared_ptr<FeatureAddSpec> featureToAddAtGeo_;
};
