#pragma once

#include "image.hpp"
#include <cmath>
#include <cstdint>
#include <glm/matrix.hpp>
#include <vector>

namespace Graphics::Texture {
	struct Atlas {
		static constexpr int N = 4;
		struct Pixel {
			uint8_t m_data[N] = {0};
	
			Pixel() = default;
			Pixel(const Pixel& p);
			Pixel(const uint8_t* p);
	
			bool operator == (const Pixel& p) const;
			bool operator != (const Pixel& p) const;
			Pixel& operator = (const Pixel& p);
			Pixel& operator = (const uint8_t* p);
			uint8_t& operator [] (int i);
			const uint8_t& operator [] (int i) const;
	
			template <typename T>
			constexpr operator glm::vec<N, T>() {
				glm::vec<N, T> vec;
				for(int i = 0; i < N; i++) {
					vec[i] = (T)m_data[i] / 255.0;
				}
				return vec;
			}
	
			template <typename T>
			constexpr Pixel& operator = (const glm::vec<N, T>& vec) {
				for(int i = 0; i < N; i++) {
					m_data[i] = (uint8_t)(std::round(vec[i] * 255));
				}
				return *this;
			}
	
			template <typename T>
			constexpr Pixel(const glm::vec<N, T>& vec) {
				*this = vec;
			}
		};
	
		glm::vec<3, int> m_size;
		std::vector<Pixel> m_data;
		bool m_padding = false;
	
		Atlas() = default;
		Atlas(glm::vec<2, int> size);
		Atlas(glm::vec<3, int> size);
		Pixel& get(glm::vec<3, int> pos);
		const Pixel& get(glm::vec<3, int> pos) const;
		void draw(const Atlas& src, glm::vec<3, int> pos);
		void draw(const Image& src, glm::vec<3, int> pos);
	};
};