#pragma once

#include <psemek/util/ndarray.hpp>
#include <psemek/gfx/color.hpp>
#include <psemek/io/stream.hpp>

#include <memory>

namespace psemek::gfx
{

	template <typename Pixel>
	using basic_pixmap = util::ndarray<Pixel, 2>;

	using pixmap_monochrome = basic_pixmap<std::uint8_t>;
	using pixmap_rgb = basic_pixmap<color_rgb>;
	using pixmap_rgba = basic_pixmap<color_rgba>;
	using pixmap_float = basic_pixmap<float>;

	// Image reading

	template <typename Pixel>
	basic_pixmap<Pixel> read_image(io::istream && is);

	extern template pixmap_monochrome read_image<std::uint8_t>(io::istream && is);
	extern template pixmap_rgb read_image<color_rgb>(io::istream && is);
	extern template pixmap_rgba read_image<color_rgba>(io::istream && is);

	// Image writing

	void write_image_png(pixmap_monochrome const & p, io::ostream && os);
	void write_image_png(pixmap_rgb const & p, io::ostream && os);
	void write_image_png(pixmap_rgba const & p, io::ostream && os);

	void write_image_tga(pixmap_monochrome const & p, io::ostream && os);
	void write_image_tga(pixmap_rgb const & p, io::ostream && os);
	void write_image_tga(pixmap_rgba const & p, io::ostream && os);

	void write_image_bmp(pixmap_rgb const & p, io::ostream && os);

	void write_image_jpg(pixmap_rgb const & p, io::ostream && os, int quality = 100);

	void write_image_hdr(basic_pixmap<color_3f> const & p, io::ostream && os);

	void write_image_pgm(pixmap_monochrome const & p, io::ostream && os);
	void write_image_ppm(pixmap_rgb const & p, io::ostream && os);

	// Utilities

	template <typename Pixel, std::size_t N>
	auto to_srgb(util::ndarray<Pixel, N> pm, float g = 1.f / 2.2f)
	{
		for (auto & c : pm)
			c = to_srgb(c, g);
		return pm;
	}

	template <typename Pixel, std::size_t N>
	auto to_linear(util::ndarray<Pixel, N> pm, float g = 1.f / 2.2f)
	{
		return to_srgb(std::move(pm), 1.f / g);
	}

}
