/*******************************************************************************************************
 DkImgTransformationsPlugin.h
 Created on:	01.06.2014

 nomacs is a fast and small image viewer with the capability of synchronizing multiple instances

 Copyright (C) 2011-2014 Markus Diem <markus@nomacs.org>
 Copyright (C) 2011-2014 Stefan Fiel <stefan@nomacs.org>
 Copyright (C) 2011-2014 Florian Kleber <florian@nomacs.org>

 This file is part of nomacs.

 nomacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 nomacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

 *******************************************************************************************************/

#pragma once

#include <QImage>
#include <QObject>
#include <QString>
#include <QToolBar>

#include "DkPluginInterface.h"
#include "DkSkewEstimator.h"

class QAction;
class QCheckBox;
class QDoubleSpinBox;
class QPushButton;
class QComboBox;

namespace nmp
{
class DkImgTransformationsViewPort;
class DkImgTransformationsToolBar;
class DkInteractionRects;

enum {
    mode_scale = 0,
    mode_rotate,
    mode_shear,

    mode_end,
};

enum {
    guide_no_guide = 0,
    guide_rule_of_thirds,
    guide_grid,

    guide_end,
};

class DkImgTransformationsPlugin : public QObject, nmc::DkViewPortInterface
{
    Q_OBJECT
    Q_INTERFACES(nmc::DkViewPortInterface)
    Q_PLUGIN_METADATA(IID "com.nomacs.ImageLounge.DkAffineTransformationsPlugin/3.5" FILE
                          "DkAffineTransformationsPlugin.json")

public:
    DkImgTransformationsPlugin();
    ~DkImgTransformationsPlugin() override;

    QImage image() const override;
    bool hideHUD() const override;

    QSharedPointer<nmc::DkImageContainer> runPlugin(
        const QString &runID = QString(),
        QSharedPointer<nmc::DkImageContainer> image = QSharedPointer<nmc::DkImageContainer>()) const override;

    bool createViewPort(QWidget *parent) override;
    nmc::DkPluginViewPort *getViewPort() override;

    void setVisible(bool visible) override;

protected:
    DkImgTransformationsViewPort *mViewport = nullptr;
    DkImgTransformationsToolBar *mToolBar = nullptr;
};

class DkImgTransformationsViewPort : public nmc::DkPluginViewPort
{
    Q_OBJECT

public:
    explicit DkImgTransformationsViewPort(QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
    ~DkImgTransformationsViewPort() override = default;

    bool isCanceled();
    QImage getTransformedImage();

    int defaultMode() const
    {
        return mDefaultMode;
    }

    int guideMode() const
    {
        return mGuideMode;
    }

    bool rotationCropEnabled() const
    {
        return mRotCropEnabled;
    }

    bool angleLinesEnabled() const
    {
        return mAngleLinesEnabled;
    }

public slots:
    void setPanning(bool checked);
    void applyChangesAndClose();
    void discardChangesAndClose();
    void setVisible(bool visible) override;
    void setScaleXValue(double val);
    void setScaleYValue(double val);
    void setShearXValue(double val);
    void setShearYValue(double val);
    void setRotationValue(double val);
    void calculateAutoRotation();
    void setCropEnabled(bool enabled);
    void setAngleLinesEnabled(bool enabled);
    void setGuideStyle(int guideMode);
    void setMode(int mode);

signals:
    void rotationChanged(qreal &);
    void scaleChanged(const QPointF &);
    void shearChanged(const QPointF &);

protected:
    void mouseMoveEvent(QMouseEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;
    void paintEvent(QPaintEvent *event) override;
    void init();
    void drawGuide(QPainter *painter, const QPolygonF &p, int paintMode);

    bool mCancelTriggered;
    bool mPanning;
    QCursor mDefaultCursor;
    DkInteractionRects *mIntrRect;
    QPointF mScaleValues;
    QPointF mShearValues;
    QPointF mShearValuesTemp;
    QPointF mShearValuesDir;
    bool mInsideIntrRect;
    int mIntrIdx;
    int mSelectedMode;
    int mDefaultMode;
    double mRotationValue;
    double mRotationValueTemp;
    QPoint mReferencePoint;
    QPoint mRotationCenter;
    double mImgRatioAngle;
    QCursor mRotatingCursor;
    bool mRotCropEnabled;
    DkSkewEstimator mSkewEstimator;
    bool mAngleLinesEnabled;
    int mGuideMode;
};

class DkImgTransformationsToolBar : public QToolBar
{
    Q_OBJECT

public:
    enum {
        apply_icon = 0,
        cancel_icon,
        pan_icon,
        scale_icon,
        rotate_icon,
        shear_icon,

        icons_end,
    };

    enum {
        settings_mode = 0,
        settings_guide,
        settings_crop,
        settings_lines,

        settings_end,
    };

    DkImgTransformationsToolBar(const QString &title, int defaultMode, QWidget *parent = nullptr);
    ~DkImgTransformationsToolBar() override;

    void setRotationValue(double val);
    void setScaleValue(QPointF val);
    void setShearValue(QPointF val);
    void setCropState(int val);
    void setGuideLineState(int val);
    void setAngleLineState(int val);

public slots:
    void setVisible(bool visible) override;

signals:
    void applySignal();
    void cancelSignal();
    void scaleXValSignal(double val);
    void scaleYValSignal(double val);
    void shearXValSignal(double val);
    void shearYValSignal(double val);
    void rotationValSignal(double val);
    void calculateAutoRotationSignal();
    void cropEnabledSignal(bool enabled);
    void showLinesSignal(bool enabled);
    void panSignal(bool checked);
    void modeChangedSignal(int mode);
    void guideStyleSignal(int guideMode);

protected:
    void createLayout(int defaultMode);
    void createIcons();
    void modifyLayout(int mode);
    void saveSetting(int val, int type);

    QDoubleSpinBox *mScaleXBox;
    QDoubleSpinBox *mScaleYBox;
    QDoubleSpinBox *mShearXBox;
    QDoubleSpinBox *mShearYBox;
    QDoubleSpinBox *mRotationBox;
    QCheckBox *mCropEnabledBox;
    QPushButton *mAutoRotateButton;
    QCheckBox *mShowLinesBox;
    QMap<QString, QAction *> mToolbarWidgetList;
    QComboBox *mGuideBox;

    QAction *mPanAction;
    QVector<QIcon> mIcons; // needed for colorizing
};

class DkInteractionRects : public QWidget
{
    Q_OBJECT

public:
    explicit DkInteractionRects(QRect imgRect, QWidget *parent = nullptr, Qt::WindowFlags f = Qt::Widget);
    explicit DkInteractionRects(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::Widget);
    ~DkInteractionRects() override;

    void draw(QPainter *painter);
    void updateRects(QRect imgRect);
    QCursor getCursorShape(int idx);
    QVector<QRect> getInteractionRects();
    void setInitialValues(QRect rect);
    QSize getInitialSize();
    QPointF getInitialPoint(int idx);
    QPoint getCenter();

protected:
    void init();

    QVector<QRect> mIntrRect;
    QVector<QCursor> mIntrCursors;
    QVector<QPointF> mInitialPoints;
    QSize mInitialSize;
    QSize mSize;
};

};
