#ifndef NVPIXELFORMATEX_H
#define NVPIXELFORMATEX_H

#include <cstdint>
#include <vector>
#ifdef SDK_SIMPLE_INCLUDE
#include "../YCKitExport.h"
#else
#include "YCKit/YCKitExport.h"
#endif

struct AVPixFmtDescriptor;

class DLL_DECL NVPixelFormatEx{
public:
    enum PixelFormat {
        Format_Invalid = -1,
        Format_ARGB32, // AARRGGBB or 00RRGGBB, check hasAlpha is required
        Format_BGRA32, //BBGGRRAA
        Format_ABGR32, // QImage.RGBA8888 le
        Format_RGBA32, // QImage. no
        Format_RGB32, // 0xAARRGGBB native endian. same as QImage::Format_ARGB32. be: ARGB32, le: BGRA32
        Format_BGR32, // 0xAABBGGRR native endian
        Format_RGB24,
        Format_BGR24,
        Format_RGB565,
        Format_BGR565,
        Format_RGB555,
        Format_BGR555,

        //http://www.fourcc.org/yuv.php
        Format_AYUV444,
        Format_YUV444P,
        Format_YUV422P,
        Format_YUV420P,
        Format_YUV411P,
        Format_YUV410P,
        Format_YV12,
        Format_UYVY, //422
        Format_VYUY, //not in ffmpeg. OMX_COLOR_FormatCrYCbY
        Format_YUYV, //422, aka yuy2
        Format_YVYU, //422
        Format_NV12,
        Format_NV21,
        Format_IMC1,
        Format_IMC2,
        Format_IMC3, //same as IMC1, swap U V
        Format_IMC4, //same as IMC2, swap U V
        Format_Y8, //GREY. single 8 bit Y plane
        Format_Y16, //single 16 bit Y plane. LE

        Format_Jpeg, //yuvj

        //Format_CameraRaw,
        //Format_AdobeDng,

        Format_YUV420P9LE,
        Format_YUV422P9LE,
        Format_YUV444P9LE,
        Format_YUV420P10LE,
        Format_YUV422P10LE,
        Format_YUV444P10LE,
        Format_YUV420P12LE,
        Format_YUV422P12LE,
        Format_YUV444P12LE,
        Format_YUV420P14LE,
        Format_YUV422P14LE,
        Format_YUV444P14LE,
        Format_YUV420P16LE,
        Format_YUV422P16LE,
        Format_YUV444P16LE,
        Format_YUV420P9BE,
        Format_YUV422P9BE,
        Format_YUV444P9BE,
        Format_YUV420P10BE,
        Format_YUV422P10BE,
        Format_YUV444P10BE,
        Format_YUV420P12BE,
        Format_YUV422P12BE,
        Format_YUV444P12BE,
        Format_YUV420P14BE,
        Format_YUV422P14BE,
        Format_YUV444P14BE,
        Format_YUV420P16BE,
        Format_YUV422P16BE,
        Format_YUV444P16BE,

        Format_RGB48, // native endian
        Format_RGB48LE,
        Format_RGB48BE,
        Format_BGR48,
        Format_BGR48LE,
        Format_BGR48BE,
        Format_RGBA64, //native endian
        Format_RGBA64LE,
        Format_RGBA64BE,
        Format_BGRA64, //native endian
        Format_BGRA64LE,
        Format_BGRA64BE,

        Format_VYU, // for rgb422_apple texture, the layout is like rgb24: (v, y, u, )
        Format_XYZ12,
        Format_XYZ12LE,
        Format_XYZ12BE,
        Format_User
    };


    static PixelFormat pixelFormatFromFFmpeg(int ff); //AVPixelFormat
    static int pixelFormatToFFmpeg(PixelFormat fmt);
    static std::vector<int> pixelFormatsFFmpeg();

    NVPixelFormatEx(PixelFormat format = Format_Invalid);
    NVPixelFormatEx(int formatFF);
    NVPixelFormatEx(const NVPixelFormatEx &other);


    ~NVPixelFormatEx();

    NVPixelFormatEx& operator=(const NVPixelFormatEx& fmt);
    NVPixelFormatEx& operator=(NVPixelFormatEx::PixelFormat pixfmt);
    NVPixelFormatEx& operator=(int ffpixfmt);
    bool operator==(const NVPixelFormatEx &other) const;
    bool operator==(NVPixelFormatEx::PixelFormat pixfmt) const;
    bool operator==(int ffpixfmt) const;
    bool operator!=(const NVPixelFormatEx &other) const {return !(operator==(other));}
    bool operator!=(NVPixelFormatEx::PixelFormat pixfmt) const {return !(operator==(pixfmt));}
    bool operator!=(int ffpixfmt) const {return !(operator==(ffpixfmt));}

    bool isValid() const {return pf!=Format_Invalid;}
    PixelFormat pixelFormat() const {return pf;}
    int pixelFormatFFmpeg() const {return pf_ff;}

    int bytesPerLine(int width, int plane) const;

    int chromaWidth(int lumaWidth) const;

    int chromaHeight(int lumaHeight) const;

    int width(int lumaWidth, int plane) const
    {
        if (plane <= 0)
            return lumaWidth;
        return chromaWidth(lumaWidth);
    }

    int height(int lumaHeight, int plane) const
    {
        if (plane <= 0)
            return lumaHeight;
        return chromaHeight(lumaHeight);
    }

    int flags() const;

    int channels() const;

    int planeCount() const {return planes;}

	bool isRGB() const;

protected:
    PixelFormat pf;
    int pf_ff;
    int planes = 0;
    AVPixFmtDescriptor* pixdesc;

protected:
    void init(NVPixelFormatEx::PixelFormat fmt);
    void init(int ffFormat);
    void init();
};
#endif // NVPIXELFORMATEX_H
