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

#include <QGraphicsWidget>
#include <QPen>

#include "MvQPlotItem.h"

class QImage;
class QPainter;
class QPixmap;

class MgQMagnifierLayoutItem;

class MvQMagnifierFactorCell
{
public:
    MvQMagnifierFactorCell(float value, QColor colour) :
        value_(value),
        colour_(colour) {}
    float value_;
    QColor colour_;
};


class MvQMagnifierSlider
{
public:
    MvQMagnifierSlider(QList<float>&, int, QColor);
    void setGeometry(float);

    float cellSweepAngle() { return cellSweepAngle_; }
    float cellInnerRadius() { return cellInnerRadius_; }
    float cellOuterRadius() { return cellOuterRadius_; }

    const MvQMagnifierFactorCell* cell(int i) const { return cells_[i]; }
    float factorValue(int i) { return cells_.at(i)->value_; }
    QColor& cellColour(int i) { return cells_.at(i)->colour_; }
    float actFactorValue() { return cells_.at(actCellIndex_)->value_; }
    int cellNum() { return cells_.count(); }
    float cellBarStartAngle() { return cellBarStartAngle_; }
    float cellBarSweepAngle() { return cellBarSweepAngle_; }

    float panelInnerRadius() { return panelInnerRadius_; }
    float panelOuterRadius() { return panelOuterRadius_; }

    int actCellIndex() { return actCellIndex_; }
    void setActCellIndex(int i) { actCellIndex_ = i; }
    float actCellAngle();

    bool checkPointInHandler(float, float);
    bool checkPointInCell(float, float, int&);
    bool checkPointInPanel(float, float);

    float handlerSize() { return handlerSize_; }
    void setHandlerSize(float s) { handlerSize_ = s; }
    bool shiftHandler(float, float, int&);
    void handlerCentre(float&, float&);

public:
    float radius_{1.};
    float actCellIndex_{0};
    float handlerSize_{0.};

    // Cell item
    float cellSweepAngle_{0.};
    float cellWidth_{6};
    float cellHeight_{13};
    float cellInnerRadius_{0.};
    float cellOuterRadius_{0.};

    // All the cells
    float cellBarStartAngle_{0.};
    float cellBarEndAngle_{0.};
    float cellBarSweepAngle_{0.};
    QList<MvQMagnifierFactorCell*> cells_;

    // Panel
    float panelWidth_{0.};
    float panelInnerRadius_{0.};
    float panelOuterRadius_{0.};
};


class MagnifierFrameData
{
public:
    MagnifierFrameData(float, float, float, int);
    bool checkRadius(float r) { return r >= minRadius_ && r < maxRadius_; }

    float width_;
    float minRadius_;
    float maxRadius_;
    std::vector<float> coeffCos_;
    std::vector<float> coeffSin_;
    int ptNum_;
};


class MvQMagnifier : public MvQPlotItem
{
    Q_OBJECT

public:
    enum MagnifierAction
    {
        NoAction,
        MoveAction,
        ResizeAction,
        HandlerAction
    };
    enum ScenePointType
    {
        InnerScenePoint,
        CoveredScenePoint,
        OuterScenePoint
    };

    MvQMagnifier(MgQPlotScene*, MvQPlotView*, QGraphicsItem* parent = nullptr);
    ~MvQMagnifier() override;

    void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override;
    QRectF boundingRect() const override;
    bool contains(const QPointF&) const override;

    void render(QPainter* painter);

    void setActivated(bool) override;
    void prepareForReset() override;
    void reset() override;
    MagnifierAction magnifierAction() { return magnifierAction_; }
    float zoomFactor() { return actSlider_->actFactorValue(); }
    bool checkPointInMagnifier(const QPointF&);
    ScenePointType identifyScenePoint(const QPointF&);
    QPointF sceneToMagnifiedPos(const QPointF&);
    QPointF magnifiedToScenePos(const QPointF&);

    void mousePressEventFromView(QMouseEvent*) override;
    void mouseMoveEventFromView(QMouseEvent*) override;
    void mouseReleaseEventFromView(QMouseEvent*) override;

signals:
    void factorChanged();
    void positionChanged();

private:
    enum MagnifierPointType
    {
        LensPoint,
        FramePoint,
        SliderHandlerPoint,
        SliderCellPoint,
        OuterPoint
    };
    enum MagnifierMode
    {
        TextMode,
        DataMode
    };

    bool checkPointInWindow(const float, const float) const;
    bool checkCircleInWindow(const float, const float, const float) const;

    bool checkPointInMagnifier(const int, const int);
    MagnifierPointType identifyPoint(const QPointF&);

    void renderFrame(QPainter*);
    void renderSlider(QPainter*);
    void createRingSlice(QPainterPath&, float, float, float, float);

    void changeMagnifierMode();
    void updateMagnifierState();

    MagnifierMode magnifierMode_{TextMode};
    MagnifierAction magnifierAction_{NoAction};
    MvQMagnifierSlider* actSlider_;
    QMap<MagnifierMode, MvQMagnifierSlider*> sliders_;
    int actCellIndexAtHandlerActionStart_{0};
    int actFrameIndex_{0};
    std::vector<MagnifierFrameData> frames_;

    QPointF dragPos_;
    float radius_{100.};
    float minRadius_{50.};
    float innerFrameWidth_{3.};
    float outerFrameWidth_{7.};
    float frameWidth_{0.};
    float centreX_{0.};
    float centreY_{0.};
    int minX_{0};
    int maxX_{0};
    int minY_{0};
    int maxY_{0};
    int refX_{0};
    int refY_{0};
    int prevX_{0};
    int prevY_{0};

    bool pointInMagnifier_{false};
    bool mouseInLens_{false};
    bool magnifierModeChanged_{false};

    QGraphicsScene* dataScene_{nullptr};
    MgQMagnifierLayoutItem* dataItem_{nullptr};
    QImage* device_{nullptr};
    QPainter* painter_{nullptr};
    QPen cellPen_{QColor(50, 50, 50)};
    QPixmap* handlerPixmap_{nullptr};
};
