// The reflective contract every message, enum, list and map implements. The
// encoders and the generator share these traits; nothing here knows a field's
// storage layout.
//
// `Message` and `MessageType` must stay object-safe: a `Value` holds `&Message`,
// so no method on `Message` may return `Self`. The one constructor that does
// return the concrete type lives on `Fresh`, which is used only in generics.

///|
/// A repeated field: zero-indexed and ordered.
pub(open) trait ListField {
  fn length(Self) -> Int32
  fn get(Self, Int32) -> Value
  fn set(Self, Int32, Value) -> Unit
  fn append(Self, Value) -> Unit
  fn append_mutable(Self) -> Value
  fn truncate(Self, Int32) -> Unit
  fn new_element(Self) -> Value
  fn is_valid(Self) -> Bool
}

///|
/// A map field: unordered, keyed by one of the six key kinds.
pub(open) trait MapField {
  fn length(Self) -> Int32
  fn range(Self, (MapKey, Value) -> Bool) -> Unit
  fn has(Self, MapKey) -> Bool
  fn clear(Self, MapKey) -> Unit
  fn get(Self, MapKey) -> Value
  fn set(Self, MapKey, Value) -> Unit
  fn mutable(Self, MapKey) -> Value
  fn new_value(Self) -> Value
  fn is_valid(Self) -> Bool
}

///|
/// A concrete enum value.
pub(open) trait Enum {
  fn descriptor(Self) -> EnumDescriptor
  fn enum_type(Self) -> &EnumType
  fn number(Self) -> Int32
}

///|
/// An enum's concrete type: its descriptor and a constructor.
pub(open) trait EnumType {
  fn new_enum(Self, Int32) -> &Enum
  fn descriptor(Self) -> EnumDescriptor
}

///|
/// A message instance, reachable only through its descriptor.
pub(open) trait Message {
  fn descriptor(Self) -> MessageDescriptor
  fn message_type(Self) -> &MessageType
  fn is_valid(Self) -> Bool
  fn range(Self, (FieldDescriptor, Value) -> Bool) -> Unit
  fn range_extensions(Self, (FieldDescriptor, Value) -> Bool) -> Unit
  fn has(Self, FieldDescriptor) -> Bool
  fn clear(Self, FieldDescriptor) -> Unit
  fn get(Self, FieldDescriptor) -> Value
  fn set(Self, FieldDescriptor, Value) -> Unit
  fn mutable(Self, FieldDescriptor) -> Value
  fn new_field(Self, FieldDescriptor) -> Value
  fn which_oneof(Self, OneofDescriptor) -> Int32?
  fn get_unknown(Self) -> RawFields
  fn set_unknown(Self, RawFields) -> Unit
}

///|
/// A message's concrete type: its descriptor and a constructor.
pub(open) trait MessageType {
  fn new_message(Self) -> &Message
  fn zero(Self) -> &Message
  fn descriptor(Self) -> MessageDescriptor
}

///|
/// A concrete extension: its type and validation of a value assigned to it.
pub(open) trait ExtensionType {
  fn new_value(Self) -> Value
  fn zero(Self) -> Value
  fn descriptor(Self) -> FieldDescriptor
  fn is_valid_value(Self, Value) -> Bool
}

///|
/// A message type that can build an empty instance of its own concrete type.
/// Kept apart from `Message` so that `&Message` stays a usable trait object.
pub(open) trait Fresh {
  fn fresh(Self) -> Self
}

///|
/// The zero value for a scalar kind; `Invalid` for a message or group, which
/// has no scalar zero.
pub fn zero_value(kind : Kind) -> Value {
  match kind {
    Bool => Bool(false)
    Int32 | Sint32 | Sfixed32 => Int32(0)
    Int64 | Sint64 | Sfixed64 => Int64(0L)
    Uint32 | Fixed32 => Uint32(0U)
    Uint64 | Fixed64 => Uint64(0UL)
    Float => Float(@float.Float::from_double(0.0))
    Double => Double(0.0)
    String => String("")
    Bytes => Bytes(b"")
    Enum => Enum(0)
    Message | Group => Invalid
  }
}

///|
/// The value `get` returns for a field that is unset: the declared default when
/// there is one, the kind's zero otherwise.
pub fn default_for(field : FieldDescriptor) -> Value {
  if field.has_default {
    field.default_value
  } else {
    zero_value(field.kind)
  }
}

///|
/// A fresh, mutable value assignable to `field`: an empty list, an empty map, a
/// new message, or the scalar default.
pub fn new_field_value(field : FieldDescriptor) -> Value {
  if field.is_map {
    MapView(ValueMap::new(field))
  } else if field.cardinality == Repeated {
    ListView(ValueList::new(field))
  } else if field.kind.is_message() {
    match field.message_type {
      Some(name) =>
        match global_types.find_message_by_name(name) {
          Some(mt) => Message(mt.new_message())
          None => Invalid
        }
      None => Invalid
    }
  } else {
    default_for(field)
  }
}

///|
/// A fresh value for an element of a list or map.
pub fn new_element_value(kind : Kind, message_type : String?) -> Value {
  if kind.is_message() {
    match message_type {
      Some(name) =>
        match global_types.find_message_by_name(name) {
          Some(mt) => Message(mt.new_message())
          None => Invalid
        }
      None => Invalid
    }
  } else {
    zero_value(kind)
  }
}

///|
/// The dotted path of the first required field that has no value, or `None`
/// when the message and its nested messages are complete. The encoders use
/// this so each can report the omission in its own error type.
pub fn missing_required(message : &Message) -> String? {
  missing_required_at(message, "")
}

///|
fn missing_required_at(message : &Message, prefix : String) -> String? {
  let desc = message.descriptor()
  for number in desc.required_numbers {
    match desc.field_by_number(number) {
      Some(field) =>
        if !message.has(field) {
          return Some(join_path(prefix, field.name))
        }
      None => ()
    }
  }
  for field in desc.fields {
    if field.kind.is_message() &&
      !field.is_map &&
      !field.is_list() &&
      message.has(field) {
      match
        missing_required_at(
          message.get(field).message(),
          join_path(prefix, field.name),
        ) {
        Some(path) => return Some(path)
        None => ()
      }
    }
  }
  None
}

///|
fn join_path(prefix : String, name : String) -> String {
  if prefix.length() == 0 {
    name
  } else {
    prefix + "." + name
  }
}