use geo::Rect;
use routers_tz_types::storage::s2cell::S2StorageBackend;
use s2::cellid::CellID;
use s2::latlng::LatLng;
use itertools::Itertools;
use crate::TimezoneResolver;
use routers_tz_types::TimeZone;
use std::fmt::Debug;
const MIN_LEVEL: u64 = 1;
const MAX_LEVEL: u64 = 13;
pub struct S2CellStorage {
backend: &'static S2StorageBackend,
}
impl Debug for S2CellStorage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("S2CellStorage")
}
}
impl Default for S2CellStorage {
fn default() -> Self {
S2CellStorage {
backend: crate::generated::s2cell::storage(),
}
}
}
impl S2CellStorage {}
impl TimezoneResolver for S2CellStorage {
type Error = ();
fn search(&self, rect: &Rect) -> Result<Vec<TimeZone>, Self::Error> {
let center = rect.center();
let ll = LatLng::from_degrees(center.y, center.x);
let leaf = CellID::from(&ll);
let timezones = (MIN_LEVEL..=MAX_LEVEL)
.rev()
.map(|level| leaf.parent(level).0)
.filter_map(
|ancestor| match self.backend.cell_ids.binary_search(&ancestor) {
Ok(pos) => Some(pos),
_ => None,
},
)
.unique()
.map(|pos| {
let tz_idx = self.backend.tz_indices[pos] as usize;
let tz = self.backend.names[tz_idx].tz();
TimeZone::new(tz)
})
.collect::<Vec<_>>();
match timezones[..] {
[] => Err(()),
_ => Ok(timezones),
}
}
}