///|
/// Source-image palette contracts.
///
/// 2x2 RGBA texel palette intended as a minimal transferable form
/// between asset/image repositories and backend upload layers.

///|
pub struct Rgba {
  r : Int
  g : Int
  b : Int
  a : Int
} derive(Debug)

///|
pub impl Show for Rgba with output(self, logger) {
  logger.write_object(to_repr(self))
}

///|
pub struct ImagePalette2x2 {
  p00 : Rgba
  p10 : Rgba
  p01 : Rgba
  p11 : Rgba
} derive(Debug)

///|
pub impl Show for ImagePalette2x2 with output(self, logger) {
  logger.write_object(to_repr(self))
}

///|
pub fn clamp_channel(channel : Int) -> Int {
  if channel < 0 {
    0
  } else if channel > 255 {
    255
  } else {
    channel
  }
}

///|
pub fn new_rgba(r : Int, g : Int, b : Int, a : Int) -> Rgba {
  {
    r: clamp_channel(r),
    g: clamp_channel(g),
    b: clamp_channel(b),
    a: clamp_channel(a),
  }
}

///|
pub fn new_image_palette_2x2(
  p00 : Rgba,
  p10 : Rgba,
  p01 : Rgba,
  p11 : Rgba,
) -> ImagePalette2x2 {
  { p00, p10, p01, p11 }
}

///|
pub fn new_solid_palette(color : Rgba) -> ImagePalette2x2 {
  { p00: color, p10: color, p01: color, p11: color }
}

///|
fn channel_from_rgba(color : Rgba, channel_index : Int) -> Int {
  match channel_index {
    0 => color.r
    1 => color.g
    2 => color.b
    3 => color.a
    _ => -1
  }
}

///|
pub fn palette_channel(
  palette : ImagePalette2x2,
  pixel_index : Int,
  channel_index : Int,
) -> Int {
  let color = match pixel_index {
    0 => Some(palette.p00)
    1 => Some(palette.p10)
    2 => Some(palette.p01)
    3 => Some(palette.p11)
    _ => None
  }
  match color {
    Some(rgba) => channel_from_rgba(rgba, channel_index)
    None => -1
  }
}

///|
pub fn checker_palette_from_seed(seed : Int) -> ImagePalette2x2 {
  let normalized_seed = if seed < 0 { 0 } else { seed }
  let seed0 = (normalized_seed * 53 + 17) & 255
  let seed1 = (normalized_seed * 97 + 73) & 255
  let seed2 = (normalized_seed * 193 + 151) & 255
  let inv0 = 255 - seed0
  let inv1 = 255 - seed1
  let inv2 = 255 - seed2
  {
    p00: new_rgba(seed0, seed1, seed2, 255),
    p10: new_rgba(inv0, inv1, inv2, 255),
    p01: new_rgba(inv0, seed1, seed2, 255),
    p11: new_rgba(seed0, inv1, inv2, 255),
  }
}