///|
pub fn Align::left() -> Align {
  Left
}

///|
pub fn Align::right() -> Align {
  Right
}

///|
pub fn Align::center() -> Align {
  Center
}

///|
pub fn VAlign::top() -> VAlign {
  Top
}

///|
pub fn VAlign::bottom() -> VAlign {
  Bottom
}

///|
pub fn VAlign::center() -> VAlign {
  Center
}

///|
pub fn Padding::zero() -> Padding {
  Padding::new(0, 0, 0, 0)
}

///|
/// Wrap records at a cell width with `modify`, or fit the total table with `with_`.
///
/// ```mbt check
/// test {
///   let table = @tabular.Table::from_rows([["hello world"]])
///   table.modify((0, 0), @tabular.Width::wrap(7).keep_words(true)) |> ignore
///   assert_eq(table.rows, [["hello \nworld"]])
/// }
/// ```
pub fn[M] Width::wrap(width : M) -> Wrap[M, PriorityRoundRobin] {
  Wrap::new(width)
}

///|
pub fn Width::wrap_with(
  width : Int,
  placeholder : String,
) -> Wrap[Int, PriorityRoundRobin] {
  { ..Wrap::new(width), placeholder, }
}

///|
pub fn[M] Width::truncate(
  width : M,
  suffix? : String = "",
) -> Truncate[M, PriorityRoundRobin] {
  Truncate::new(width).suffix(suffix)
}

///|
pub fn[M] Height::increase(height : M) -> CellHeightIncrease[M] {
  CellHeightIncrease::new(height)
}

///|
pub fn[M] Height::limit(height : M) -> CellHeightLimit[M] {
  CellHeightLimit::new(height)
}

///|
pub fn Format::surround(prefix : String, suffix : String) -> Format {
  Surround(prefix, suffix, false)
}

///|
pub fn Format::value(text : String) -> Format {
  Value(text, false)
}

///|
pub fn Format::content(transform : (String) -> String) -> Format {
  Content(transform, false)
}

///|
pub fn Format::positioned(transform : (String, Int, Int) -> String) -> Format {
  Positioned(transform, false)
}

///|
pub fn Format::multiline(self : Format) -> Format {
  match self {
    Surround(prefix, suffix, _) => Surround(prefix, suffix, true)
    Value(text, _) => Value(text, true)
    Content(transform, _) => Content(transform, true)
    Positioned(transform, _) => Positioned(transform, true)
  }
}

///|
pub fn Rows::new(start : Int, end_ : Int) -> Rows {
  { start, end_, skip_n: 0, step_n: 1, exclude: None, predicate: None, }
}

///|
pub fn Rows::first() -> Rows {
  Rows::new(0, 1)
}

///|
pub fn Rows::one(index : Int) -> Rows {
  Rows::new(index, index + 1)
}

///|
pub fn Rows::first_offset(offset : Int) -> Rows {
  Rows::one(offset)
}

///|
pub fn Rows::last() -> Rows {
  Rows::new(-2, 0)
}

///|
pub fn Rows::last_offset(offset : Int) -> Rows {
  Rows::new(-2 - offset, 0)
}

///|
pub fn Rows::all() -> Rows {
  Rows::new(0, -1)
}

///|
pub fn Rows::intersect(self : Rows, cols : Cols) -> Segment {
  { kind: Cross(self, cols), skip_n: 0, step_n: 1, }
}

///|
pub fn Rows::and_(self : Rows, other : Rows) -> Segment {
  self.as_segment().and_(other.as_segment())
}

///|
pub fn Rows::and_cols(self : Rows, cols : Cols) -> Segment {
  self.as_segment().and_(cols.as_segment())
}

///|
pub fn Rows::and_cell(self : Rows, cell : Cell) -> Segment {
  self.as_segment().and_(cell.as_segment())
}

///|
pub fn Rows::as_segment(self : Rows) -> Segment {
  { kind: RowsOnly(self), skip_n: 0, step_n: 1, }
}

///|
pub fn Rows::inverse(self : Rows) -> Segment {
  { kind: InverseRows(self), skip_n: 0, step_n: 1, }
}

///|
pub fn Rows::not(self : Rows, other : Rows) -> Rows {
  {
    start: self.start,
    end_: self.end_,
    skip_n: self.skip_n,
    step_n: self.step_n,
    exclude: Some(other),
    predicate: self.predicate,
  }
}

///|
pub fn Rows::not_cols(self : Rows, cols : Cols) -> Segment {
  self.as_segment().not(cols.as_segment())
}

///|
pub fn Rows::not_cell(self : Rows, cell : Cell) -> Segment {
  self.as_segment().not(cell.as_segment())
}

///|
pub fn Rows::skip(self : Rows, count : Int) -> Rows {
  {
    start: self.start,
    end_: self.end_,
    skip_n: count,
    step_n: self.step_n,
    exclude: self.exclude,
    predicate: self.predicate,
  }
}

///|
pub fn Rows::step_by(self : Rows, step : Int) -> Rows {
  {
    start: self.start,
    end_: self.end_,
    skip_n: self.skip_n,
    step_n: if step <= 0 {
      1
    } else {
      step
    },
    exclude: self.exclude,
    predicate: self.predicate,
  }
}

///|
pub fn Rows::filter(self : Rows, predicate : (Entity) -> Bool) -> Rows {
  {
    start: self.start,
    end_: self.end_,
    skip_n: self.skip_n,
    step_n: self.step_n,
    exclude: self.exclude,
    predicate: Some(predicate),
  }
}

///|
pub fn Cols::new(start : Int, end_ : Int) -> Cols {
  { start, end_, skip_n: 0, step_n: 1, exclude: None, predicate: None, }
}

///|
pub fn Cols::first() -> Cols {
  Cols::new(0, 1)
}

///|
pub fn Cols::one(index : Int) -> Cols {
  Cols::new(index, index + 1)
}

///|
pub fn Cols::first_offset(offset : Int) -> Cols {
  Cols::one(offset)
}

///|
pub fn Cols::last() -> Cols {
  Cols::new(-2, 0)
}

///|
pub fn Cols::last_offset(offset : Int) -> Cols {
  Cols::new(-2 - offset, 0)
}

///|
pub fn Cols::all() -> Cols {
  Cols::new(0, -1)
}

///|
pub fn Cols::intersect(self : Cols, rows : Rows) -> Segment {
  { kind: Cross(rows, self), skip_n: 0, step_n: 1, }
}

///|
pub fn Cols::and_(self : Cols, other : Cols) -> Segment {
  self.as_segment().and_(other.as_segment())
}

///|
pub fn Cols::and_rows(self : Cols, rows : Rows) -> Segment {
  self.as_segment().and_(rows.as_segment())
}

///|
pub fn Cols::and_cell(self : Cols, cell : Cell) -> Segment {
  self.as_segment().and_(cell.as_segment())
}

///|
pub fn Cols::as_segment(self : Cols) -> Segment {
  { kind: ColsOnly(self), skip_n: 0, step_n: 1, }
}

///|
pub fn Cols::inverse(self : Cols) -> Segment {
  { kind: InverseCols(self), skip_n: 0, step_n: 1, }
}

///|
pub fn Cols::not(self : Cols, other : Cols) -> Cols {
  {
    start: self.start,
    end_: self.end_,
    skip_n: self.skip_n,
    step_n: self.step_n,
    exclude: Some(other),
    predicate: self.predicate,
  }
}

///|
pub fn Cols::not_rows(self : Cols, rows : Rows) -> Segment {
  self.as_segment().not(rows.as_segment())
}

///|
pub fn Cols::not_cell(self : Cols, cell : Cell) -> Segment {
  self.as_segment().not(cell.as_segment())
}

///|
pub fn Cols::skip(self : Cols, count : Int) -> Cols {
  {
    start: self.start,
    end_: self.end_,
    skip_n: count,
    step_n: self.step_n,
    exclude: self.exclude,
    predicate: self.predicate,
  }
}

///|
pub fn Cols::step_by(self : Cols, step : Int) -> Cols {
  {
    start: self.start,
    end_: self.end_,
    skip_n: self.skip_n,
    step_n: if step <= 0 {
      1
    } else {
      step
    },
    exclude: self.exclude,
    predicate: self.predicate,
  }
}

///|
pub fn Cols::filter(self : Cols, predicate : (Entity) -> Bool) -> Cols {
  {
    start: self.start,
    end_: self.end_,
    skip_n: self.skip_n,
    step_n: self.step_n,
    exclude: self.exclude,
    predicate: Some(predicate),
  }
}

///|
pub fn Segment::all() -> Segment {
  { kind: All, skip_n: 0, step_n: 1, }
}

///|
pub fn Cell::new(row : Int, col : Int) -> Cell {
  { row, col, }
}

///|
pub fn ByColName::new(name : String) -> ByColName {
  { name, }
}

///|
pub fn Cell::as_segment(self : Cell) -> Segment {
  { kind: CellOnly(self), skip_n: 0, step_n: 1, }
}

///|
pub fn Cell::and_(self : Cell, other : Cell) -> Segment {
  self.as_segment().and_(other.as_segment())
}

///|
pub fn Cell::not(self : Cell, other : Cell) -> Segment {
  self.as_segment().not(other.as_segment())
}

///|
pub fn Cell::inverse(self : Cell) -> Segment {
  { kind: InverseCell(self), skip_n: 0, step_n: 1, }
}

///|
pub fn Segment::new(
  row_start : Int,
  row_end : Int,
  col_start : Int,
  col_end : Int,
) -> Segment {
  { kind: Range(row_start, row_end, col_start, col_end), skip_n: 0, step_n: 1, }
}

///|
pub fn Segment::and_(self : Segment, other : Segment) -> Segment {
  { kind: Union2(self, other), skip_n: 0, step_n: 1, }
}

///|
pub fn Segment::and_rows(self : Segment, rows : Rows) -> Segment {
  self.and_(rows.as_segment())
}

///|
pub fn Segment::and_cols(self : Segment, cols : Cols) -> Segment {
  self.and_(cols.as_segment())
}

///|
pub fn Segment::and_cell(self : Segment, cell : Cell) -> Segment {
  self.and_(cell.as_segment())
}

///|
pub fn Segment::not_(self : Segment, other : Segment) -> Segment {
  { kind: Diff2(self, other), skip_n: 0, step_n: 1, }
}

///|
pub fn Segment::not(self : Segment, other : Segment) -> Segment {
  self.not_(other)
}

///|
pub fn Segment::not_cell(self : Segment, cell : Cell) -> Segment {
  self.not(cell.as_segment())
}

///|
pub fn Segment::skip(self : Segment, count : Int) -> Segment {
  { ..self, skip_n: count, }
}

///|
pub fn Segment::step_by(self : Segment, step : Int) -> Segment {
  { ..self, step_n: if step <= 0 { 1 } else { step }, }
}

///|
pub fn Setting::align(align : Align) -> Setting {
  Align(align)
}

///|
pub fn Setting::valign(align : VAlign) -> Setting {
  VAlign(align)
}

///|
pub fn Setting::padding(padding : Padding) -> Setting {
  Pad(padding)
}

///|
pub fn Setting::format(format : Format) -> Setting {
  Fmt(format)
}

///|
pub fn[W : WidthOption] Setting::width(width : W) -> Setting {
  W(WidthOption::to_mode(width))
}

///|
pub fn[H : HeightOption] Setting::height(height : H) -> Setting {
  H(HeightOption::to_mode(height))
}

///|
pub fn Span::col(size : Int) -> Setting {
  SpanCol(size)
}

///|
pub fn Span::row(size : Int) -> Setting {
  SpanRow(size)
}

///|
pub fn Padding::new(
  left : Int,
  right : Int,
  top : Int,
  bottom : Int,
) -> Padding {
  {
    left: Int::max(0, left),
    right: Int::max(0, right),
    top: Int::max(0, top),
    bottom: Int::max(0, bottom),
    fills: @papergrid.Sides::filled(' '),
  }
}