// Copyright 2026 Gabriel Bjørnager Jensen.
//
// This file is part of LOOKLOOK.
//
// LOOKLOOK is free software: you can redistribute
// it and/or modify it under the terms of the GNU
// Affero General Public License as published by
// the Free Software Foundation, either version 3
// of the License, or (at your option) any later
// version.
//
// LOOKLOOK is distributed in the hope that it will
// be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Af-
// fero General Public License along with LOOKLOOK.
// If not, see <https://www.gnu.org/licenses/>.

//! The [`Render::encode`] method.

use crate::mode::{Mode, PixelLayout};
use crate::render::Render;

impl Render {
	/// Encodes the render.
	///
	/// The encoded data can be retrieved using [`data`]
	/// and [`data_mut`].
	///
	/// [`data`]: Self::data
	/// [`data_mut`]: Self::data_mut
	///
	/// # Errors
	///
	/// This method will forward any encoding errors.
	pub fn encode(&mut self, mode: &Mode) {
		if mode.is_raw() {
			// Already encoded.

			self.encoded = None;
			return;
		}

		let mut encoded: Vec<_> = self.encoded.take()
			.map_or_default(|encoded| {
				let mut v: Vec<_> = encoded.into();
				v.clear();

				v
			});

		match *mode {
			Mode::Raw(..) => {
				// Handled above.
				unreachable!();
			}

			Mode::Video(ref video) => {
				match (video.pixel_layout, video.colour_depth.as_u8()) {
					(PixelLayout::Grey, 1) => {
						for slot in &self.raw {
							const SHIFT: u32 = u32::BITS - u8::BITS;

							let grey = (slot >> SHIFT) as u8;

							encoded.push(grey);
						}
					}

					(PixelLayout::Grey, 2) => {
						for slot in &self.raw {
							const SHIFT: u32 = u32::BITS - u16::BITS;

							let grey = (slot >> SHIFT) as u16;

							encoded.extend(&grey.to_le_bytes());
						}
					}

					(PixelLayout::Rgb, 1) => {
						for [red_value, green_value, blue_value] in self.raw().iter().copied().array_chunks::<3>() {
							const SHIFT: u32 = u32::BITS - u8::BITS;

							let red   = (red_value >> SHIFT) as u8;
							let green = (green_value >> SHIFT) as u8;
							let blue  = (blue_value >> SHIFT) as u8;

							encoded.push(red);
							encoded.push(green);
							encoded.push(blue);
						}
					}

					(PixelLayout::Rgb, 2) => {
						for [red_value, green_value, blue_value] in self.raw().iter().copied().array_chunks::<3>() {
							const SHIFT: u32 = u32::BITS - u16::BITS;

							let red   = (red_value >> SHIFT) as u16;
							let green = (green_value >> SHIFT) as u16;
							let blue  = (blue_value >> SHIFT) as u16;

							encoded.extend(red.to_be_bytes());
							encoded.extend(green.to_be_bytes());
							encoded.extend(blue.to_be_bytes());
						}
					}

					(layout, depth) => {
						unimplemented!("{depth} {layout} is not currently supported");
					}
				}
			}

			_ => {
				unimplemented!("`{}` mode is currently unsupported", mode.as_str());
			}
		}

		self.encoded = Some(encoded.into());
	}
}
