//! QuickDraw PICT indexed `PixMap`s.

use crate::{bin::check_data, err::*, image::{*, pict::{pm, rle}}};

/// Reads an indexed `PixMap`.
pub fn read(mut im: Image8,
            b: &[u8],
            hdr: pm::head::Header) -> ResultS<Image8>
{
	let clut = ok!(hdr.clut, "no CLUT in indexed mode")?;
	let mut p = 0;

	if hdr.pitch < 8 && hdr.depth == pm::head::Depth::_8 {
		// uncompressed 8-bit colormap indices
		for _ in 0..im.h() {
			for _ in 0..im.w() {
				let idx = usize::from(b[p]);

				im.cr.push(ok!(clut.get(idx), "bad index")?.clone());

				p += 1;
			}
		}

		Ok(im)
	} else if hdr.rle {
		// RLE compressed 1, 2, 4 or 8 bit colormap indices
		for _ in 0..im.h() {
			let (d, pp) = rle::read::<u8>(&b[p..], hdr.pitch)?;

			let d = if hdr.depth < pm::head::Depth::_8 {
				expand_data(d, hdr.depth)?
			} else {
				d
			};

			check_data(&d, im.w())?;

			p += pp;

			for &idx in &d {
				im.cr.push(ok!(clut.get(usize::from(idx)), "bad index")?.clone());
			}
		}

		Ok(im)
	} else {
		bail!("invalid configuration")
	}
}

/// Expand packed pixel data based on bit depth.
pub fn expand_data(b: Vec<u8>, depth: pm::head::Depth) -> ResultS<Vec<u8>>
{
	let mut o = Vec::with_capacity(match depth {
		pm::head::Depth::_4 => b.len() * 2,
		pm::head::Depth::_2 => b.len() * 4,
		pm::head::Depth::_1 => b.len() * 8,
		_ => bail!("invalid bit depth"),
	});

	for ch in b {
		match depth {
			pm::head::Depth::_4 => {
				for i in (0..=1).rev() {
					o.push(ch >> (i * 4) & 0xF_u8);
				}
			}
			pm::head::Depth::_2 => {
				for i in (0..=3).rev() {
					o.push(ch >> (i * 2) & 0x3_u8);
				}
			}
			pm::head::Depth::_1 => {
				for i in (0..=7).rev() {
					o.push(ch >> i & 0x1_u8);
				}
			}
			_ => bail!("invalid bit depth"),
		}
	}

	Ok(o)
}

// EOF
