#ifndef YUV_BUFFER_T_H
#define YUV_BUFFER_T_H
#include <assert.h>
#include <string.h>
#include "HalideRuntime.h"
#include "HalideBuffer.h"
class YuvBufferT {
public:
    enum class ChromaStorage {
        // UVUVUV... Interleaved U and V with element stride 2
        // UVUVUV... and arbitrary row stride.
        // U and V have the same extents and strides.
        kInterleavedUFirst,
        // VUVUVU... Interleaved V and U with element stride 2
        // VUVUVU... and arbitrary row stride.
        // U and V have the same extents and strides.
        kInterleavedVFirst,
        // U and V and stored in separate planes, with U first, followed
        // immediately by V. Element stride = 1, row stride = width.
        // U and V have the same extents and strides.
        kPlanarPackedUFirst,
        // V and U and stored in separate planes, with V first, followed
        // immediately by U. Element stride = 1, row stride = width.
        // U and V have the same extents and strides.
        kPlanarPackedVFirst,
        // U and V are stored in separate planes.
        // Element stride = 1, row stride = arbitrary.
        // U and V have the same extents and strides.
        kPlanarGeneric,
        // Some other arbitrary interleaving of chroma not easily classified.
        kOther
    };
    // Make a null YuvBufferT.
    YuvBufferT() = default;
    YuvBufferT(uint8_t *lumaPointer,
        int32_t lumaWidth, int32_t lumaHeight,
        int32_t lumaElementStrideBytes, int32_t lumaRowStrideBytes,
        uint8_t *chromaUPointer,
        int32_t chromaUWidth, int32_t chromaUHeight,
        int32_t chromaUElementStrideBytes, int32_t chromaURowStrideBytes,
        uint8_t *chromaVPointer,
        int32_t chromaVWidth, int32_t chromaVHeight,
        int32_t chromaVElementStrideBytes, int32_t chromaVRowStrideBytes);
    YuvBufferT(const YuvBufferT ©) = default;
    bool isNull() const;
    Halide::Runtime::Buffer<uint8_t> luma() const;
    Halide::Runtime::Buffer<uint8_t> chromaU() const;
    Halide::Runtime::Buffer<uint8_t> chromaV() const;
    ChromaStorage chromaStorage() const;
    // If chroma channels are interleaved, return an interleaved
    // Halide::Runtime::Buffer<uint8_t> with:
    // - The host pointer pointing to whichever chroma buffer is first in
    //   memory.
    // - Twice the width.
    // Otherwise, returns a Halide::Runtime::Buffer<uint8_t> pointing to nullptr.
    Halide::Runtime::Buffer<uint8_t> interleavedChromaView() const;
    // If chroma channels are planar and tightly packed (one directly
    // follows the other, with the same size and strides), then
    // returns a Halide::Runtime::Buffer<uint8_t> with:
    // - The host pointer pointing to whichever chroma buffer is first in
    //   memory.
    // - Twice the height.
    // Otherwise, returns a Halide::Runtime::Buffer<uint8_t> pointing to nullptr.
    Halide::Runtime::Buffer<uint8_t> packedPlanarChromaView() const;
    // Rotate the buffer 180 degrees. Cheap. Just messes with the strides.
    void rotate180();
    // Copy the contents from another YuvBufferT
    void copy_from(const YuvBufferT &other);
    // Fill the buffer with a fixed YUV value
    void fill(uint8_t y, uint8_t u, uint8_t v);
    // Fill the chroma with a fixed UV value
    void fillUV(uint8_t u, uint8_t v);
private:
    Halide::Runtime::Buffer<uint8_t> luma_;
    Halide::Runtime::Buffer<uint8_t> chromaU_;
    Halide::Runtime::Buffer<uint8_t> chromaV_;
    ChromaStorage chromaStorage_;
    Halide::Runtime::Buffer<uint8_t> interleavedChromaView_;
    Halide::Runtime::Buffer<uint8_t> packedPlanarChromaView_;
};
#endif // YUV_BUFFER_T_H