///|
pub struct ReportIndexEntry {
  id : String
  title : String
  keywords : Array[String]
  report : ChemReport
} derive(Debug, Eq)

///|
pub struct ReportIndex {
  entries : Array[ReportIndexEntry]
} derive(Debug, Eq)

///|
pub fn report_index() -> ReportIndex {
  { entries: [] }
}

///|
pub fn ReportIndex::add(
  self : ReportIndex,
  id : String,
  report : ChemReport,
  keywords : Array[String],
) -> ReportIndex {
  self.entries.push({ id, title: report.title, keywords, report })
  self
}

///|
pub fn ReportIndex::entries(self : ReportIndex) -> Array[ReportIndexEntry] {
  self.entries.copy()
}

///|
pub fn ReportIndex::search(
  self : ReportIndex,
  term : String,
) -> Array[ChemReport] {
  let query = term.trim().to_lower()
  let matches : Array[ChemReport] = []
  for item in self.entries {
    let keyword_match = item.keywords.fold(init=false, (found, value) => {
      found || value.to_lower().contains(query)
    })
    if query == "" ||
      item.id.to_lower().contains(query) ||
      item.title.to_lower().contains(query) ||
      keyword_match {
      matches.push(item.report)
    }
  }
  matches
}

///|
pub fn ReportIndex::publishable(self : ReportIndex) -> Array[ReportIndexEntry] {
  [
    for item in self.entries if item.report.is_publishable() => item
  ]
}