use crate::base::serialize_date;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use crate::base::deserialize_date;
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)]
pub struct TakMarkerDetail {
pub status: Status,
#[serde(skip_serializing_if = "Option::is_none")]
pub link: Option<Link>,
pub contact: Contact,
#[serde(skip_serializing_if = "Option::is_none")]
pub remarks: Option<Remarks>,
#[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<Color>,
pub precisionlocation: PrecisionLocation,
#[serde(skip_serializing_if = "Option::is_none")]
pub usericon: Option<UserIcon>,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct Status {
#[serde(rename = "@readiness")]
pub readiness: bool,
}
impl Default for Status {
fn default() -> Self {
Status { readiness: true }
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct Link {
#[serde(rename = "@uid")]
uid: String,
#[serde(
rename = "@production_time",
serialize_with = "serialize_date",
deserialize_with = "deserialize_date"
)]
pub production_time: DateTime<Utc>,
#[serde(rename = "@type")]
pub cot_type: String,
#[serde(rename = "@parent_callsign")]
pub parent_callsign: String,
#[serde(rename = "@relation")]
pub relation: String,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct Contact {
#[serde(rename = "@callsign")]
pub callsign: String,
#[serde(rename = "@emailAddress", skip_serializing_if = "Option::is_none")]
pub email_address: Option<String>,
#[serde(rename = "@endpoint", skip_serializing_if = "Option::is_none")]
pub endpoint: Option<String>,
#[serde(rename = "@phone", skip_serializing_if = "Option::is_none")]
pub phone: Option<u32>,
#[serde(rename = "@xmppUsername", skip_serializing_if = "Option::is_none")]
pub xmpp_username: Option<String>,
}
impl Default for Contact {
fn default() -> Self {
Contact {
callsign: "???".to_string(),
email_address: None,
endpoint: None,
phone: None,
xmpp_username: None,
}
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct Remarks {
#[serde(rename = "$value")]
pub source: Option<Vec<String>>,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct Color {
#[serde(rename = "@argb")]
pub argb: i32,
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct PrecisionLocation {
#[serde(rename = "@altsrc")]
pub altsrc: String,
#[serde(rename = "@geopointsrc", skip_serializing_if = "Option::is_none")]
pub geopointsrc: Option<String>,
#[serde(
rename = "@PRECISE_IMAGE_FILE",
skip_serializing_if = "Option::is_none"
)]
pub pi_file: Option<String>,
#[serde(
rename = "@PRECISE_IMAGE_FILE_X",
skip_serializing_if = "Option::is_none"
)]
pub pi_file_x: Option<String>,
#[serde(
rename = "@PRECISE_IMAGE_FILE_Y",
skip_serializing_if = "Option::is_none"
)]
pub pi_file_y: Option<String>,
}
impl Default for PrecisionLocation {
fn default() -> Self {
Self {
altsrc: "???".to_string(),
geopointsrc: None,
pi_file: None,
pi_file_x: None,
pi_file_y: None,
}
}
}
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct UserIcon {
#[serde(rename = "@iconsetpath")]
iconsetpath: String,
}
#[cfg(test)]
mod test {
use crate::base::Cot;
use super::*;
#[test]
fn test_deserialize_tak_marker() {
let xml_path = format!(
"{}/src/tak/examples/marker-2525.cot",
env!("CARGO_MANIFEST_DIR")
);
let xml_text = std::fs::read_to_string(&xml_path).unwrap();
let marker: Cot<TakMarkerDetail> = quick_xml::de::from_str(&xml_text).unwrap();
assert_eq!(marker.version, "2.0");
}
}