#ifndef IMAGEWIDGET_H
#define IMAGEWIDGET_H

#include <memory>
#include <QOpenGLWidget>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLFunctions>
#include <QPainterPath>
#include "database.h"
#include "rawimage.h"
#include "imageinfodata.h"
#include "stretchtoolbar.h"

class ImageWidget
{
public:
    ImageWidget(){}
    virtual ~ImageWidget(){}

    virtual void setImage(std::shared_ptr<RawImage> image, int index) = 0;
    virtual void setWCS(std::shared_ptr<WCSDataT> wcs) = 0;

    virtual void zoom(int zoom, const QPointF &mousePos = QPointF()) = 0;
    virtual void bestFit() = 0;

    virtual void setBayerMask(int mask) = 0;
    virtual void setColormap(int colormap) = 0;
    virtual void setOffset(float dx, float dy) = 0;
    virtual void allocateThumbnails(const QStringList &paths) = 0;

    virtual void setMTFParams(const MTFParam &params) = 0;
    virtual void superPixel(bool enable) = 0;
    virtual void invert(bool enable) = 0;
    virtual void falseColor(bool enable) = 0;
    virtual QImage renderToImage() = 0;
    virtual void thumbnailLoaded(const Image *image) = 0;
    virtual void showThumbnail(bool enable) = 0;
    virtual void drawGrid(bool enable) = 0;

    static QImage loadColormap();
};

struct ImageThumb
{
    QString name;
    QString path;
    QSize size;
    bool selected;
    bool dirty;
};

class ImageWidgetGL : public QOpenGLWidget, public ImageWidget
{
    Q_OBJECT
    QOpenGLFunctions *f = nullptr;
    QOpenGLExtraFunctions *fx = nullptr;
    QTimer *m_updateTimer = nullptr;
    std::unique_ptr<QOpenGLShaderProgram> m_program;
    std::unique_ptr<QOpenGLShaderProgram> m_thumbnailProgram;
    std::unique_ptr<QOpenGLShaderProgram> m_debayerProgram;
    std::unique_ptr<QOpenGLBuffer> m_buffer;
    std::unique_ptr<QOpenGLBuffer> m_bufferSizes;
    std::unique_ptr<QOpenGLTexture> m_image;
    std::unique_ptr<QOpenGLVertexArrayObject> m_vao;
    std::unique_ptr<QOpenGLVertexArrayObject> m_vaoThumb;
    std::unique_ptr<QOpenGLTexture> m_thumbnailTexture;
    std::unique_ptr<QOpenGLTexture> m_lut;
    std::unique_ptr<QOpenGLTexture> m_colormap;
    GLuint m_debayerTex = 0;
    std::shared_ptr<RawImage> m_rawImage;
    std::shared_ptr<WCSDataT> m_wcs;
    SkyGrid m_grid;
    int m_width, m_height;
    int m_imgWidth = -1, m_imgHeight = -1;
    int m_currentImg = 0;
    MTFParam m_mtfParams;
    float m_unit_scale[2] = {1.0f, 0.0f}; // scale and offset
    float m_dx = 0, m_dy = 0;
    float m_scale = 1.0f;
    int m_scaleStop = 0;
    bool m_bestFit = false;
    bool m_bwImg = false;
    bool m_falseColor = false;
    bool m_invert = false;
    bool m_superpixel = false;
    bool m_showThumbnails = false;
    bool m_selecting = false;
    bool m_sizesDirty = false;
    bool m_srgb = false;
    bool m_drawGrid = false;
    int m_thumbnailCount = 0;
    int m_maxTextureSize = 0;
    int m_maxArrayLayers = 0;
    int m_firstRed[2] = {0, 0};
    int m_colormapIdx = 0;
    QVector<ImageThumb> m_thumnails;
    Database *m_database = nullptr;
    QPointF m_lastPos;
    QString m_error;
    bool  m_swPaint = false;
public:
    explicit ImageWidgetGL(Database *database, QWidget *parent = nullptr);
    ~ImageWidgetGL() override;
    void setImage(std::shared_ptr<RawImage> image, int index) override;
    void setWCS(std::shared_ptr<WCSDataT> wcs) override;
    void zoom(int zoom, const QPointF &mousePos = QPointF()) override;
    void bestFit() override;
    void allocateThumbnails(const QStringList &paths) override;
    QVector2D getImagePixelCoord(const QVector2D &pos);
    void setBayerMask(int mask) override;
    void setColormap(int colormap) override;
    void setOffset(float dx, float dy) override;
    void setMTFParams(const MTFParam &params) override;
    void superPixel(bool enable) override;
    void invert(bool enable) override;
    void falseColor(bool enable) override;
    QImage renderToImage() override;
    void thumbnailLoaded(const Image *image) override;
    void showThumbnail(bool enable) override;
    void drawGrid(bool enable) override;
protected:
    void paintGL() override;
    void resizeGL(int w, int h) override;
    void initializeGL() override;
    void dragEnterEvent(QDragEnterEvent *event) override;
    void dropEvent(QDropEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;
    void wheelEvent(QWheelEvent *event) override;
    void thumbSelect(QMouseEvent *event);
    void debayer();
    void updateScrollBars();
signals:
    void fileDropped(const QString &path);
    void status(const QString &value, const QString &pixelCoords, const QString &celestialCoords);
    void scrollBarsUpdate(int valueH, int stepH, int maxH, int valueV, int stepV, int maxV);
};

#endif // IMAGEWIDGET_H
