///|
pub(all) struct ZdaRecord {
  talker_value : String
  time_value : UtcTime
  date_value : UtcDate
  local_zone_hours_value : Int
  local_zone_minutes_value : Int
} derive(Eq, Debug)

///|
fn zda_error(message : String) -> NmeaError {
  NmeaError::from_diagnostic(
    Diagnostic::new(SentenceInvalid, Error, message, SourceRef::sentence(0)),
  )
}

///|
pub fn parse_zda(frame : NmeaFrame) -> Result[ZdaRecord, NmeaError] {
  if frame.formatter() != "ZDA" {
    return Err(zda_error("frame formatter is not ZDA"))
  }
  let cursor = FieldCursor::new(frame.fields())
  let time_text = match cursor.required(0) {
    Ok(value) => value
    Err(error) => return Err(error)
  }
  let time = match UtcTime::parse(time_text, SourceRef::field(0, 0)) {
    Ok(value) => value
    Err(error) => return Err(error)
  }
  let day = match cursor.integer(1, min=1, max=31) {
    Ok(value) => value
    Err(error) => return Err(error)
  }
  let month = match cursor.integer(2, min=1, max=12) {
    Ok(value) => value
    Err(error) => return Err(error)
  }
  let year = match cursor.integer(3, min=1900, max=9999) {
    Ok(value) => value
    Err(error) => return Err(error)
  }
  let date = match UtcDate::new(year, month, day, SourceRef::field(0, 1)) {
    Ok(value) => value
    Err(error) => return Err(error)
  }
  let zone_hours = match cursor.integer(4, min=-13, max=13) {
    Ok(value) => value
    Err(error) => return Err(error)
  }
  let zone_minutes = match cursor.integer(5, min=0, max=59) {
    Ok(value) => value
    Err(error) => return Err(error)
  }
  Ok({
    talker_value: frame.talker(),
    time_value: time,
    date_value: date,
    local_zone_hours_value: zone_hours,
    local_zone_minutes_value: zone_minutes,
  })
}

///|
pub fn ZdaRecord::time(self : ZdaRecord) -> UtcTime {
  self.time_value
}

///|
pub fn ZdaRecord::date(self : ZdaRecord) -> UtcDate {
  self.date_value
}

///|
pub fn ZdaRecord::local_zone_hours(self : ZdaRecord) -> Int {
  self.local_zone_hours_value
}

///|
pub fn ZdaRecord::local_zone_minutes(self : ZdaRecord) -> Int {
  self.local_zone_minutes_value
}

///|
pub fn ZdaRecord::encode(self : ZdaRecord) -> Result[String, NmeaError] {
  let fields = [
    utc_time_wire(self.time_value),
    pad2(self.date_value.day_value),
    pad2(self.date_value.month_value),
    self.date_value.year_value.to_string(),
    if self.local_zone_hours_value < 0 {
      "-" + pad2(-self.local_zone_hours_value)
    } else {
      pad2(self.local_zone_hours_value)
    },
    pad2(self.local_zone_minutes_value),
  ]
  Ok(NmeaFrame::new(36, self.talker_value, "ZDA", fields).encode())
}