//! `Info` type.

use crate::{err::*, text::*};

/// Reads a `Minf` chunk.
pub fn read(b: &[u8]) -> ResultS<Info>
{
	read_data! {
		endian: BIG, buf: b, size: 88, start: 0, data {
			let texture_id = u16[0];
			let physics_id = u16[2];
			let skypict_id = u16[4];
			let miss_flags = u16[6] flag MissionFlags;
			let envi_flags = u16[8] flag EnvironmentFlags;
			let level_name = mac_roman_cstr[18; 66] no_try;
			let entr_flags = u32[84] flag EntryFlags;
		}
	}

	Ok(Info{texture_id, physics_id, skypict_id, miss_flags, envi_flags,
	        entr_flags, level_name})
}

/// Writes a `Minf` chunk.
pub fn write(v: &Info) -> Vec<u8>
{
	let mut o = Vec::with_capacity(4);
	o.extend(&v.texture_id.to_be_bytes());
	o.extend(&v.physics_id.to_be_bytes());
	o.extend(&v.skypict_id.to_be_bytes());
	o.extend(&v.miss_flags.bits().to_be_bytes());
	o.extend(&v.envi_flags.bits().to_be_bytes());
	o.extend(&pad_zero(to_mac_roman(&v.level_name), 66));
	o.extend(&v.entr_flags.bits().to_be_bytes());
	o
}

/// Reads an old `Minf` chunk.
pub fn read_old(b: &[u8]) -> ResultS<Info>
{
	let minf = read(b)?;

	let mut entr_flags = if minf.entr_flags.is_empty() {
		EntryFlags::SOLO
	} else {
		minf.entr_flags
	};

	if entr_flags.intersects(EntryFlags::SOLO | EntryFlags::CARNAGE) {
		entr_flags.insert(EntryFlags::CO_OP)
	}

	Ok(Info{entr_flags, ..minf})
}

impl Default for Info
{
	fn default() -> Self
	{
		Self{texture_id: 0,
		physics_id: 1,
		skypict_id: 0,
		miss_flags: MissionFlags::empty(),
		envi_flags: EnvironmentFlags::empty(),
		entr_flags: EntryFlags::SOLO,
		level_name: "Map".to_string()}
	}
}

/// Static map information.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Info {
	pub texture_id: u16,
	pub physics_id: u16,
	pub skypict_id: u16,
	pub miss_flags: MissionFlags,
	pub envi_flags: EnvironmentFlags,
	pub entr_flags: EntryFlags,
	pub level_name: String,
}

c_bitfield! {
	/// Static environment flags.
	#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
	pub struct EnvironmentFlags: u16 {
		VACUUM     = 0,
		MAGNETIC   = 1,
		REBELLION  = 2,
		LOW_GRAV   = 3,
		M1_GLUE    = 4,
		LAVA_FLOOR = 5,
		REBELLION2 = 6,
		MUSIC      = 7,
		TERM_PAUSE = 8,
		M1_MONSTER = 9,
		M1_WEPS    = 10,
	}
}

c_bitfield! {
	/// Static entry point flags.
	#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
	pub struct EntryFlags: u32 {
		SOLO    = 0,
		CO_OP   = 1,
		CARNAGE = 2,
		KTMWTB  = 3,
		KOTH    = 4,
		DEFENSE = 5,
		RUGBY   = 6,
		CTF     = 7,
	}
}

c_bitfield! {
	/// Static mission flags.
	#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
	pub struct MissionFlags: u16 {
		EXTERMINATION  = 0,
		EXPLORATION    = 1,
		RETRIEVAL      = 2,
		REPAIR         = 3,
		RESCUE         = 4,
		M1_EXPLORATION = 5,
		M1_RESCUE      = 6,
		M1_REPAIR      = 7,
	}
}

// EOF
