//! `Minf` type.

use crate::{durandal::err::*, marathon::text::*};
use bitflags::bitflags;

/// Reads a `Minf` chunk.
pub fn read(b: &[u8]) -> ResultS<Minf>
{
   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 MsnFlags;
         let envi_flags = u16[8] flag EnvFlags;
         let level_name = mac_roman_cstr[18; 66] no_try;
         let entr_flags = u32[84] flag EntFlags;
      }
   }

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

/// Writes a `Minf` chunk.
pub fn write(v: &Minf) -> 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<Minf>
{
   let minf = read(b)?;

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

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

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

impl Default for Minf
{
   fn default() -> Self
   {
      Self{texture_id: 0,
           physics_id: 1,
           skypict_id: 0,
           miss_flags: MsnFlags::empty(),
           envi_flags: EnvFlags::empty(),
           entr_flags: EntFlags::SOLO,
           level_name: "Map".to_string()}
   }
}

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

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

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

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

// EOF
