///|
pub struct Delimiter {
  comma : String
  period : String
  question : String
  exclam : String
  space : String
}

///|
pub type Word = StringView

///|
pub struct Clause(Array[Word]) derive(Debug)

///|
pub enum Termination {
  Period
  Question
  Exclam
  Missing
} derive(Debug)

///|
pub struct Sentence(Array[Clause], Termination) derive(Debug)

///|
pub struct Paragraph(Array[Sentence]) derive(Debug)

///|
pub fn Delimiter::clause(self : Delimiter, view : StringView) -> Clause {
  view.trim().split(self.space).to_array()
}

///|
pub fn Delimiter::sentence(
  self : Delimiter,
  view : StringView,
  kind : Termination,
) -> Sentence {
  Sentence(
    view.split(self.comma).map(clause => self.clause(clause)).to_array(),
    kind,
  )
}

///|
pub fn Delimiter::suffix_kind(
  self : Delimiter,
  v : StringView,
  pred : (StringView, StringView) -> Bool,
) -> (Termination, Int) {
  match () {
    _ if pred(v, self.period) => (Period, self.period.length())
    _ if pred(v, self.question) => (Question, self.question.length())
    _ if pred(v, self.exclam) => (Exclam, self.exclam.length())
    _ => (Missing, 0)
  }
}

///|
pub fn Delimiter::suffix_matcher(
  self : Delimiter,
  v : StringView,
) -> (Termination, Int)? {
  match self.suffix_kind(v, StringView::has_prefix) {
    (Missing, 0) => None
    (kind, length) => Some((kind, length))
  }
}

///|
pub fn Delimiter::strip_sentence_suffix(
  self : Delimiter,
  v : StringView,
) -> (StringView, Termination) {
  match self.suffix_kind(v, StringView::has_suffix) {
    (Missing, _) => (v, Missing)
    (kind, length) => (v.view(end_offset=v.length() - length), kind)
  }
}

///|
pub fn Delimiter::paragraph(
  self : Delimiter,
  view : StringView,
) -> (Paragraph, Termination) {
  let (view, kind) = self.strip_sentence_suffix(view)
  let sentences = string_view_split_match(
      view,
      v => self.suffix_matcher(v),
      kind,
    )
    .map(g => self.sentence(g.1, g.0))
    .to_array()
  (sentences, kind)
}

///|
pub fn Delimiter::display_clause(self : Delimiter, clause : Clause) -> String {
  clause.0.join(self.space)
}

///|
pub fn Delimiter::display_termination(
  self : Delimiter,
  kind : Termination,
) -> String {
  match kind {
    Period => self.period
    Question => self.question
    Exclam => self.exclam
    Missing => ""
  }
}

///|
pub fn Delimiter::display_sentence(
  self : Delimiter,
  sentence : Sentence,
) -> String {
  let clauses = sentence.0
    .map(claude => self.display_clause(claude.0))
    .join(self.comma + self.space)
  clauses + self.display_termination(sentence.1)
}

///|
pub fn Delimiter::display_paragraph(
  self : Delimiter,
  paragraph : Paragraph,
) -> String {
  paragraph.0.map(sentence => self.display_sentence(sentence)).join(self.space)
}