#ifndef RAWIMAGE_H
#define RAWIMAGE_H

#include "libxisf.h"
#include <vector>
#include <memory>
#include <stdint.h>
#include <math.h>
#include <memory.h>
#ifndef NO_QT
#include <QImage>
#endif
#include "mtfparam.h"

extern int THUMB_SIZE;
extern int THUMB_SIZE_BORDER;
extern int THUMB_SIZE_BORDER_Y;
extern bool QUALITY_RESIZE;

class Peak
{
    uint32_t m_v;
    uint32_t m_x,m_y;
public:
    Peak() : m_v(0), m_x(0), m_y(0) {}
    Peak(uint32_t v, uint32_t x, uint32_t y) : m_v(v), m_x(x), m_y(y) {}
    uint32_t v() const { return m_v; }
    uint32_t x() const { return m_x; }
    uint32_t y() const { return m_y; }
    double distance(const Peak &d) const
    {
        uint32_t dx = m_x-d.m_x;
        uint32_t dy = m_y-d.m_y;
        return dx*dx + dy*dy;
    }
    bool operator <(const Peak &d) const
    {
        return m_v > d.m_v;
    }
};

class RawImage
{
    using PixelType = uint8_t;
public:
    enum DataType
    {
        UINT8,
        UINT16,
        UINT32,
        FLOAT16,
        FLOAT32,
        FLOAT64,
    };
    struct Stats
    {
        bool m_stats = false;
        double m_mean[4] = {0.0};
        double m_stdDev[4] = {0.0};
        double m_median[4] = {0.0};
        double m_min[4] = {0.0};
        double m_max[4] = {0.0};
        double m_mad[4] = {0.0};
        uint32_t m_saturated[4] = {0};
        std::vector<uint32_t> m_histogram;
    };
protected:
    std::unique_ptr<PixelType[]> m_pixels;
    std::unique_ptr<PixelType[]> m_original;
    uint32_t m_width = 0;
    uint32_t m_height = 0;
    uint32_t m_origWidth = 0;
    uint32_t m_origHeight = 0;
    uint32_t m_channels = 0;
    uint32_t m_ch = 0;
    DataType m_type = UINT8;
    DataType m_origType = UINT8;
    float m_thumbAspect = 0.0;
    Stats m_stats;
    bool m_planar = false;
    std::vector<uint8_t> m_iccProfile;
    std::vector<uint16_t> m_lut;// actually qfloat16
    void allocate(uint32_t w, uint32_t h, uint32_t ch, DataType type);
public:
    RawImage();
    RawImage(uint32_t w, uint32_t h, uint32_t ch, DataType type);
    RawImage(const RawImage &d);
    RawImage(RawImage &&d);
#ifndef NO_QT
    RawImage(const QImage &img);
#endif
    const RawImage::Stats& imageStats() const;
    void calcStats();
    uint32_t width() const;
    uint32_t height() const;
    uint32_t channels() const;
    uint64_t size() const;
    DataType type() const;
    uint32_t norm() const;
    uint64_t widthBytes() const;
    uint32_t widthSamples() const;
    void* data();
    const void* data() const;
    void* data(uint32_t row, uint32_t col = 0);
    const void* data(uint32_t row, uint32_t col = 0) const;
    const void *origData() const;
    const void *origData(uint32_t row, uint32_t col = 0) const;
    bool planar() const;
    void setPlanar();
    void convertToThumbnail();
    void convertToGLFormat();
    void convertToType(RawImage::DataType type);
    float thumbAspect() const;
    bool pixel(int x, int y, double &r, double &g, double &b) const;
    void resize(uint32_t w, uint32_t h);
    void resizeInt(int downsample, bool avg);
    std::pair<float, float> unitScale() const;
    void flip();

    static std::shared_ptr<RawImage> fromPlanar(const RawImage &img);
    static std::shared_ptr<RawImage> fromPlanar(const void *pixels, uint32_t w, uint32_t h, uint32_t ch, DataType type);
    std::shared_ptr<RawImage> toPlanar();
    static size_t typeSize(DataType type);
    std::vector<RawImage> split() const;
    bool valid() const;
#ifndef NO_QT
    void setICCProfile(const QByteArray &icc);
    void setICCProfile(const LibXISF::ByteArray &icc);
    void convertTosRGB();
    void generateLUT();
#endif
    void applySTF(const MTFParam &mtfParams);
    MTFParam calcMTFParams(bool linked = false, bool debayer = false) const;
    const std::vector<uint16_t>& getLUT() const;

};

//Q_DECLARE_SMART_POINTER_METATYPE(std::shared_ptr);
//Q_DECLARE_METATYPE(std::shared_ptr<RawImage>);

#endif // RAWIMAGE_H
