//! Marathon Map format handling.

pub mod ambi;
pub mod attk;
pub mod bonk;
pub mod chnk;
pub mod damg;
pub mod entr;
pub mod epnt;
pub mod fxpx;
pub mod iidx;
pub mod lins;
pub mod lite;
pub mod ltfn;
pub mod medi;
pub mod minf;
pub mod mnpx;
pub mod note;
pub mod objs;
pub mod plac;
pub mod plat;
pub mod pnts;
pub mod poly;
pub mod prpx;
pub mod pxpx;
pub mod sids;
pub mod stex;
pub mod term;
pub mod trig;
pub mod trmf;
pub mod trmg;
pub mod wppx;

use crate::{durandal::err::*, marathon::text::mac_roman_cstr};
use std::convert::TryFrom;

/// Reads a Map file.
pub fn read(b: &[u8]) -> ResultS<Wad>
{
   read_data! {
      endian: BIG, buf: b, size: 128, start: 0, data {
         let ver_wad  = u16[0] enum Ver;
         let ver_dat  = u16[2];
         let name     = mac_roman_cstr[4; 64] no_try;
         let siz_app  = u16[78] usize;
         let siz_wcnk = u16[80] usize;
         let siz_went = u16[82] usize;
      }
   }

   let old_dat = ver_dat == 0;
   let old_wad = match ver_wad {
      Ver::Base => true,
      _         => false,
   };

   let siz_ent = if old_wad {8 } else {10};
   let siz_cnk = if old_wad {12} else {16};

   if !old_wad && siz_ent != siz_went {
      bail!("invalid entry size");
   }

   if !old_wad && siz_cnk != siz_wcnk {
      bail!("invalid chunk size");
   }

   let entries = entr::read(b, old_wad, old_dat, siz_app, siz_ent, siz_cnk)?;

   Ok(Wad{name, siz_app, entries})
}

/// A Map file containing entries.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
pub struct Wad
{
   /// The original name of this file.
   pub name: String,

   /// The size of each `Entry`'s `appdata` field.
   pub siz_app: usize,

   /// All of the entries in this `Wad`.
   pub entries: entr::EntryMap,
}

c_enum! {
   /// The version of a `Wad`.
   #[derive(Debug)]
   enum Ver: u16
   {
      Base = 0,
      Dir  = 1,
      Over = 2,
      Inf  = 4,
   }
}

/// The number of game ticks per second.
pub const TICKS_PER_SECOND: u16 = 30;

// EOF
