// Port of rich/_log_render.py.

///|
/// Renders the layout of `Console.log` (and `RichHandler`).
pub struct LogRender {
  show_time : Bool
  show_level : Bool
  show_path : Bool
  time_format : String
  time_formatter : ((Double) -> Text)?
  omit_repeated_times : Bool
  level_width : Int?
  priv mut last_time : Text?
}

///|
/// `time_format` is a C `strftime` format; `time_formatter` overrides it
/// with a function from the time (seconds since the epoch) to a Text.
pub fn LogRender::new(
  show_time? : Bool = true,
  show_level? : Bool = false,
  show_path? : Bool = true,
  time_format? : String = "[%x %X]",
  time_formatter? : (Double) -> Text,
  omit_repeated_times? : Bool = true,
  level_width? : Int? = Some(8),
) -> LogRender {
  {
    show_time,
    show_level,
    show_path,
    time_format,
    time_formatter,
    omit_repeated_times,
    level_width,
    last_time: None,
  }
}

///|
/// Build the log line as a grid table.
pub fn LogRender::render(
  self : LogRender,
  console : Console,
  renderables : Array[&Renderable],
  log_time? : Double,
  time_format? : String,
  level? : &IntoText,
  path? : String,
  line_no? : Int,
  link_path? : String,
) -> Table raise {
  let output = Table::grid(padding=[0, 1])
  output.set_expand(true)
  if self.show_time {
    output.add_column(style="log.time")
  }
  if self.show_level {
    output.add_column(style="log.level", width?=self.level_width)
  }
  output.add_column(ratio=1, style="log.message", overflow=Fold)
  let path = match path {
    Some(p) if p != "" => Some(p)
    _ => None
  }
  if self.show_path && path is Some(_) {
    output.add_column(style="log.path")
  }
  let row : Array[&Renderable] = []
  if self.show_time {
    let log_time = match log_time {
      Some(t) => t
      None => (console.get_datetime)()
    }
    let log_time_display = match self.time_formatter {
      Some(f) if time_format is None => f(log_time)
      _ =>
        Text::new(
          text=@term.strftime(time_format.unwrap_or(self.time_format), log_time),
        )
    }
    if self.last_time is Some(last) &&
      last == log_time_display &&
      self.omit_repeated_times {
      row.push(Text::new(text=space_string(log_time_display.length())))
    } else {
      row.push(log_time_display)
      self.last_time = Some(log_time_display)
    }
  }
  if self.show_level {
    match level {
      Some(l) =>
        match l.into_text_type() {
          Str(s) => row.push(s)
          Text(t) => row.push(t)
        }
      None => row.push("")
    }
  }
  row.push(Renderables::new(renderables~))
  if self.show_path && path is Some(path) {
    let path_text = Text::new()
    path_text.append_str(
      path,
      style=match link_path {
        Some(lp) => "link file://\{lp}"
        None => ""
      },
    )
    |> ignore
    if line_no is Some(line_no) && line_no != 0 {
      path_text.append_str(":") |> ignore
      path_text.append_str(
        "\{line_no}",
        style=match link_path {
          Some(lp) => "link file://\{lp}#\{line_no}"
          None => ""
        },
      )
      |> ignore
    }
    row.push(path_text)
  }
  output.add_row(row)
  output
}