use crate::error::Result;
use crate::types::{MeshCode, MeshLevel};
use alloc::format;
use alloc::string::ToString;
use alloc::vec::Vec;
pub fn parent(mesh: MeshCode) -> Option<MeshCode> {
let level = mesh.level();
let parent_level = level.parent()?;
let code_str = mesh.as_string();
let parent_len = parent_level.code_length();
let parent_code_str = &code_str[0..parent_len];
MeshCode::from_str(parent_code_str).ok()
}
pub fn children(mesh: MeshCode) -> Vec<MeshCode> {
let level = mesh.level();
let code_str = mesh.as_string();
match level {
MeshLevel::First => {
let mut result = Vec::with_capacity(64);
for t in 0..8 {
for u in 0..8 {
let child_str = format!("{code_str}{t}{u}");
if let Ok(child) = MeshCode::from_str(&child_str) {
result.push(child);
}
}
}
result
}
MeshLevel::Second => {
let mut result = Vec::with_capacity(100);
for v in 0..10 {
for w in 0..10 {
let child_str = format!("{code_str}{v}{w}");
if let Ok(child) = MeshCode::from_str(&child_str) {
result.push(child);
}
}
}
result
}
MeshLevel::Third => subdivision_children(&code_str, MeshLevel::FourthHalf),
MeshLevel::FourthHalf => subdivision_children(&code_str, MeshLevel::FourthQuarter),
MeshLevel::FourthQuarter => subdivision_children(&code_str, MeshLevel::FourthEighth),
MeshLevel::FourthEighth | MeshLevel::Fifth => Vec::new(),
}
}
fn subdivision_children(code_str: &str, child_level: MeshLevel) -> Vec<MeshCode> {
let mut result = Vec::with_capacity(4);
for i in 1..=4 {
let child_code = format!("{code_str}{i}").parse::<u64>().unwrap();
if let Ok(child) = MeshCode::new(child_level, child_code) {
result.push(child);
}
}
result
}
pub fn to_level(mesh: MeshCode, target_level: MeshLevel) -> Result<MeshCode> {
let current_level = mesh.level();
if current_level == target_level {
return Ok(mesh);
}
let mut level = current_level;
let is_ancestor = loop {
match level.parent() {
Some(parent) if parent == target_level => break true,
Some(parent) => level = parent,
None => break false,
}
};
if !is_ancestor {
return Err(crate::error::MeshCodeError::InvalidFormat(
"Target level is not an ancestor of the current level".to_string(),
));
}
let code_str = mesh.as_string();
let target_code_str = &code_str[0..target_level.code_length()];
MeshCode::from_str(target_code_str)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parent() {
let mesh = MeshCode::from_str("53393599").unwrap();
let parent_mesh = parent(mesh).unwrap();
assert_eq!(parent_mesh.as_string(), "533935");
assert_eq!(parent_mesh.level(), MeshLevel::Second);
let parent_mesh = parent(parent_mesh).unwrap();
assert_eq!(parent_mesh.as_string(), "5339");
assert_eq!(parent_mesh.level(), MeshLevel::First);
assert!(parent(parent_mesh).is_none());
}
#[test]
fn test_children_first() {
let mesh = MeshCode::from_str("5339").unwrap();
let children_list = children(mesh);
assert_eq!(children_list.len(), 64);
assert!(children_list.iter().all(|c| c.level() == MeshLevel::Second));
}
#[test]
fn test_children_second() {
let mesh = MeshCode::from_str("533935").unwrap();
let children_list = children(mesh);
assert_eq!(children_list.len(), 100);
assert!(children_list.iter().all(|c| c.level() == MeshLevel::Third));
}
#[test]
fn test_to_level() {
let mesh = MeshCode::from_str("53393599").unwrap();
let second = to_level(mesh, MeshLevel::Second).unwrap();
assert_eq!(second.as_string(), "533935");
let first = to_level(mesh, MeshLevel::First).unwrap();
assert_eq!(first.as_string(), "5339");
}
}