//! `Side` type.

use super::stex;
use crate::{durandal::{bin::OptU16, err::*, fixed::Fixed},
            marathon::xfer::TransferMode};
use bitflags::bitflags;
use std::convert::TryFrom;

/// Reads a `SIDS` chunk.
pub fn read(b: &[u8]) -> ResultS<(Side, usize)>
{
   read_data! {
      endian: BIG, buf: b, size: 64, start: 0, data {
         let stype    = u16[0] enum SideType;
         let flags    = u16[2] flag SideFlags;
         let tex_pri  = stex::read[4;  6];
         let tex_sec  = stex::read[10; 6];
         let tex_tra  = stex::read[16; 6];
         let paneltyp = u16[38];
         let paneldat = i16[40];
         let xfer_pri = u16[42] enum TransferMode;
         let xfer_sec = u16[44] enum TransferMode;
         let xfer_tra = u16[46] enum TransferMode;
         let shade    = Fixed[48];
      }
   }

   Ok((Side{stype, flags, tex_pri, tex_sec, tex_tra, paneltyp, paneldat,
            xfer_pri, xfer_sec, xfer_tra, shade}, 64))
}

/// Reads an old `SIDS` chunk.
pub fn read_old(b: &[u8]) -> ResultS<(Side, usize)>
{
   let (side, siz) = read(b)?;

   Ok((Side{tex_tra: stex::SideTex{tex_id: OptU16::none(), ..side.tex_tra},
            shade:   0.into(),
            flags:   side.flags | SideFlags::ITEM_OPT,
            ..side}, siz))
}

/// One side of a line segment.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Debug, Eq, PartialEq)]
pub struct Side
{
   pub stype:    SideType,
   pub flags:    SideFlags,
   pub tex_pri:  stex::SideTex,
   pub tex_sec:  stex::SideTex,
   pub tex_tra:  stex::SideTex,
   pub paneltyp: u16,
   pub paneldat: i16,
   pub xfer_pri: TransferMode,
   pub xfer_sec: TransferMode,
   pub xfer_tra: TransferMode,
   pub shade:    Fixed,
}

bitflags! {
   /// Flags for `Side`.
   #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
   pub struct SideFlags: u16
   {
      const STATUS      = 1;
      const PANEL       = 1 << 1;
      const REPAIR      = 1 << 2;
      const ITEM_USE    = 1 << 3;
      const LIGHTED     = 1 << 4;
      const CAN_DESTROY = 1 << 5;
      const HIT_ONLY    = 1 << 6;
      const ITEM_OPT    = 1 << 7;
   }
}

c_enum! {
   /// The texture type of a `Side`.
   #[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
   #[derive(Debug)]
   pub enum SideType: u16
   {
      Full      = 0,
      High      = 1,
      Low       = 2,
      Composite = 3,
      Split     = 4,
   }
}

// EOF
