//! Map file entry type.

use crate::err::*;
use super::head;
use std::collections::BTreeMap;

/// Read an entry from a Map file.
pub fn read(map: &head::Map, i: usize) -> ResultS<(u16, Entry<'_>)>
{
	let size = map.head().size_entry();
	let b    = map.dir();
	let sta  = size * i;

	read_data! {
		endian: BIG, buf: b, size: size, start: sta, data {
			let offset   = u32[0] usize;
			let dsize    = u32[4] usize;
		}
	}

	let (index, app_data) = if !map.head().old_wad() {
		read_data! {
			endian: BIG, buf: b, size: size, start: sta, data {
				let index    = u16[8];
				let app_data = u8[10; map.head().size_appl()];
			}
		}
		(index, app_data)
	} else {
		(i as u16, &b[0..0])
	};

	let data  = &map.data()[offset..offset + dsize];

	Ok((index, Entry{data, app_data}))
}

/// Reads all entries in a Map file.
pub fn read_all(map: &head::Map) -> ResultS<EntryMap<'_>>
{
	let mut entries = EntryMap::new();

	for i in 0..map.num_ent() {
		let (index, entry) = read(map, i)?;

		if entries.contains_key(&index) {
			bail!("entry index already exists");
		}

		entries.insert(index, entry);
	}

	Ok(entries)
}

/// An entry containing chunked data and application-specific data.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
pub struct Entry<'a> {
	/// The data in this `Entry`.
	pub data: &'a [u8],

	/// The application specific data for this Entry.
	pub app_data: &'a [u8],
}

/// A map of indexed entries.
pub type EntryMap<'a> = BTreeMap<u16, Entry<'a>>;

// EOF
