///|
pub(all) struct RawRecord {
  frame_value : NmeaFrame
} derive(Eq, Debug)

///|
pub(all) enum NmeaRecord {
  GgaRecordValue(GgaRecord)
  RmcRecordValue(RmcRecord)
  GsaRecordValue(GsaRecord)
  GsvRecordValue(GsvRecord)
  VtgRecordValue(VtgRecord)
  ZdaRecordValue(ZdaRecord)
  GllRecordValue(GllRecord)
  RawRecordValue(RawRecord)
} derive(Eq, Debug)

///|
pub fn parse_record(frame : NmeaFrame) -> Result[NmeaRecord, NmeaError] {
  match frame.formatter() {
    "GGA" =>
      match parse_gga(frame) {
        Ok(value) => Ok(GgaRecordValue(value))
        Err(error) => Err(error)
      }
    "RMC" =>
      match parse_rmc(frame) {
        Ok(value) => Ok(RmcRecordValue(value))
        Err(error) => Err(error)
      }
    "GSA" =>
      match parse_gsa(frame) {
        Ok(value) => Ok(GsaRecordValue(value))
        Err(error) => Err(error)
      }
    "GSV" =>
      match parse_gsv(frame) {
        Ok(value) => Ok(GsvRecordValue(value))
        Err(error) => Err(error)
      }
    "VTG" =>
      match parse_vtg(frame) {
        Ok(value) => Ok(VtgRecordValue(value))
        Err(error) => Err(error)
      }
    "ZDA" =>
      match parse_zda(frame) {
        Ok(value) => Ok(ZdaRecordValue(value))
        Err(error) => Err(error)
      }
    "GLL" =>
      match parse_gll(frame) {
        Ok(value) => Ok(GllRecordValue(value))
        Err(error) => Err(error)
      }
    _ => Ok(RawRecordValue({ frame_value: frame }))
  }
}

///|
pub fn parse_sentence(
  input : String,
  policy? : ParsePolicy = Strict,
  limits? : FrameLimits = FrameLimits::standard(),
) -> Result[NmeaRecord, NmeaError] {
  match parse_frame(input, policy~, limits~) {
    Ok(frame) => parse_record(frame)
    Err(error) => Err(error)
  }
}

///|
pub fn NmeaRecord::formatter(self : NmeaRecord) -> String {
  match self {
    GgaRecordValue(_) => "GGA"
    RmcRecordValue(_) => "RMC"
    GsaRecordValue(_) => "GSA"
    GsvRecordValue(_) => "GSV"
    VtgRecordValue(_) => "VTG"
    ZdaRecordValue(_) => "ZDA"
    GllRecordValue(_) => "GLL"
    RawRecordValue(raw) => raw.frame_value.formatter()
  }
}

///|
pub fn NmeaRecord::talker(self : NmeaRecord) -> String {
  match self {
    GgaRecordValue(value) => value.talker_value
    RmcRecordValue(value) => value.talker_value
    GsaRecordValue(value) => value.talker_value
    GsvRecordValue(value) => value.talker_value
    VtgRecordValue(value) => value.talker_value
    ZdaRecordValue(value) => value.talker_value
    GllRecordValue(value) => value.talker_value
    RawRecordValue(raw) => raw.frame_value.talker()
  }
}

///|
pub fn RawRecord::frame(self : RawRecord) -> NmeaFrame {
  self.frame_value
}

///|
pub fn NmeaRecord::encode(self : NmeaRecord) -> Result[String, NmeaError] {
  match self {
    GgaRecordValue(value) => value.encode()
    RmcRecordValue(value) => value.encode()
    GsaRecordValue(value) => value.encode()
    GsvRecordValue(value) => value.encode()
    VtgRecordValue(value) => value.encode()
    ZdaRecordValue(value) => value.encode()
    GllRecordValue(value) => value.encode()
    RawRecordValue(raw) => Ok(raw.frame_value.encode())
  }
}