///|
pub(all) struct MarkdownTableParseResult {
  block : MarkdownBlock
  end_index : Int
} derive(Eq, Debug)

///|
fn markdown_table_block_at(
  lines : Array[String],
  index : Int,
) -> MarkdownTableParseResult? {
  if index + 1 >= lines.length() ||
    !markdown_table_separator_line(lines[index + 1]) {
    return None
  }
  let segment_lines : Array[String] = [lines[index], lines[index + 1]]
  let mut next = index + 2
  while next < lines.length() && markdown_table_body_line(lines[next]) {
    segment_lines.push(lines[next])
    next = next + 1
  }
  Some({
    block: markdown_table_block(
      markdown_table_text_from_source_lines(segment_lines),
      markdown_table_alignments_for_separator(lines[index + 1]),
    ),
    end_index: next - 1,
  })
}

///|
fn markdown_table_separator_line(line : String) -> Bool {
  let trimmed = line.trim().to_owned()
  if !trimmed.contains("|") {
    return false
  }
  let cells = markdown_split_table_cells(trimmed)
  if cells.length() == 0 {
    return false
  }
  for cell in cells {
    if !markdown_table_separator_cell(cell.trim().to_owned()) {
      return false
    }
  }
  true
}

///|
fn markdown_table_separator_cell(cell : String) -> Bool {
  let chars = cell.to_array()
  let mut dash_count = 0
  for ch in chars {
    if ch == '-' {
      dash_count = dash_count + 1
    } else if ch != ':' && ch != ' ' && ch != '\t' {
      return false
    }
  }
  dash_count >= 3
}

///|
fn markdown_table_body_line(line : String) -> Bool {
  let trimmed = line.trim().to_owned()
  trimmed != "" && trimmed.contains("|")
}

///|
pub fn markdown_split_table_cells(line : String) -> Array[String] {
  let cells : Array[String] = []
  let chars = line.to_array()
  let mut start = 0
  let mut end = chars.length()
  if start < end && chars[start] == '|' {
    start = start + 1
  }
  if end > start &&
    chars[end - 1] == '|' &&
    markdown_editor_table_pipe_is_separator(chars, end - 1) {
    end = end - 1
  }
  let current : Array[Char] = []
  let mut index = start
  while index < end {
    if chars[index] == '|' &&
      markdown_editor_table_pipe_is_separator(chars, index) {
      cells.push(String::from_array(current))
      current.clear()
    } else {
      current.push(chars[index])
    }
    index = index + 1
  }
  cells.push(String::from_array(current))
  cells
}

///|
fn markdown_table_block(
  text : String,
  table_alignments : Array[@core.TextAlign?],
) -> MarkdownBlock {
  {
    kind: MarkdownBlockKind::Table,
    text,
    inlines: [],
    table_alignments,
    code_language: None,
  }
}

///|
fn markdown_table_text(
  header : Array[@md.TableCell],
  rows : Array[Array[@md.TableCell]],
) -> String {
  let lines : Array[String] = []
  lines.push(markdown_table_row_text(header))
  for row in rows {
    lines.push(markdown_table_row_text(row))
  }
  markdown_join_lines(lines)
}

///|
fn markdown_table_text_from_source_lines(lines : Array[String]) -> String {
  let rows : Array[String] = []
  for index in 0.. String {
  let cells : Array[String] = []
  for cell in row {
    cells.push(markdown_inline_text(cell.children).trim().to_owned())
  }
  cells.join("  |  ")
}

///|
fn markdown_table_preview(
  block : MarkdownBlock,
  base : @core.FontSpec,
) -> RichTextTable? {
  match block.kind {
    Table => {
      let lines = markdown_split_lines(block.text)
      if lines.length() == 0 {
        return None
      }
      let rows : Array[Array[RichTextTableCell]] = []
      let aligns = block.table_alignments
      let mut line_offset = 0
      for index in 0.. None
  }
}

///|
pub(all) struct MarkdownTableCellPreviewRange {
  text : String
  start : Int
  end : Int
}

///|
fn markdown_table_cell_ranges_for_line(
  line : String,
) -> Array[MarkdownTableCellPreviewRange] {
  let cells : Array[MarkdownTableCellPreviewRange] = []
  let chars = line.to_array()
  let mut start = 0
  let mut end = chars.length()
  if start < end && chars[start] == '|' {
    start = start + 1
  }
  if end > start &&
    chars[end - 1] == '|' &&
    markdown_editor_table_pipe_is_separator(chars, end - 1) {
    end = end - 1
  }
  let mut segment_start = start
  let mut index = start
  while index <= end {
    if index == end ||
      (
        chars[index] == '|' &&
        markdown_editor_table_pipe_is_separator(chars, index)
      ) {
      let range = markdown_table_trimmed_range(chars, segment_start, index)
      cells.push({
        text: String::from_array(chars[range.start:range.end]),
        start: range.start,
        end: range.end,
      })
      segment_start = index + 1
    }
    index = index + 1
  }
  cells
}

///|
fn markdown_table_alignments_for_separator(
  line : String,
) -> Array[@core.TextAlign?] {
  let aligns : Array[@core.TextAlign?] = []
  for cell in markdown_split_table_cells(line) {
    aligns.push(markdown_table_alignment_for_separator_cell(cell))
  }
  aligns
}

///|
fn markdown_table_alignment_for_separator_cell(
  cell : String,
) -> @core.TextAlign? {
  let trimmed = cell.trim().to_owned()
  let chars = trimmed.to_array()
  if chars.length() == 0 {
    return None
  }
  let leading = chars[0] == ':'
  let trailing = chars[chars.length() - 1] == ':'
  if leading && trailing {
    Some(@core.TextAlign::TextCenter)
  } else if trailing {
    Some(@core.TextAlign::TextEnd)
  } else {
    None
  }
}

///|
fn markdown_table_alignment_at(
  aligns : Array[@core.TextAlign?],
  index : Int,
) -> @core.TextAlign? {
  if index >= 0 && index < aligns.length() {
    aligns[index]
  } else {
    None
  }
}

///|
fn markdown_table_trimmed_range(
  chars : Array[Char],
  start : Int,
  end : Int,
) -> RichTextSourceRange {
  let mut content_start = start
  let mut content_end = end
  while content_start < content_end &&
        (chars[content_start] == ' ' || chars[content_start] == '\t') {
    content_start = content_start + 1
  }
  while content_end > content_start &&
        (chars[content_end - 1] == ' ' || chars[content_end - 1] == '\t') {
    content_end = content_end - 1
  }
  { start: content_start, end: content_end }
}