///|
/// Normalized waterfall row for renderers.
pub(all) struct WaterfallRow {
  index : Int
  url : String
  domain : String
  http_method : String
  status : Int
  kind : String
  start_offset : Int
  duration : Int
  blocked : Int
  dns : Int
  connect : Int
  ssl : Int
  send : Int
  wait : Int
  receive : Int
  bytes : Int
} derive(Eq, Debug)

///|
pub fn build_waterfall(archive : HarArchive) -> Array[WaterfallRow] {
  let rows : Array[WaterfallRow] = []
  let mut offset = 0
  for i = 0; i < archive.log.entries.length(); i = i + 1 {
    let entry = archive.log.entries[i]
    rows.push(WaterfallRow::{
      index: i,
      url: entry.request.url,
      domain: extract_domain(entry.request.url),
      http_method: entry.request.http_method,
      status: entry.response.status,
      kind: resource_kind(entry.response.content.mime_type, entry.request.url),
      start_offset: offset,
      duration: entry.time,
      blocked: phase(entry.timings.blocked),
      dns: phase(entry.timings.dns),
      connect: phase(entry.timings.connect),
      ssl: phase(entry.timings.ssl),
      send: phase(entry.timings.send),
      wait: phase(entry.timings.wait),
      receive: phase(entry.timings.receive),
      bytes: entry_bytes(entry),
    })
    offset = offset + entry.time
  }
  rows
}

///|
fn phase(value : Int) -> Int {
  if value < 0 {
    0
  } else {
    value
  }
}

///|
pub fn waterfall_total_duration(rows : Array[WaterfallRow]) -> Int {
  let mut total = 0
  for i = 0; i < rows.length(); i = i + 1 {
    let end = rows[i].start_offset + rows[i].duration
    if end > total {
      total = end
    }
  }
  total
}

///|
pub fn render_waterfall_table(rows : Array[WaterfallRow]) -> String {
  let mut out = "idx method status ms kind domain url\n"
  for i = 0; i < rows.length(); i = i + 1 {
    let row = rows[i]
    out = out + row.index.to_string() + " "
    out = out + row.http_method + " "
    out = out + row.status.to_string() + " "
    out = out + row.duration.to_string() + " "
    out = out + row.kind + " "
    out = out + row.domain + " "
    out = out + row.url + "\n"
  }
  out
}

///|
pub fn rows_for_domain(
  rows : Array[WaterfallRow],
  domain : String,
) -> Array[WaterfallRow] {
  let out : Array[WaterfallRow] = []
  for i = 0; i < rows.length(); i = i + 1 {
    if rows[i].domain == domain {
      out.push(rows[i])
    }
  }
  out
}

///|
pub fn rows_for_kind(
  rows : Array[WaterfallRow],
  kind : String,
) -> Array[WaterfallRow] {
  let out : Array[WaterfallRow] = []
  for i = 0; i < rows.length(); i = i + 1 {
    if rows[i].kind == kind {
      out.push(rows[i])
    }
  }
  out
}

///|
pub fn rows_after(
  rows : Array[WaterfallRow],
  offset : Int,
) -> Array[WaterfallRow] {
  let out : Array[WaterfallRow] = []
  for i = 0; i < rows.length(); i = i + 1 {
    if rows[i].start_offset >= offset {
      out.push(rows[i])
    }
  }
  out
}

///|
pub fn row_wait_ratio(row : WaterfallRow) -> Int {
  if row.duration <= 0 {
    0
  } else {
    row.wait * 100 / row.duration
  }
}

///|
pub fn row_receive_ratio(row : WaterfallRow) -> Int {
  if row.duration <= 0 {
    0
  } else {
    row.receive * 100 / row.duration
  }
}