// The default list and map implementations. A generated message may use these
// directly; a message type with its own storage may implement the traits
// itself.

///|
/// A list backed by an array. It remembers the element kind so that a new
/// element can be built without consulting the descriptor again.
pub struct ValueList {
  element_kind : Kind
  element_message_type : String?
  items : Array[Value]
}

///|
pub fn ValueList::new(field : FieldDescriptor) -> ValueList {
  {
    element_kind: field.kind,
    element_message_type: field.message_type,
    items: [],
  }
}

///|
pub fn ValueList::from_array(
  field : FieldDescriptor,
  items : Array[Value],
) -> ValueList {
  { element_kind: field.kind, element_message_type: field.message_type, items, }
}

///|
pub impl ListField for ValueList with fn length(self) -> Int32 {
  self.items.length()
}

///|
pub impl ListField for ValueList with fn get(self, index : Int32) -> Value {
  self.items[index]
}

///|
pub impl ListField for ValueList with fn set(self, index : Int32, value : Value) -> Unit {
  self.items[index] = value
}

///|
pub impl ListField for ValueList with fn append(self, value : Value) -> Unit {
  self.items.push(value)
}

///|
pub impl ListField for ValueList with fn append_mutable(self) -> Value {
  let value = new_element_value(self.element_kind, self.element_message_type)
  self.items.push(value)
  value
}

///|
pub impl ListField for ValueList with fn truncate(self, length : Int32) -> Unit {
  if length < self.items.length() {
    self.items.resize(length, Invalid)
  }
}

///|
pub impl ListField for ValueList with fn new_element(self) -> Value {
  new_element_value(self.element_kind, self.element_message_type)
}

///|
pub impl ListField for ValueList with fn is_valid(_self) -> Bool {
  true
}

///|
pub extend ValueList with ListField::{
  length,
  get,
  set,
  append,
  append_mutable,
  truncate,
  new_element,
  is_valid,
}

///|
/// A map backed by an association array. Protobuf maps are usually small, and a
/// linear lookup avoids requiring the key type to be hashable here.
pub struct ValueMap {
  key_kind : Kind
  value_kind : Kind
  value_message_type : String?
  entries : Array[(MapKey, Value)]
}

///|
pub fn ValueMap::new(field : FieldDescriptor) -> ValueMap {
  let key_kind = match field.map_key_field {
    Some(key) => key.kind
    None => String
  }
  let (value_kind, value_message_type) = match field.map_value_field {
    Some(value) => (value.kind, value.message_type)
    None => (String, None)
  }
  { key_kind, value_kind, value_message_type, entries: [], }
}

///|
fn ValueMap::index_of(self : ValueMap, key : MapKey) -> Int32 {
  let mut found = -1
  let mut i = 0
  while i < self.entries.length() {
    if self.entries[i].0 == key {
      found = i
      break
    }
    i = i + 1
  }
  found
}

///|
pub impl MapField for ValueMap with fn length(self) -> Int32 {
  self.entries.length()
}

///|
pub impl MapField for ValueMap with fn range(self, f : (MapKey, Value) -> Bool) -> Unit {
  let mut i = 0
  while i < self.entries.length() {
    let (key, value) = self.entries[i]
    if !f(key, value) {
      break
    }
    i = i + 1
  }
}

///|
pub impl MapField for ValueMap with fn has(self, key : MapKey) -> Bool {
  self.index_of(key) >= 0
}

///|
pub impl MapField for ValueMap with fn clear(self, key : MapKey) -> Unit {
  let index = self.index_of(key)
  if index >= 0 {
    let _ = self.entries.remove(index)
  }
}

///|
pub impl MapField for ValueMap with fn get(self, key : MapKey) -> Value {
  let index = self.index_of(key)
  if index >= 0 {
    self.entries[index].1
  } else {
    Invalid
  }
}

///|
pub impl MapField for ValueMap with fn set(self, key : MapKey, value : Value) -> Unit {
  let index = self.index_of(key)
  if index >= 0 {
    self.entries[index] = (key, value)
  } else {
    self.entries.push((key, value))
  }
}

///|
pub impl MapField for ValueMap with fn mutable(self, key : MapKey) -> Value {
  let index = self.index_of(key)
  if index >= 0 {
    self.entries[index].1
  } else {
    let value = new_element_value(self.value_kind, self.value_message_type)
    self.entries.push((key, value))
    value
  }
}

///|
pub impl MapField for ValueMap with fn new_value(self) -> Value {
  new_element_value(self.value_kind, self.value_message_type)
}

///|
pub impl MapField for ValueMap with fn is_valid(_self) -> Bool {
  true
}

///|
pub extend ValueMap with MapField::{
  length,
  range,
  has,
  clear,
  get,
  set,
  mutable,
  new_value,
  is_valid,
}