use arinc424::fields;
use arinc424::fields::LowerUpperLimit;
use crate::measurements::Angle;
use crate::nd::*;
use crate::MagneticVariation;
use crate::VerticalDistance;
use geo::Point;
impl<'a> TryFrom<fields::Cycle<'a>> for AiracCycle {
type Error = arinc424::Error;
fn try_from(value: fields::Cycle) -> Result<Self, Self::Error> {
Ok(AiracCycle::new(value.year()?, value.cycle()?))
}
}
impl From<fields::ArspType> for AirspaceType {
fn from(value: fields::ArspType) -> Self {
match value {
fields::ArspType::ClassC => Self::TMA,
fields::ArspType::ControlArea => Self::CTA,
fields::ArspType::TerminalControlArea => Self::TMA,
fields::ArspType::RadarZone => Self::RadarZone,
fields::ArspType::ClassB => Self::TMA,
fields::ArspType::RadioMandatoryZone => Self::RMZ,
fields::ArspType::TransponderMandatoryZone => Self::TMZ,
fields::ArspType::ControlZone => Self::CTR,
}
}
}
pub fn parse_classification(
arsp_type: fields::ArspType,
arsp_class: Option<&fields::AirspaceClassification<'_>>,
) -> Option<AirspaceClassification> {
if let Some(class) = arsp_class {
match class.as_bytes()[0] {
b'A' => return Some(AirspaceClassification::A),
b'B' => return Some(AirspaceClassification::B),
b'C' => return Some(AirspaceClassification::C),
b'D' => return Some(AirspaceClassification::D),
b'E' => return Some(AirspaceClassification::E),
b'F' => return Some(AirspaceClassification::F),
b'G' => return Some(AirspaceClassification::G),
_ => {}
}
}
match arsp_type {
fields::ArspType::ClassB => Some(AirspaceClassification::B),
fields::ArspType::ClassC => Some(AirspaceClassification::C),
_ => None,
}
}
impl From<fields::RestrictiveType> for AirspaceType {
fn from(value: fields::RestrictiveType) -> Self {
match value {
fields::RestrictiveType::Danger => Self::Danger,
fields::RestrictiveType::Prohibited => Self::Prohibited,
fields::RestrictiveType::Restricted
| fields::RestrictiveType::Alert
| fields::RestrictiveType::Caution
| fields::RestrictiveType::LongTermTFR
| fields::RestrictiveType::MOA
| fields::RestrictiveType::NationalSecurityArea
| fields::RestrictiveType::Training
| fields::RestrictiveType::Warning
| fields::RestrictiveType::UnspecifiedOrUnknown => Self::Restricted,
}
}
}
impl<'a> TryFrom<fields::IcaoCode<'a>> for LocationIndicator {
type Error = arinc424::Error;
fn try_from(value: fields::IcaoCode<'a>) -> Result<Self, Self::Error> {
LocationIndicator::try_from(value.as_str()).map_err(|_| arinc424::Error::InvalidVariant {
field: "IcaoCode",
bytes: value.as_bytes().to_vec(),
expected: "valid location identifier",
})
}
}
pub fn lat_lon_to_point<'a>(
lat: fields::Latitude<'a>,
lon: fields::Longitude<'a>,
) -> Result<Point<f64>, arinc424::Error> {
Ok(Point::new(lon.as_decimal()?, lat.as_decimal()?))
}
impl From<fields::MagVar> for MagneticVariation {
fn from(value: fields::MagVar) -> Self {
match value {
fields::MagVar::East(d) => Self::East(d),
fields::MagVar::West(d) => Self::West(d),
fields::MagVar::OrientedToTrueNorth => Self::OrientedToTrueNorth,
}
}
}
impl<'a> From<fields::RegnCode<'a>> for Region {
fn from(value: fields::RegnCode) -> Self {
match value.as_str() {
"ENRT" => Self::Enroute,
icao => Self::TerminalArea(
icao.as_bytes()
.try_into()
.expect("ICAO should be 4 character"),
),
}
}
}
impl From<fields::RwyBrg> for Angle {
fn from(rwy_brg: fields::RwyBrg) -> Self {
match rwy_brg {
fields::RwyBrg::MagneticNorth(degree) => Self::m(degree),
fields::RwyBrg::TrueNorth(degree) => Self::t(degree as f32),
}
}
}
impl From<fields::LowerUpperLimit> for VerticalDistance {
fn from(value: LowerUpperLimit) -> Self {
match value {
LowerUpperLimit::Altitude(alt) => VerticalDistance::Altitude(alt as u16),
LowerUpperLimit::FlightLevel(fl) => VerticalDistance::Fl(fl),
LowerUpperLimit::NotSpecified => VerticalDistance::Unlimited,
LowerUpperLimit::Unlimited => VerticalDistance::Unlimited,
LowerUpperLimit::Ground => VerticalDistance::Gnd,
LowerUpperLimit::MeanSeaLevel => VerticalDistance::Msl(0),
LowerUpperLimit::NOTAM => VerticalDistance::Unlimited,
}
}
}