//! Shapes file color lookup tables.

use crate::durandal::{err::*, image::Color};

/// Reads a color from a color table into `clut`.
pub fn read_color(b: &[u8], clut: &mut [ColorShp]) -> ResultS<()>
{
   read_data! {
      endian: BIG, buf: b, size: 8, start: 0, data {
         let flag = u8[0];
         let ind  = u8[1];
         let r    = u16[2];
         let g    = u16[4];
         let b    = u16[6];
      }
   }

   let cr = ok!(clut.get_mut(usize::from(ind)), "bad index")?;

   *cr = match flag {
      128 => ColorShp::Lit   {r, g, b},
      0   => ColorShp::Opaque{r, g, b},
      _   => {
         return Err(err_msg("invalid flag in color"));
      }
   };

   Ok(())
}

/// Reads color tables from `b`.
pub fn read(b: &[u8], tab_ofs: usize, tab_num: usize, clr_num: usize)
   -> ResultS<Vec<Clut>>
{
   let end = tab_num * clr_num * 8;

   let b = ok!(b.get(tab_ofs..tab_ofs + end), "bad offset")?;

   let mut v = vec![vec![ColorShp::Translucent; clr_num]; tab_num];
   let mut p = 0;

   for clut in v.iter_mut().take(tab_num) {
      for _ in 0..clr_num {
         read_color(ok!(b.get(p..p + 8), "not enough data")?, clut)?;
         p += 8;
      }
   }

   Ok(v)
}

impl Color for ColorShp
{
   fn r(&self) -> u16
   {
      match *self {
         ColorShp::Translucent => 0,
         ColorShp::Opaque{r, ..} |
         ColorShp::Lit   {r, ..} => r,
      }
   }

   fn g(&self) -> u16
   {
      match *self {
         ColorShp::Translucent => 0,
         ColorShp::Opaque{g, ..} |
         ColorShp::Lit   {g, ..} => g,
      }
   }

   fn b(&self) -> u16
   {
      match *self {
         ColorShp::Translucent => 0,
         ColorShp::Opaque{b, ..} |
         ColorShp::Lit   {b, ..} => b,
      }
   }

   fn a(&self) -> u16
   {
      match *self {
         ColorShp::Translucent => 0,
         ColorShp::Opaque{..} |
         ColorShp::Lit   {..} => u16::max_value(),
      }
   }
}

/// A color in a `Clut`.
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ColorShp
{
   /// A completely translucent color.
   Translucent,

   /// An opaque color which may be shaded.
   Opaque{/** The red component.   */ r: u16,
          /** The green component. */ g: u16,
          /** The blue component.  */ b: u16},

   /// An opaque color which may not be shaded.
   Lit{/** The red component.   */ r: u16,
       /** The green component. */ g: u16,
       /** The blue component.  */ b: u16},
}

/// A color collection.
pub type Clut = Vec<ColorShp>;

// EOF
