use lazy_static::lazy_static;
use crate::core::auth0::UserDetails;
use std::str::FromStr;
lazy_static! {
static ref RE: regex::Regex = regex::Regex::new(r#"(\d+)\.(\d+)(e|E)([-]?)(\d+)"#).unwrap();
}
#[rustfmt::skip]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct LocationPo {
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<i64>,
#[serde(rename = "deviceId", skip_serializing_if = "Option::is_none")]
pub device_id: Option<String>,
#[serde(rename = "userId", skip_serializing_if = "Option::is_none")]
pub user_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub latitude: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub longitude: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub accuracy: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub altitude: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub speed: Option<String>,
#[serde(rename = "speedAccuracy", skip_serializing_if = "Option::is_none")]
pub speed_accuracy: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub heading: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub time: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tag: Option<String>,
}
#[rustfmt::skip]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct LocationRecord {
pub device_id: Option<String>,
pub location_id: Option<i64>,
pub user_id: Option<String>,
pub upload_user: Option<String>,
pub latitude: Option<String>,
pub longitude: Option<String>,
pub accuracy: Option<String>,
pub altitude: Option<String>,
pub speed: Option<String>,
pub speed_accuracy: Option<String>,
pub heading: Option<String>,
pub timestamp: Option<String>,
pub tag: Option<String>,
}
impl LocationRecord {
pub fn from(user: Option<&UserDetails>, data: &LocationPo) -> Self {
Self {
device_id: data.device_id.to_owned(),
location_id: data.id.to_owned(),
user_id: data.user_id.to_owned(),
upload_user: user.map(|u| u.user_id()),
latitude: Self::get_float_val(&data.latitude),
longitude: Self::get_float_val(&data.longitude),
accuracy: Self::get_float_val(&data.accuracy),
altitude: Self::get_float_val(&data.altitude),
heading: Self::get_float_val(&data.heading),
speed: Self::get_float_val(&data.speed),
speed_accuracy: Self::get_float_val(&data.speed_accuracy),
timestamp: data.time.to_owned(),
tag: data.tag.to_owned(),
}
}
fn get_float_val(val: &Option<String>) -> Option<String> {
match val {
Some(sci_str) => match bigdecimal::BigDecimal::from_str(sci_str) {
Ok(d) => {
if let Some(captures) = RE.captures(sci_str) {
let n1 = captures.get(1).unwrap().as_str();
let n2 = captures.get(2).unwrap().as_str();
let _n3 = captures.get(3).unwrap().as_str();
let _n4 = captures.get(4).unwrap().as_str();
let n5 = captures.get(5).unwrap().as_str();
let n = crate::commons::string_to_number::<usize>(n5).unwrap();
let s = format!("0.{}{}{}", "0".repeat(n - 1), n1, n2);
Some(s)
} else {
Some(d.to_string())
}
}
Err(e) => {
log::error!("get_float_val-Failed: val={}, err={:?}", sci_str, e);
None
}
},
None => None,
}
}
}