///|
/// A small dependency-free importer for normalized CSV exchange files.
pub struct CsvImportResult {
  entries : Array[Entry]
  errors : Array[String]
} derive(Debug, Eq)

///|
pub fn import_entries_csv(csv : String) -> CsvImportResult {
  let entries : Array[Entry] = []
  let errors : Array[String] = []
  let mut row = 0
  for line_view in csv.split("\n") {
    let line = line_view.to_owned()
    if row == 0 {
      row += 1
      continue
    }
    if line.trim() == "" {
      row += 1
      continue
    }
    let fields : Array[String] = []
    for field in line.split(",") {
      fields.push(field.trim().to_owned())
    }
    if fields.length() != 6 {
      errors.push("row " + row.to_string() + ": expected 6 columns")
      row += 1
      continue
    }
    match parse_csv_entry(fields) {
      Some(entry) => entries.push(entry)
      None =>
        errors.push("row " + row.to_string() + ": invalid normalized entry")
    }
    row += 1
  }
  { entries, errors }
}

///|
fn parse_csv_entry(fields : Array[String]) -> Entry? {
  let debit = parse_amount(fields[2])
  let credit = parse_amount(fields[3])
  let cash = parse_bool(fields[4])
  match (debit, credit, cash) {
    (Some(debit), Some(credit), Some(cash)) => {
      let entry = Entry::new_with_dimension(
        fields[0],
        fields[1],
        debit,
        credit,
        fields[5],
        cash~,
      )
      if validate_entry(entry) is ValidEntry {
        Some(entry)
      } else {
        None
      }
    }
    _ => None
  }
}

///|
fn parse_amount(text : String) -> Amount? {
  if text == "" {
    return None
  }
  let mut sign = 1
  let mut start = 0
  if text[0] == '-' {
    sign = -1
    start = 1
  }
  if start == text.length() {
    return None
  }
  let mut value = 0
  for i in start.. '9' {
      return None
    }
    value = value * 10 + digit.to_int() - '0'.to_int()
  }
  Some(value * sign)
}

///|
fn parse_bool(text : String) -> Bool? {
  match text {
    "true" => Some(true)
    "false" => Some(false)
    _ => None
  }
}