// 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`] type.

mod dump;
mod encode;

use crate::mode::Mode;
use crate::synth::Synth;

use oct::IntoOctets;

/// A render.
#[derive(Clone, Debug)]
pub struct Render {
	/// The raw render data.
	raw: Vec<u32>,

	/// The encoded render data.
	encoded: Option<Box<[u8]>>,
}

impl Render {
	/// Creates a new, empty render.
	#[inline]
	#[must_use]
	pub fn new() -> Self {
		Self { raw: Default::default(), encoded: Default::default() }
	}

	/// Configures the render for a specific mode.
	///
	/// The contents of the raw buffer should not be
	/// relied upon until the next render.
	pub fn configure(&mut self, mode: &Mode) {
		self.raw.resize(mode.render_size(), 0);

		self.encoded = None;
	}

	/// Renders the render.
	pub fn render(&mut self, series: &[Synth]) {
		let mut tick = 0;

		for slot in &mut self.raw {
			let mut value = tick;

			for synth in series {
				value = synth.impulse(value);
			}

			*slot = value.to_le();

			tick = tick.wrapping_add(1);
		}
	}

	/// Retrieves the raw render data.
	#[inline]
	#[must_use]
	pub fn raw(&self) -> &[u32] {
		&self.raw
	}

	/// Mutably retrieves the encoded raw data.
	#[inline]
	#[must_use]
	pub fn raw_mut(&mut self) -> &mut [u32] {
		&mut self.raw
	}

	/// Retrieves the encoded render data.
	#[inline]
	#[must_use]
	pub fn encoded(&self) -> &[u8] {
		self.encoded.as_deref()
			.unwrap_or_else(|| self.raw.as_octets())
	}

	/// Mutably retrieves the encoded render data.
	#[inline]
	#[must_use]
	pub fn encoded_mut(&mut self) -> &mut [u8] {
		self.encoded.as_deref_mut()
			.unwrap_or_else(|| self.raw.as_octets_mut())
	}

	/// Retrieves the size of the raw render.
	///
	/// The returned value is in count of 32-bit words.
	#[inline]
	#[must_use]
	pub fn raw_size(&self) -> usize {
		self.raw.len()
	}

	/// Retrieves the size of the encoded render.
	#[inline]
	#[must_use]
	pub fn encoded_size(&self) -> usize {
		self.encoded().len()
	}
}

impl Default for Render {
	#[inline]
	fn default() -> Self {
		Self::new()
	}
}

impl Drop for Render {
	#[inline(always)]
	fn drop(&mut self) {}
}
