//! Sounds format definition type.

use crate::{bin::{u32b, usize_from_u32}, err::*, fixed::*, sound::Sound16};

/// Reads a sound definition.
pub fn read(b: &[u8]) -> ResultS<Option<(Vec<usize>, u16, SoundDef)>>
{
	read_data! {
		endian: BIG, buf: b, size: 64, start: 0, data {
			let index    = u16[0];
			let volume   = u16[2] enum Volume;
			let flags    = u16[4] flag SoundFlags;
			let chance   = u16[6];
			let pitch_lo = Fixed[8];
			let pitch_hi = Fixed[12];
			let n_sounds = u16[16] usize;
			let grp_ofs  = u32[20] usize;
		}
	}

	if index == u16::max_value() {
		return Ok(None);
	}

	if n_sounds > 5 {
		bail!("too many sounds");
	}

	let mut ofs = Vec::with_capacity(n_sounds);
	let mut p   = 36;

	for _ in 0..n_sounds {
		ofs.push(grp_ofs + usize_from_u32(u32b(&b[p..])));
		p += 4;
	}

	let sounds = Vec::with_capacity(n_sounds);

	Ok(Some((ofs, index,
	         SoundDef{volume, flags, chance, pitch_lo, pitch_hi, sounds})))
}

/// A sound definition containing one, many or no sounds.
#[derive(Debug, Eq, PartialEq)]
pub struct SoundDef {
	/// The volume type for this sound.
	pub volume: Volume,

	/// The flags for this sound.
	pub flags: SoundFlags,

	/// The chance out of `u16::max_value()` that this sound will not play.
	pub chance: u16,

	/// The low random pitch bound.
	pub pitch_lo: Fixed,

	/// The high random pitch bound.
	pub pitch_hi: Fixed,

	/// All of the sounds in this collection.
	pub sounds: Vec<Sound16>,
}

c_bitfield! {
	/// Flags for `SoundDef`.
	#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
	pub struct SoundFlags: u16 {
		/// The sound will not restart when trying to play over itself.
		NO_RESTART        = 0,
		/// The sound will not switch channels when trying to play over itself.
		NO_CHANNEL_SWITCH = 1,
		/// The pitch variance will be halved.
		LESS_PITCH_CHANGE = 2,
		/// The pitch variance will be nullified.
		NO_PITCH_CHANGE   = 3,
		/// The sound will play even when completely obstructed by walls.
		NO_OBSTRUCTION    = 4,
		/// The sound will play even when completely obstructed by media.
		NO_MEDIA_OBSTRUCT = 5,
		/// The sound will have special stereo effects.
		AMBIENT           = 6,
	}
}

c_enum! {
	/// The type of volume this sound has.
	#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
	pub enum Volume: u16 {
		Quiet  = 0,
		Normal = 1,
		Loud   = 2,
	}
}

// EOF
