//! Wad file chunk type.

use crate::{durandal::{bin::*, err::*, image}, marathon::{map, pict}};

/// Reads all chunks in an entry.
pub fn read(b: &[u8], old: bool, siz_cnk: usize) -> ResultS<Vec<Chunk>>
{
   let mut chunks = Vec::new();
   let mut p = 0;

   let read_chunk_minf = if old {map::minf::read_old} else {map::minf::read};
   let read_chunk_sids = if old {map::sids::read_old} else {map::sids::read};
   let read_chunk_poly = if old {map::poly::read_old} else {map::poly::read};
   let read_chunk_lite = if old {map::lite::read_old} else {map::lite::read};

   while p < b.len() {
      read_data! {
         endian: BIG, buf: b, size: siz_cnk, start: p, data {
            let iden = Ident[0];
            let size = u32[8] usize;
         }
      }

      let beg  = p + siz_cnk;
      let end  = beg + size;
      let data = ok!(b.get(beg..end), "not enough data")?;

      chunks.push(match &iden.0 {
         b"PICT" => Chunk::Pict(pict::load_pict(data)?),
         b"Minf" => Chunk::Minf(read_chunk_minf(data)?),
         b"iidx" => Chunk::Iidx(rd_array(data, map::iidx::read)?),
         b"EPNT" => Chunk::Epnt(rd_array(data, map::epnt::read)?),
         b"PNTS" => Chunk::Pnts(rd_array(data, map::pnts::read)?),
         b"LINS" => Chunk::Lins(rd_array(data, map::lins::read)?),
         b"SIDS" => Chunk::Sids(rd_array(data, read_chunk_sids)?),
         b"POLY" => Chunk::Poly(rd_array(data, read_chunk_poly)?),
         b"OBJS" => Chunk::Objs(rd_array(data, map::objs::read)?),
         b"LITE" => Chunk::Lite(rd_array(data, read_chunk_lite)?),
         b"plac" => Chunk::Plac(rd_array(data, map::plac::read)?),
         b"ambi" => Chunk::Ambi(rd_array(data, map::ambi::read)?),
         b"bonk" => Chunk::Bonk(rd_array(data, map::bonk::read)?),
         b"medi" => Chunk::Medi(rd_array(data, map::medi::read)?),
         b"plat" => Chunk::Plat(rd_array(data, map::plat::read)?),
         b"NOTE" => Chunk::Note(rd_array(data, map::note::read)?),
         b"term" => Chunk::Term(rd_array(data, map::term::read)?),
         b"FXpx" => Chunk::Fxpx(rd_array(data, map::fxpx::read)?),
         b"MNpx" => Chunk::Mnpx(rd_array(data, map::mnpx::read)?),
         b"PRpx" => Chunk::Prpx(rd_array(data, map::prpx::read)?),
         b"PXpx" => Chunk::Pxpx(rd_array(data, map::pxpx::read)?),
         b"WPpx" => Chunk::Wppx(rd_array(data, map::wppx::read)?),
         _       => Chunk::Data{iden, data: data.to_vec()},
      });

      p = end;
   }

   Ok(chunks)
}

/// Any kind of chunk in an `Entry`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
pub enum Chunk
{
   /** A `PICT` chunk.  */ Pict(image::Image8),
   /** A `Minf` chunk.  */ Minf(map::minf::Minf),
   /** An `iidx` chunk. */ Iidx(Vec<u16>),
   /** An `EPNT` chunk. */ Epnt(Vec<map::epnt::Endpoint>),
   /** A `PNTS` chunk.  */ Pnts(Vec<map::pnts::Point>),
   /** A `LINS` chunk.  */ Lins(Vec<map::lins::Line>),
   /** A `SIDS` chunk.  */ Sids(Vec<map::sids::Side>),
   /** A `POLY` chunk.  */ Poly(Vec<map::poly::Polygon>),
   /** A `LITE` chunk.  */ Lite(Vec<map::lite::Light>),
   /** An `OBJS` chunk. */ Objs(Vec<map::objs::Object>),
   /** A `plac` chunk.  */ Plac(Vec<map::plac::ObjectFreq>),
   /** An `ambi` chunk. */ Ambi(Vec<map::ambi::SoundAmbi>),
   /** A `bonk` chunk.  */ Bonk(Vec<map::bonk::SoundRand>),
   /** A `medi` chunk.  */ Medi(Vec<map::medi::Media>),
   /** A `plat` chunk.  */ Plat(Vec<map::plat::Platform>),
   /** A `NOTE` chunk.  */ Note(Vec<map::note::Note>),
   /** A `term` chunk.  */ Term(Vec<map::term::Terminal>),
   /** A `FXpx` chunk.  */ Fxpx(Vec<map::fxpx::Effect>),
   /** A `MNpx` chunk.  */ Mnpx(Vec<map::mnpx::Monster>),
   /** A `PRpx` chunk.  */ Prpx(Vec<map::prpx::Projectile>),
   /** A `PXpx` chunk.  */ Pxpx(Vec<map::pxpx::Physics>),
   /** A `WPpx` chunk.  */ Wppx(Vec<map::wppx::Weapon>),

   /// Any other type of chunk, which may have arbitrary data in it.
   Data{/** The name of the chunk. */ iden: Ident,
        /** The data.              */ data: Vec<u8>},
}

// EOF
