#ifndef GLTEXTURECUBEMAP_HPP_
#define GLTEXTURECUBEMAP_HPP_


#include <string>
#include <utility>

#include <globject.hpp>
#include <gltexturend.hpp>


/// Class

class GLTextureCubemap : public GLTextureND<2>
{
public:

    /// Special member functions

    explicit GLTextureCubemap(
        std::string object_label,
        Size        size,
        GLenum      internal_format = GL_RGB8,
        GLenum      wrap            = GL_CLAMP_TO_EDGE,
        GLenum      min_filter      = GL_LINEAR,
        GLenum      mag_filter      = GL_LINEAR
    );

    /// Core

    GLTextureCubemap static const & empty();

    /// TGA

    GLTextureCubemap static tga_read(
        Paths const & paths,
        GLenum        format          = GL_BGRA,
        GLenum        internal_format = GL_SRGB8_ALPHA8,
        GLenum        wrap            = GL_CLAMP_TO_EDGE,
        GLenum        min_filter      = GL_LINEAR,
        GLenum        mag_filter      = GL_LINEAR
    );

    void tga_write(
        Paths const & paths,
        GLenum        format = GL_BGRA
    ) const;

protected:

    /// Core

    void virtual data_(
        void const * data,
        GLenum       target,
        GLenum       format,
        GLenum       type
    ) override;

    /// Check

    void static check_cubemap_paths_(Paths const & paths);
    void        check_cubemap_size_() const;

private:

    /// Core

    auto static constexpr faces_ = GLuint{6};
};


/// Special member functions

inline GLTextureCubemap::GLTextureCubemap(
    std::string object_label,
    Size        size,
    GLenum      internal_format,
    GLenum      wrap,
    GLenum      min_filter,
    GLenum      mag_filter
)
:
    GLTextureND(
        std::move(object_label),
        GL_TEXTURE_CUBE_MAP,
        GL_TEXTURE_BINDING_CUBE_MAP,
        GL_MAX_CUBE_MAP_TEXTURE_SIZE,
        size,
        internal_format,
        wrap,
        min_filter,
        mag_filter
    )
{
    try
    {
        check_cubemap_size_();
        for (auto face = GLuint{0}; face < faces_; ++face)
        {
            glTexImage2D(
                GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0,
                (GLint)internal_format,
                size[0], size[1], 0,
                GL_RED, GL_UNSIGNED_BYTE, nullptr
            );
            check_error_(glGetError());
        }
        if (supported({3, 2}, "GL_ARB_seamless_cube_map"))
            glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
    }
    catch (...)
    {
        fail_action_("create");
    }
}

/// Core

inline GLTextureCubemap const & GLTextureCubemap::empty()
{
    return empty_<GLTextureCubemap>();
}

inline void GLTextureCubemap::data_(
    void const * data,
    GLenum       target,
    GLenum       format,
    GLenum       type
)
{
    glTexSubImage2D(
        target, 0,
        0, 0,
        size()[0], size()[1],
        format, type, data
    );
}


#endif // GLTEXTURECUBEMAP_HPP_
