#pragma once

#include <psemek/gfx/gl.hpp>
#include <psemek/gfx/pixel.hpp>
#include <psemek/math/vector.hpp>

#include <cstddef>
#include <optional>

namespace psemek::gfx
{

	struct renderbuffer
	{
		renderbuffer();
		renderbuffer(renderbuffer &&);
		renderbuffer & operator = (renderbuffer &&);
		~renderbuffer();

		renderbuffer(renderbuffer const &) = delete;
		renderbuffer & operator = (renderbuffer const &) = delete;

		static constexpr GLenum target = gl::RENDERBUFFER;

		static renderbuffer null();

		GLuint id() const { return id_; }

		explicit operator bool() const { return id() != 0; }

		void bind() const;

		void reset();

		math::vector<std::size_t, 2> size() const { return size_; }

		std::size_t width() const { return size_[0]; }
		std::size_t height() const { return size_[1]; }

		std::optional<int> samples() const { return samples_; }

		void storage(GLenum internal_format, math::vector<std::size_t, 2> const & size);
		void storage(GLenum internal_format, math::vector<std::size_t, 2> const & size, int samples);

		template <typename Pixel>
		void storage(math::vector<std::size_t, 2> const & size)
		{
			storage(pixel_traits<Pixel>::internal_format, size);
		}

		template <typename Pixel>
		void storage(math::vector<std::size_t, 2> const & size, int samples)
		{
			storage(pixel_traits<Pixel>::internal_format, size, samples);
		}

	private:
		GLuint id_ = 0;
		math::vector<std::size_t, 2> size_ = {0, 0};
		std::optional<int> samples_ = std::nullopt;

		explicit renderbuffer(std::nullptr_t);
	};

}
