///|
/// A MARC subfield.
pub(all) struct Subfield {
  code : Char
  value : String
} derive(Eq, Debug)

///|
/// A MARC control or data field.
pub(all) enum MarcField {
  ControlField(tag~ : String, value~ : String)
  DataField(
    tag~ : String,
    indicator1~ : Char,
    indicator2~ : Char,
    subfields~ : Array[Subfield]
  )
} derive(Eq, Debug)

///|
/// A parsed MARC 21 record.
pub(all) struct MarcRecord {
  leader : @leader.Leader
  fields : Array[MarcField]
} derive(Eq, Debug)

///|
pub fn MarcRecord::leader(self : MarcRecord) -> @leader.Leader {
  self.leader
}

///|
pub fn MarcRecord::fields(self : MarcRecord) -> Array[MarcField] {
  self.fields
}

///|
pub fn MarcField::tag(self : MarcField) -> String {
  match self {
    ControlField(tag~, ..) => tag
    DataField(tag~, ..) => tag
  }
}

///|
pub fn MarcField::value(self : MarcField) -> String {
  match self {
    ControlField(value~, ..) => value
    DataField(subfields~, ..) => {
      let mut output = ""
      for subfield in subfields {
        if output.is_empty() {
          output = subfield.value
        } else {
          output = output + " " + subfield.value
        }
      }
      output
    }
  }
}

///|
pub fn MarcRecord::fields_by_tag(
  self : MarcRecord,
  tag : String,
) -> Array[MarcField] {
  let result : Array[MarcField] = []
  for field in self.fields {
    if field.tag() == tag {
      result.push(field)
    }
  }
  result
}

///|
pub fn MarcRecord::first_subfield(
  self : MarcRecord,
  tag : String,
  code : Char,
) -> String? {
  for field in self.fields {
    match field {
      DataField(tag=field_tag, subfields~, ..) if field_tag == tag =>
        for subfield in subfields {
          if subfield.code == code {
            return Some(subfield.value)
          }
        }
      _ => ()
    }
  }
  None
}

///|
pub fn MarcRecord::title(self : MarcRecord) -> String? {
  self.first_subfield("245", 'a')
}

///|
pub fn MarcRecord::control_number(self : MarcRecord) -> String? {
  for field in self.fields {
    match field {
      ControlField(tag="001", value~) => return Some(value)
      _ => ()
    }
  }
  None
}

///|
/// Return every value of a subfield across all matching fields.
pub fn MarcRecord::subfields(
  self : MarcRecord,
  tag : String,
  code : Char,
) -> Array[String] {
  let result : Array[String] = []
  for field in self.fields {
    match field {
      DataField(tag=field_tag, subfields~, ..) if field_tag == tag =>
        for subfield in subfields {
          if subfield.code == code {
            result.push(subfield.value)
          }
        }
      _ => ()
    }
  }
  result
}

///|
pub fn MarcRecord::isbn_list(self : MarcRecord) -> Array[String] {
  self.subfields("020", 'a')
}

///|
pub fn MarcRecord::subtitle(self : MarcRecord) -> String? {
  self.first_subfield("245", 'b')
}

///|
pub fn MarcRecord::primary_author(self : MarcRecord) -> String? {
  self.first_subfield("100", 'a')
}

///|
pub fn MarcRecord::other_authors(self : MarcRecord) -> Array[String] {
  self.subfields("700", 'a')
}

///|
pub fn MarcRecord::publisher(self : MarcRecord) -> String? {
  self.first_subfield("264", 'b')
}

///|
pub fn MarcRecord::publication_year(self : MarcRecord) -> String? {
  self.first_subfield("264", 'c')
}

///|
pub fn MarcRecord::languages(self : MarcRecord) -> Array[String] {
  self.subfields("041", 'a')
}

///|
pub fn MarcRecord::subjects(self : MarcRecord) -> Array[String] {
  self.subfields("650", 'a')
}

///|
pub fn MarcRecord::summary(self : MarcRecord) -> String? {
  self.first_subfield("520", 'a')
}