/******************************************************************************
*	File		-	vertex_buffer.h
*	Author		-	Joey Pollack
*	Date		-	2022/07/13 (y/m/d)
*	Mod Date	-	2022/07/13 (y/m/d)
*	Description	-	OpenGL vertex buffer object
******************************************************************************/

#ifndef LUNARIUM_VERTEX_BUFFER_H_
#define LUNARIUM_VERTEX_BUFFER_H_

#include <core/common_defs.h>
#include <vector>

namespace lunarium
{
    enum VertexAttributeType
    {
        INT32,
        INT64,
        FLOAT32,
        FLOAT64,
    };

    struct VertexAttribute
    {
        VertexAttributeType Type;
        int NumValues;
    };

    class VertexBuffer;
    class BufferLayout
    {
    public:
        void PushVertexAttribute(VertexAttribute va);
        void ClearLayout();
        std::vector<VertexAttribute>& GetLayout();

        int GetNumAttributes() const;
        int GetLayoutSizeInBytes() const;
        int GetAttributeSizeInBytes(VertexAttribute va) const;

    private:
        std::vector<VertexAttribute> mLayout;

    private:
        friend class VertexBuffer;
        void ImplementLayout();
    };

    // For now this class will also contain the VAO for the buffer
    class VertexBuffer
    {
    public:
        enum LayoutType
        {
            LINE,
            TRIANGLE,
        };

    public:


        static VertexBuffer* Create(BufferLayout& VertexLayout, u32 num_vertices, const void* vertices = nullptr, u32 num_indices = 0, u32* indices = nullptr);
        static void Destroy(VertexBuffer** ppBuf);

        void SetType(LayoutType primitive_type);

        void Clear();

        void Bind();
        void Unbind();

        void BindVBO();
        void UnbindVBO();

        bool WillFit(u32 num_vertices);
        bool IdxWillFit(u32 num_indices);

        u32 GetNumVerts() const;

        /// Returns false if the data does not fit in the buffer
        /// size is the size in bytes
        bool PushVertices(const void* vertices, u32 num_verts);
        bool PushIndices(const u32* indices, u32 num_indices);

        void DrawArray(u32 num_elements = 0);


    private:
        BufferLayout mLayout;
        LayoutType mPrimType;
        bool mIsStatic;
        u32 mVAO;
        u32 mVBO;
        u8* mCPUBuffer;
        u32 mSize;      // Size of the buffer in bytes
        u32 mIndex;     // The next spot to push data into for a dynamic buffer
        u32 mNumVertices;

        u32 mEBO;
        u32* mCPUIdxBuffer;
        u32 mEBOSize;
        u32 mEBOIndex;
        u32 mEBOIsStatic;
        u32 mNumIndices;    // Number of indices currently in the buffer

    private:    // HELPER METHODS

        VertexBuffer(BufferLayout& VertexLayout, u32 num_vertices, const void* vertices = nullptr, u32 num_indices = 0, u32* indices = nullptr);
        void Free();
        void Flush();
    };
}

#endif	// LUNARIUM_VERTEX_BUFFER_H_