///|
fn pdf_crypto_low_byte(value : Int, shift : Int) -> Byte {
  ((value >> shift) & 0xff).to_byte()
}

///|
fn pdf_arc4_swap(state : Array[Int], left : Int, right : Int) -> Unit {
  let value = state[left]
  state[left] = state[right]
  state[right] = value
}

///|
/// Apply ARC4 to `data` with `key`.
///
/// ARC4 is symmetric, so the same function encrypts and decrypts. Empty keys
/// raise `@core.PdfError::CryptoKeyExpected`.
pub fn pdf_arc4_crypt(
  key : BytesView,
  data : BytesView,
) -> @core.PdfBytes raise @core.PdfError {
  guard key.length() > 0 else { raise CryptoKeyExpected }
  let state = Array::make(256, 0)
  for value in 0..<256 {
    state[value] = value
  }
  let mut j = 0
  for i in 0..<256 {
    j = (j + state[i] + key[i % key.length()].to_int()) % 256
    pdf_arc4_swap(state, i, j)
  }
  let output = Array::make(data.length(), b'\x00')
  let mut i = 0
  j = 0
  let mut output_position = 0
  for byte in data {
    i = (i + 1) % 256
    j = (j + state[i]) % 256
    pdf_arc4_swap(state, i, j)
    let stream_byte = state[(state[i] + state[j]) % 256]
    output[output_position] = (byte.to_int() ^ stream_byte).to_byte()
    output_position += 1
  }
  Bytes::from_array(output)
}