#pragma once
/*********************************************************************************
**
**      @copyright (c) 2025, Cortx Technologies, Montreal, QC.
**      All Rights Reserved.
**
**      PROPRIETARY SOFTWARE.
**      This software is proprietary and confidential to Cortx Technologies.
**      Unauthorized use, reproduction, or distribution in whole or in part
**      is scrictly prohibited.
**
**********************************************************************************
**
**  @file       shaderUtil.h
**  @brief      Header file for the shader functions.
**  @author     arturodlrios
**  @date       Created on 2024/02/27
**
**  @details    Handles shader compilation, linking, and uniform variable
**              management for OpenGL applications with comprehensive
**              error reporting.
**
**********************************************************************************/

/**********************************  Includes  ***********************************/
#include "../../pch/pch.h"

/*********************************  Namespaces  **********************************/
namespace nshaders
{
    /*!
     * @brief     Utility class to load, compile and attach vertex and fragment shaders to a program
     * @details   Provides comprehensive shader management including file loading, compilation,
     *            linking, validation, and uniform variable management for OpenGL applications.
     *            Includes robust error checking and reporting mechanisms.
     */
    class Shader
    {
    public:
        /*!
         * @brief     Default constructor
         * @details   Initializes shader object with default values
         */
        Shader(void) : glProgramId_m(0) {}

        /*!
         * @brief     Loads and compiles vertex and fragment shaders from files
         * @param[in] vertexShaderFile: Path to vertex shader source file
         * @param[in] fragmentShaderFile: Path to fragment shader source file
         * @return    Success on successful compilation and linking, Error on failure
         * @details   This function loads shader source code from files, compiles them,
         *            links them into a shader program, and validates the result.
         *            The function performs comprehensive error checking and logging.
         * @note      Requires valid OpenGL context to be active
         * @warning   Shader files must exist and be readable
         */
        CortxCode_t load(const std::string &vertexShaderFile,
                                    const std::string &fragmentShaderFile);

        /*!
         * @brief     Activates the shader program for rendering
         * @details   Makes this shader program the active program for subsequent
         *            rendering operations. All draw calls will use this shader.
         * @note      Must be called before rendering with this shader
         * @warning   Requires valid OpenGL context and compiled shader program
         */
        void use(void);

        /*!
         * @brief     Deletes the shader program and frees OpenGL resources
         * @details   Properly cleans up the shader program object and releases
         *            associated OpenGL resources. Should be called when shader
         *            is no longer needed.
         * @note      Safe to call multiple times
         * @warning   Shader becomes invalid after this call
         */
        void unload(void);

        /*!
         * @brief     Gets the OpenGL program ID
         * @return    OpenGL program ID for this shader
         * @details   Returns the internal OpenGL program ID for advanced operations
         * @note      Use with caution - direct OpenGL manipulation
         */
        uint32_t getProgramId() { return glProgramId_m; }

        /*!
         * @brief     Sets a float array uniform variable in the shader
         * @param[in] name: Name of the uniform variable in the shader
         * @param[in] count: Number of float values in the array
         * @param[in] value: Pointer to the float array data
         * @details   Sets a uniform variable of type float array in the currently
         *            active shader program. Used for passing array data to shaders.
         * @note      Shader program must be active (use() called)
         * @warning   Uniform name must exist in shader source code
         */
        void setFloatArray(std::string const &name, uint32_t const &count, float const *value);

        /*!
         * @brief     Sets a 4x4 matrix uniform variable in the shader
         * @param[in] mat4: The 4x4 matrix data (glm::mat4)
         * @param[in] name: Name of the uniform variable in the shader
         * @details   Sets a uniform variable of type mat4 in the currently active
         *            shader program. Commonly used for transformation matrices.
         * @note      Shader program must be active (use() called)
         * @warning   Matrix is passed as column-major (GL_FALSE transpose parameter)
         */
        void setMat4(const glm::mat4 &mat4, const std::string &name);

        /*!
         * @brief     Sets a 3D vector uniform variable in the shader
         * @param[in] vec3: The 3D vector data (glm::vec3)
         * @param[in] name: Name of the uniform variable in the shader
         * @details   Sets a uniform variable of type vec3 in the currently active
         *            shader program. Used for colors, positions, normals, etc.
         * @note      Shader program must be active (use() called)
         * @warning   Uses glProgramUniform for program-specific uniform setting
         */
        void setVec3(const glm::vec3 &vec3, const std::string &name);

        /*!
         * @brief     Sets a boolean uniform variable in the shader
         * @param[in] value: Boolean value to set
         * @param[in] name: Name of the uniform variable in the shader
         * @details   Sets a uniform variable of type bool in the currently active
         *            shader program. Boolean is converted to integer (0 or 1).
         * @note      Shader program must be active (use() called)
         * @warning   Boolean is passed as integer to OpenGL
         */
        void setBool(bool value, const std::string &name);

        /*!
         * @brief     Sets an integer uniform variable in the shader
         * @param[in] value: Integer value to set
         * @param[in] name: Name of the uniform variable in the shader
         * @details   Sets a uniform variable of type int in the currently active
         *            shader program. Used for counters, indices, flags, etc.
         * @note      Shader program must be active (use() called)
         * @warning   Uniform name must exist in shader source code
         */
        void setInt(int value, const std::string &name);

    private:
        /*!
         * @brief     Compiles shader source code into OpenGL shader object
         * @param[in] shaderType: Type of shader (GL_VERTEX_SHADER, GL_FRAGMENT_SHADER, etc.)
         * @param[in] shaderSource: Source code string of the shader
         * @return    OpenGL shader ID on success, 0 on failure
         * @details   This function compiles shader source code and performs comprehensive
         *            error checking. It reports compilation errors and OpenGL state errors.
         * @note      Requires valid OpenGL context to be active
         * @warning   Memory allocated for error log must be freed by caller
         */
        uint32_t compileShader(uint32_t shaderType,
                               const std::string &shaderSource);

        /*!
         * @brief     Validates that the shader program is loaded and ready for use
         * @param[in] functionName: Name of the calling function for error reporting
         * @return    true if program is valid, false otherwise
         * @details   Checks if glProgramId_m is not 0, indicating a loaded program
         */
        bool validateProgramLoaded(const std::string &functionName);

        /*!
         * @brief     Validates that a uniform location is valid
         * @param[in] location: OpenGL uniform location to validate
         * @param[in] uniformName: Name of the uniform for error reporting
         * @return    true if location is valid, false otherwise
         * @details   Checks if location is not -1, indicating a valid uniform
         */
        bool validateUniformLocation(GLint location, const std::string &uniformName);

        uint32_t glProgramId_m;
    };
} /* namespace nshaders */
/******************************  End of File  ************************************/
