Documentation
use psdk_extension::imagep;
use psdk_extension::imagep::ConvertBitmapOptions;
pub use psdk_extension::imagep::{ThresholdEdgeDitherDepth, ThresholdEdgeDitherMode};
use psdk_father::args::{ArgContext, PsdkArgBase, PsdkEasyArg, Raw};
use psdk_father::command::{CommandClause, Commander, PsdkCommand, PsdkTextCommand};
use psdk_father::errors::{PsdkFatherError, PsdkFatherResult};
use std::sync::{Arc, Mutex};

#[derive(Clone, Debug)]
pub struct CImagePixelsOptions {
  /// 图片起始x坐标
  pub x: i32,
  /// 图片起始y坐标
  pub y: i32,
  /// 图片数据
  pub pixels: Vec<u8>,
  /// 图片宽度
  pub width: u32,
  /// 图片高度
  pub height: u32,
  /// 是否压缩
  pub compress: bool,
  /// 是否反色
  pub reverse: bool,
  /// 二值化0-255(默认190)
  pub gray_threshold: Option<i32>,
  /// 平滑权重(默认0)
  pub smooth_weight: i32,
  /// 边缘抖动模式
  pub edge_dither_mode: Option<ThresholdEdgeDitherMode>,
  /// 边缘抖动深度
  pub edge_dither_depth: ThresholdEdgeDitherDepth,
}

#[derive(Clone, Debug)]
pub struct CImagePixels {
  options: CImagePixelsOptions,
  ctx: Arc<Mutex<ArgContext>>,
}

impl CImagePixels {
  pub fn new(options: CImagePixelsOptions) -> Self {
    Self {
      options,
      ctx: Default::default(),
    }
  }
}

impl From<(i32, i32, Vec<u8>, u32, u32)> for CImagePixels {
  fn from((x, y, pixels, width, height): (i32, i32, Vec<u8>, u32, u32)) -> Self {
    Self::new(CImagePixelsOptions {
      x,
      y,
      pixels,
      width,
      height,
      compress: false,
      reverse: false,
      gray_threshold: None,
      smooth_weight: 0,
      edge_dither_mode: None,
      edge_dither_depth: Default::default(),
    })
  }
}

impl PsdkEasyArg<String> for CImagePixels {
  fn context(&self) -> Arc<Mutex<ArgContext>> {
    self.ctx.clone()
  }
}

impl PsdkArgBase<String> for CImagePixels {
  fn header(&self) -> String {
    if self.options.compress {
      "ZG".to_string()
    } else {
      "CG".to_string()
    }
  }

  fn clause(&self) -> PsdkFatherResult<CommandClause> {
    let cbi = imagep::convert_to_bitmap(ConvertBitmapOptions {
      compress: self.options.compress,
      reverse: self.options.reverse,
      width: self.options.width,
      height: self.options.height,
      pixels: self.options.pixels.clone(),
      gray_threshold: self.options.gray_threshold,
      smooth_weight: self.options.smooth_weight,
      edge_dither_mode: self.options.edge_dither_mode,
      edge_dither_depth: self.options.edge_dither_depth,
    })
    .map_err(|e| PsdkFatherError::Custom(format!("Extension: {:?}", e)))?;

    let height = self.options.height;
    let byte_width = cbi.byte_width;
    let converted_bitmap_data = cbi.data;

    let mut commander = Commander::new();
    let mut ptc = PsdkTextCommand::with_header_format_cpcl(self.header());
    ptc
      .append(byte_width)
      .append(height)
      .append(if self.options.compress {
        self.options.x / 8
      } else {
        self.options.x
      })
      .append(self.options.y);
    if self.options.compress {
      ptc.append(converted_bitmap_data.len());
    }
    commander
      .push_clause(ptc.clause(), false)
      .push_text_with_newline(" ", false)
      .push_binary_with_newline(&converted_bitmap_data, false)
      .newline();
    let command = commander.command()?;
    Raw::new().push_binary(command.binary()).clause()
  }
}

psdk_father::impl_psdk_arg_to_easy_arg!(String, CImagePixels, true);