Documentation
use crate::{
  command::EmapiCommand,
  constants::{COMMAND_HEADER_LENGTH, FRAME_HEAD, FRAME_OVERHEAD_LENGTH},
  endian::read_uint16,
  error::{EmapiError, Result},
  frame_codec::FrameCodec,
};

#[derive(Debug, Default, Clone)]
pub struct FrameParser {
  buffer: Vec<u8>,
}

impl FrameParser {
  pub fn new() -> Self {
    Self::default()
  }

  pub fn add(&mut self, data: &[u8]) -> Result<Vec<EmapiCommand>> {
    self.buffer.extend_from_slice(data);
    let mut commands = Vec::new();

    loop {
      let Some(head_index) = self.buffer.iter().position(|byte| *byte == FRAME_HEAD) else {
        self.buffer.clear();
        return Ok(commands);
      };
      if head_index > 0 {
        self.buffer.drain(..head_index);
      }
      if self.buffer.len() < 4 {
        return Ok(commands);
      }

      let data_length = usize::from(read_uint16(&self.buffer, 2)?);
      let frame_length = data_length + FRAME_OVERHEAD_LENGTH;
      if data_length < COMMAND_HEADER_LENGTH {
        self.buffer.remove(0);
        return Err(EmapiError::InvalidFrameDataLength);
      }
      if self.buffer.len() < frame_length {
        return Ok(commands);
      }

      let frame: Vec<u8> = self.buffer.drain(..frame_length).collect();
      commands.push(FrameCodec::decode(&frame)?);
    }
  }
}