#ifndef TITAN_PCBCAM_GRAPHVIEW_H
#define TITAN_PCBCAM_GRAPHVIEW_H
#include "../titanpcbcamglobal.h"
#include <QWidget>
#include <QMenu>
#include <QRectF>
#include <QEvent>
#include "../core/job.h"


class PcbCamPopViewWindow;

class PcbCamCanvasPrivate;
class TITAN_PCBCAM_EXPORT PcbCamCanvas : public QWidget
{
    Q_OBJECT
    friend class PcbCamPopViewWindow;

public:
    enum MouseMode {
        ZoomAreaMode,
        SingleSelectionMode,
        RectangleSelectionMode,
        PolygonSelectionMode,
        LayerNetSelectionMode,
        LayerPolylineSelectionMode,
        PanViewMode,
        MeasurePointsMode,
        MeasureSpacingMode,
        PopViewMode,
        SnapFeatMode,
    };

    enum LayerScope {
        WorkLayer = 0x01,
        AffectedLayer = 0x02,
        DisplayLayer = 0x04,
    };
    Q_ENUM(LayerScope)
    Q_DECLARE_FLAGS(LayerScopes, LayerScope)
    Q_FLAGS(LayerScopes)

    struct FeatureInfo {
        PcbCamLayer *layer {nullptr};
        PcbCamFeature *feature {nullptr};
        PcbCamStep *step {nullptr};
        QTransform matrix;
    };

    explicit PcbCamCanvas(QWidget *parent = 0);
    ~PcbCamCanvas();

signals:
    void mousePositionChanged(const QPointF &iPos);
    void messageNotified(const QVariant &iInfo);
    void displayUpdated();
    void selectionChanged();
    void keyPressed(const QString &iKey);
    void snapFeatChanged(const QVariant &iInfo);

public slots:
    void setJobData(PcbCamJob *iJob);
    void fitInView(const QRectF &iRect, bool iSaveHist = true);
    void setCurrentStep(const QString &iStep);
    QString currentStep() const;
    void zoomHome();
    void zoomIn();
    void zoomOut();
    void zoomPrevious();
    void viewLeft(qreal iRate = 0.9);
    void viewRight(qreal iRate = 0.9);
    void viewUp(qreal iRate = 0.9);
    void viewDown(qreal iRate = 0.9);

    void setOrientMatrix(const QTransform &iMatrix);
    QTransform orientMatrix() const;
    QTransform currentMatrix() const;

    void setUnitsType(PcbCam::UnitsType iUnits);
    PcbCam::UnitsType unitsType() const;

    void display(const QString &iLayer, const QString &iColor);
    void resetDisplayLayers(const QMap<QString, QString> &iDispInfo);
    void clearDisplay();
    void refresh();

    void setBgColor(const QString &iBgColor);
    QString bgColor() const;
    void setRubberColor(const QString &iColor);
    QString rubberColor() const;
    void setHighlightColor(const QString &iColor);
    QString highlightColor() const;
    void setSelectionColor(const QString &iColor);
    QString selectionColor() const;
    void setProfileColor(const QString &iColor);
    QString profileColor() const;


    QPointF mapToScene(const QPoint &iPoint) const;
    QRectF mapToScene(const QRect &iRect) const;
    void setMouseMode(const PcbCamCanvas::MouseMode iMouseMode);
    PcbCamCanvas::MouseMode mouseMode() const;

    QList<PcbCamCanvas::FeatureInfo> getFeaturesAt(const QPoint &iPoint, LayerScope iLayerScope, int iTolPix=2) const;
    PcbCamCanvas::FeatureInfo getFirstFeatureAt(const QPoint &iPoint, LayerScope iLayerScope, int iTolPix=2) const;
    QVariantMap snapFeatInfo(const QPoint &iPoint, int iTolPix=2);
    void setSnapFeatRequestKey(const QString &iKey);
    void singleClickSelection(const QPoint &iPoint, PcbCam::FeatureSelectionOperation iSelOp);
    void doubleClickSelection(const QPoint &iPoint, PcbCam::FeatureSelectionOperation iSelOp);
    QList<PcbCamFeature *> selectFeature(const QStringList &iLayers, const QPainterPath &iPath,
                                        const PcbCam::FeatureSelectionFilter &iFilter,
                                        PcbCam::FeatureSelectionOperation iSelOp,
                                        PcbCam::FeatureSelectionMode iMode
                                        );
    QList<PcbCamFeature *> selectedFeatures() const;
    void layerNetSelection(const QStringList &iLayers, const QPoint &iPoint, PcbCam::FeatureSelectionOperation iSelOp, const PcbCam::FeatureSelectionFilter &iFilter);

    void highlightFeature(const QString &iStep,
                          const QStringList &iLayers,
                          const PcbCam::FeatureSelectionFilter &iFilter,
                          PcbCam::FeatureSelectionOperation iSelOp,
                          const QTransform &iMatrix,
                          bool iStepRepeat);
    void clearSelection();
    void clearHighlight();

    void setCheckMeasList(const QVariantList &iData);
    void clearPopView();
    void setMousePoint(const QPointF &iPos);
    void setDrawRelativeOrig(bool iY);
    void setOriginalPoint(double x, double y);
    QPointF originalPoint() const;
    QPointF relativeOriginalPoint() const;

    void setContextMenu(QMenu *iMenu);
    QMenu *contextMenu() const;

    void setCurrentFeatureFilter(const PcbCam::FeatureSelectionFilter &iFilter);
    PcbCam::FeatureSelectionFilter currentFeatureFilter() const;

    void setSnapLayers(const QStringList &iSnapLayers);
    QStringList snapLayers() const;

    void setSnapMode(PcbCam::SnapModes iMode);
    PcbCam::SnapModes snapMode() const;

    void setSnapFeatureType(PcbCam::FeatureTypes iType);
    PcbCam::FeatureTypes snapFeatureType() const;

    QVariantMap getSnapPoint(const QPoint &iCursorPos, int iSnapRange = 20);
    void getSnapPathsInRect(const QString &iStep, const QRectF &iRange, bool iIncludeStepRepeat, const QTransform &iMatrix, QPainterPath &oSnapFeatPaths, QPolygonF &oSnapFeatPoints) const;

    void setDisplayOption(PcbCam::DisplayOptions iDispOption);
    PcbCam::DisplayOptions displayOption() const;

private slots:
    void onPopViewClosed();

private:
    void doSpacingMeasure();
    void doDistMeasure();
    void createPopView(const QRectF &iSourceRect, const QRect &iTargetRect);
    void drawStepLayer(QPainter *painter,
                       const QString &iStep,
                       const QString &iLayer,
                       const QColor &iColor,
                       bool iStepRepeat,
                       const QTransform &iMatrix,
                       const QRectF &iSceneRect,
                       PcbCam::DisplayOptions iDispOption) const;

    void drawStepProfile(QPainter *painter,
                         const QString &iStep,
                         const QColor &iColor,
                         const QTransform &iMatrix,
                         bool iSelected = false) const;

    QPixmap render(const QTransform &iMatrix, const QSize &iSize);
    QPixmap renderChkMeans(const QTransform &iMatrix, const QSize &iSize);


    void showContextMenu(const QPoint &iPos);

protected:
    bool event(QEvent *iEvent) override;
    void paintEvent(QPaintEvent *iEvent) override;
    void resizeEvent(QResizeEvent *) override;
    void wheelEvent(QWheelEvent *event) override;
    void contextMenuEvent(QContextMenuEvent *event) override;

protected:
    const QScopedPointer<PcbCamCanvasPrivate> d_ptr;

private:
    Q_DECLARE_PRIVATE(PcbCamCanvas)
    Q_DISABLE_COPY(PcbCamCanvas)
};


#endif // TITAN_PCBCAM_GRAPHVIEW_H
