#ifndef CMESH_HPP
#define CMESH_HPP

#include "../Material/SMaterial.hpp"
#include "../Texture/CAbstractTexture.hpp"
#include "SVertex.hpp"
#include "../../../Controller/Exception/CLogicException.hpp"

#ifdef WIN32
#include <gl/glew.h>
#else
#include <GL/glew.h>
#endif

#include <vector>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>

/**
 * @file CMesh.hpp
 * @brief File for the mesh struct.
 */

/**
 * @brief Class CMesh, used to represent a mesh, a set of vertex (which can be indexed), ready to be drawn.
 */
class CMesh {
private:
    /**
     * @brief List of the vertices of the mesh.
     */
    std::vector<SVertex> m_vertexes;

    /**
     * @brief List of the indices of the mesh.
     */
    std::vector<unsigned int> m_indexes;

    /**
     * @brief A pointer to the material containing textures, colors and the shader used for the mesh.
     */
    SMaterial* m_material;

    /**
     * @brief The vertex buffer.
     */
    unsigned int m_vertexBufferObject;

    /**
     * @brief The index buffer.
     */
    unsigned int m_elementBufferObject;

    /**
     * @brief Vertex array object, all the data.
     */
    unsigned int m_vertexArrayObject;

    /**
     * @brief Apply material to use for drawing.
     * @param[in] model the model matrix.
     * @param[in] view the view matrix.
     * @param[in] projection the projection matrix.
     * @param[in] lightPos the position of the light source.
     * @param[in] intensity the intensity of the light source.
     */
    void bindMaterial(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 lightPos, float intensity);

public:
    /**
     * @brief the constructor.
     */
    CMesh(void);

    /**
     * @brief the destructor.
     */
    ~CMesh(void);

    /**
     * @brief The vertex array getter.
     * @return std::vector<SVertex>&, A reference to the list of vertex.
     */
    std::vector<SVertex>& getVertexes(void);

    /**
     * @brief The index array getter.
     * @return std::vector<unsigned int>&, A reference to the list of index.
     */
    std::vector<unsigned int>& getIndexes(void);

    /**
     * @brief The material getter.
     * @return SMaterial*, the material.
     */
    SMaterial* getMaterial(void);

    /**
     * @brief The material setter.
     * @param[in] material the wanted material.
     */
    void setMaterial(SMaterial* material);

    /**
     * @brief The vertex setter.
     * @param[in] vertices list of the vertices to give to the GPU.
     */
    void setVertices(std::vector<SVertex> vertices);

    /**
     * @brief The indexes setter.
     * @param[in] indexes list of the indexes for the index buffer
     */
    void setIndexes(std::vector<unsigned int> indexes);

    /**
     * @brief Load the mesh in GPU.
     */
    void load(void);

    /**
     * @brief draw the mesh.
     * @param[in] model the model matrix.
     * @param[in] view the view matrix.
     * @param[in] projection the projection matrix.
     * @param[in] lightPos the position of the light source.
     * @param[in] intensity the intensity of the light source.
     */
    void draw(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 lightPos, float intensity);
};

#endif