//! Portable Pixel Map format images.

use crate::{err::*, fixed::FixedLong, image::*};
use std::io;

/// Writes a PPM file from an image.
///
/// # Errors
///
/// Errors if `out` cannot be written to.
pub fn write_ppm(out: &mut impl io::Write, im: &impl Image) -> ResultS<()>
{
	write!(out, "P3\n{} {}\n{}\n", im.w(), im.h(), u16::max_value())?;

	for y in 0..im.h() {
		for x in 0..im.w() {
			let cr = im.index(x, y);
			write!(out, "{} {} {} ", cr.r(), cr.g(), cr.b())?;
		}

		out.write_all(b"\n")?;
	}

	Ok(())
}

/// Reads a PPM file into an image.
pub fn read_ppm(inp: &[u8]) -> ResultS<Image16>
{
	let mut it = inp.split(|&n| n == b'\n' || n == b'\r' || n == b' ');

	if ok!(it.next(), "no magic number")? != b"P3" {
		bail!("not P3 format");
	}

	let mut get_num = move || -> ResultS<u16> {
		let st = loop {
			match ok!(it.next(), "no more strings")? {
				b"" => {}
				st  => break st
			}
		};
		let st = unsafe {std::str::from_utf8_unchecked(st)};
		let nu = u16::from_str_radix(st, 10)?;
		Ok(nu)
	};

	let width  = get_num()?;
	let height = get_num()?;
	let depth  = i64::from(get_num()?);

	let mut im = Image16::new(usize::from(width), usize::from(height));

	for _ in 0..height * width {
		let r = FixedLong::from_int(get_num()?.into());
		let g = FixedLong::from_int(get_num()?.into());
		let b = FixedLong::from_int(get_num()?.into());

		let r = (r / depth * 0xFFFF).integ() as u16;
		let g = (g / depth * 0xFFFF).integ() as u16;
		let b = (b / depth * 0xFFFF).integ() as u16;

		im.cr.push(Color16::new(r, g, b));
	}

	Ok(im)
}

// EOF
