///|
/// One ordered part of the message text of an event. A renderer uses the
/// segments to show the literal text and the bound values in different styles.
/// The text of all segments, in order, is equal to `LogEvent::message`.
pub(all) enum MessageSegment {
  /// Literal text of the template. A hole that has no property stays here as
  /// its literal text, for example `{Target}`, as `message` shows it.
  Text(String)
  /// A hole with a bound property: the hole name and the JSON value. When a name
  /// occurs in more than one hole, each of these holes holds the first value.
  Value(name~ : String, value~ : Json)
} derive(Eq, Debug)

///|
pub extend MessageSegment with Eq::{equal, not_equal}

///|
pub extend MessageSegment with @debug.Debug::{to_repr}

///|
/// The text of the segment in the message: the literal text, or the value as
/// `message` shows it. A JSON string has no quotes, and each other value is
/// compact JSON.
pub fn MessageSegment::text(self : MessageSegment) -> String {
  match self {
    Text(text) => text
    Value(value~, ..) => render_value(value)
  }
}

///|
/// The message as ordered segments. Two literal parts next to each other join
/// into one `Text` segment. The result is a copy: a change to it, or to a JSON
/// array or object in it, does not change the event.
pub fn LogEvent::segments(self : LogEvent) -> Array[MessageSegment] {
  let segments : Array[MessageSegment] = []
  let text = StringBuilder()
  let flush = () => {
    if !text.is_empty() {
      segments.push(Text(text.to_string()))
      text.reset()
    }
  }
  for part in parse_template(self.template) {
    match part {
      Literal(literal) => text.write_string(literal)
      Hole(name) =>
        match self.find(name) {
          Some(value) => {
            flush()
            segments.push(Value(name~, value=copy_json(value)))
          }
          None => text.write_string("{\{name}}")
        }
    }
  }
  flush()
  segments
}