use std::str::FromStr;
use hifitime::Epoch;
use serde::{Deserialize, Deserializer};
use crate::TrajId;
#[derive(Debug, Deserialize)]
pub(crate) struct StructuredAdes {
#[serde(rename = "obsBlock")]
pub(crate) obs_blocks: Vec<ObsBlock>,
}
#[derive(Debug, Deserialize)]
pub(crate) struct FlatAdes {
#[serde(rename = "optical")]
pub(crate) opticals: Vec<OpticalObs>,
}
#[derive(Debug, Deserialize)]
pub(crate) struct ObsBlock {
#[serde(rename = "obsContext")]
pub(crate) obs_context: ObsContext,
#[serde(rename = "obsData")]
pub(crate) obs_data: ObsData,
}
#[derive(Debug, Deserialize)]
pub(crate) struct ObsContext {
pub(crate) observatory: Observatory,
}
#[derive(Debug, Deserialize)]
pub(crate) struct Observatory {
#[serde(rename = "mpcCode")]
pub(crate) mpc_code: String,
}
#[derive(Debug, Deserialize)]
pub(crate) struct ObsData {
#[serde(rename = "optical")]
pub(crate) opticals: Vec<OpticalObs>,
}
#[derive(Debug, Deserialize)]
pub(crate) struct OpticalObs {
#[serde(rename = "permID")]
pub(crate) perm_id: Option<String>,
#[serde(rename = "provID")]
pub(crate) prov_id: Option<String>,
#[serde(rename = "trkSub")]
pub(crate) trk_sub: Option<String>,
#[serde(rename = "obsTime", deserialize_with = "deserialize_mjd_tt")]
pub(crate) obs_time: f64,
pub(crate) ra: f64,
pub(crate) dec: f64,
#[serde(rename = "precRA")]
pub(crate) prec_ra: Option<f64>,
#[serde(rename = "precDec")]
pub(crate) prec_dec: Option<f64>,
#[serde(rename = "rmsRA")]
pub(crate) rms_ra: Option<f64>,
#[serde(rename = "rmsDec")]
pub(crate) rms_dec: Option<f64>,
pub(crate) stn: String,
pub(crate) mag: Option<f64>,
#[serde(rename = "rmsMag")]
pub(crate) rms_mag: Option<f64>,
pub(crate) band: Option<String>,
}
impl OpticalObs {
pub(crate) fn traj_id(&self) -> Option<TrajId> {
let id = self
.perm_id
.clone()
.or_else(|| self.prov_id.clone())
.or_else(|| self.trk_sub.clone())?;
if let Ok(n) = id.parse::<u32>() {
Some(TrajId::Int(n))
} else {
Some(TrajId::Str(id))
}
}
pub(crate) fn ra_error_arcsec(&self, fallback: Option<f64>) -> Option<f64> {
self.rms_ra.or(self.prec_ra).or(fallback)
}
pub(crate) fn dec_error_arcsec(&self, fallback: Option<f64>) -> Option<f64> {
self.rms_dec.or(self.prec_dec).or(fallback)
}
pub(crate) fn mpc_code_bytes(&self) -> [u8; 3] {
let bytes = self.stn.as_bytes();
let mut code = [b' '; 3];
let len = bytes.len().min(3);
code[..len].copy_from_slice(&bytes[..len]);
code
}
}
fn deserialize_mjd_tt<'de, D>(deserializer: D) -> Result<f64, D::Error>
where
D: Deserializer<'de>,
{
let date_str = String::deserialize(deserializer)?;
let epoch = Epoch::from_str(&date_str).map_err(serde::de::Error::custom)?;
Ok(epoch.to_mjd_tt_days())
}