Documentation
use crate::{
  constants::{COMMAND_HEADER_LENGTH, FRAME_OVERHEAD_LENGTH, PRINT_TRANSFER_FRAME_OVERHEAD_LENGTH},
  error::{EmapiError, Result},
};

pub const FILE_TRANSFER_CHUNK_HEADER_LENGTH: usize = 4;
pub const FILE_TRANSFER_PAYLOAD_ALIGNMENT: usize = 32;

pub fn print_transfer_payload_capacity(max_packet_length: usize) -> Result<usize> {
  let Some(capacity) = max_packet_length.checked_sub(PRINT_TRANSFER_FRAME_OVERHEAD_LENGTH) else {
    return Err(EmapiError::InvalidCapacity {
      name: "print transfer payload",
    });
  };
  if capacity == 0 {
    return Err(EmapiError::InvalidCapacity {
      name: "print transfer payload",
    });
  }
  Ok(capacity)
}

pub fn file_transfer_payload_capacity(mtu: usize) -> Result<usize> {
  let overhead = FRAME_OVERHEAD_LENGTH + COMMAND_HEADER_LENGTH + FILE_TRANSFER_CHUNK_HEADER_LENGTH;
  let Some(capacity) = mtu.checked_sub(overhead) else {
    return Err(EmapiError::InvalidCapacity {
      name: "file transfer payload",
    });
  };
  let aligned_capacity =
    capacity / FILE_TRANSFER_PAYLOAD_ALIGNMENT * FILE_TRANSFER_PAYLOAD_ALIGNMENT;
  if aligned_capacity == 0 {
    return Err(EmapiError::InvalidCapacity {
      name: "file transfer payload",
    });
  }
  Ok(aligned_capacity)
}

pub fn chunk_print_data(data: &[u8], max_packet_length: usize) -> Result<Vec<Vec<u8>>> {
  let payload_capacity = print_transfer_payload_capacity(max_packet_length)?;
  let mut chunks = Vec::new();
  for chunk in data.chunks(payload_capacity) {
    chunks.push(chunk.to_vec());
  }
  Ok(chunks)
}