class RubyWasmUi::Utils::Arrays::ArrayWithOriginalIndices

def add_item(item, index)

def add_item(item, index)
  operation = {
    op: ARRAY_DIFF_OP[:ADD],
    index:,
    item:
  }
  @array.insert(index, item)
  @original_indices.insert(index, -1)
  operation
end

def find_index_from(item, from_index)

def find_index_from(item, from_index)
  (from_index...length).each do |index|
    return index if @equal_proc.call(@array[index], item)
  end
  nil
end

def initialize(array, equal_proc)

def initialize(array, equal_proc)
  @array = array.dup
  @original_indices = array.each_index.to_a
  @equal_proc = equal_proc
end

def is_addition?(item, from_index)

def is_addition?(item, from_index)
  return find_index_from(item, from_index).nil?
end

def is_noop?(index, new_array)

def is_noop?(index, new_array)
  return false if index >= length
  item = @array[index]
  new_item = new_array[index]
  @equal_proc.call(item, new_item)
end

def is_removal?(index, new_array)

def is_removal?(index, new_array)
  return false if index >= length
  item = @array[index]
  index_in_new_array = new_array.find_index { |new_item| @equal_proc.call(new_item, item) }
  index_in_new_array.nil?
end

def length

def length
  @array.length
end

def move_item(item, to_index)

def move_item(item, to_index)
  from_index = find_index_from(item, to_index)
  operation = {
    op: ARRAY_DIFF_OP[:MOVE],
    original_index: original_index_at(from_index),
    from: from_index,
    index: to_index,
    item: @array[from_index]
  }
  temp_deleted_item = @array.delete_at(from_index)
  @array.insert(to_index, temp_deleted_item)
  temp_deleted_original_index = @original_indices.delete_at(from_index)
  @original_indices.insert(to_index, temp_deleted_original_index)
  operation
end

def noop_item(index)

def noop_item(index)
  {
    op: ARRAY_DIFF_OP[:NOOP],
    original_index: original_index_at(index),
    index:,
    item: @array[index]
  }
end

def original_index_at(index)

def original_index_at(index)
  @original_indices[index]
end

def remove_item(index)

def remove_item(index)
  operation = {
    op: ARRAY_DIFF_OP[:REMOVE],
    index:,
    item: @array[index]
  }
  @array.delete_at(index)
  @original_indices.delete_at(index)
  operation
end

def remove_item_after(index)

def remove_item_after(index)
  operations = []
  while index < length
    operations << remove_item(index)
  end
  operations
end