use serde_json::{json, Value};
use std::collections::HashMap;
use crate::models::CorticalArea;
use feagi_structures::genomic::BrainRegion;
use crate::types::{BduError, BduResult};
pub struct GenomeSaver;
impl GenomeSaver {
pub fn save_to_json(
cortical_areas: &HashMap<String, CorticalArea>,
brain_regions: &HashMap<String, (BrainRegion, Option<String>)>,
genome_id: Option<String>,
genome_title: Option<String>,
) -> BduResult<String> {
let mut blueprint = serde_json::Map::new();
for (cortical_id, area) in cortical_areas {
let mut area_data = serde_json::Map::new();
area_data.insert("cortical_name".to_string(), json!(area.name));
area_data.insert("block_boundaries".to_string(), json!([
area.dimensions.width,
area.dimensions.height,
area.dimensions.depth
]));
area_data.insert("relative_coordinate".to_string(), json!([
area.position.0,
area.position.1,
area.position.2
]));
let cortical_type = match area.cortical_type {
crate::models::cortical_area::CorticalAreaType::Sensory => "IPU",
crate::models::cortical_area::CorticalAreaType::Motor => "OPU",
crate::models::cortical_area::CorticalAreaType::Memory => "MEMORY",
crate::models::cortical_area::CorticalAreaType::Custom => "CUSTOM",
};
area_data.insert("cortical_type".to_string(), json!(cortical_type));
for (key, value) in &area.properties {
area_data.insert(key.clone(), value.clone());
}
blueprint.insert(cortical_id.clone(), Value::Object(area_data));
}
let mut regions_map = serde_json::Map::new();
for (region_id, (region, parent_id)) in brain_regions {
let mut region_data = serde_json::Map::new();
region_data.insert("title".to_string(), json!(region.name));
region_data.insert("parent_region_id".to_string(),
if let Some(ref parent) = parent_id {
json!(parent)
} else {
Value::Null
}
);
let areas: Vec<String> = region.cortical_areas.iter().cloned().collect();
region_data.insert("areas".to_string(), json!(areas));
region_data.insert("regions".to_string(), json!(Vec::<String>::new()));
for (key, value) in ®ion.properties {
region_data.insert(key.clone(), value.clone());
}
regions_map.insert(region_id.clone(), Value::Object(region_data));
}
let genome = json!({
"genome_id": genome_id.unwrap_or_else(||
format!("genome_{}", chrono::Utc::now().timestamp())
),
"genome_title": genome_title.unwrap_or_else(|| "Exported Genome".to_string()),
"version": "2.1",
"blueprint": blueprint,
"brain_regions": regions_map,
"neuron_morphologies": {},
"physiology": {}
});
serde_json::to_string_pretty(&genome)
.map_err(|e| BduError::Internal(format!("Failed to serialize genome: {}", e)))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::models::cortical_area::AreaType;
use feagi_structures::genomic::RegionType;
use crate::types::Dimensions;
#[test]
fn test_save_minimal_genome() {
let mut cortical_areas = HashMap::new();
let mut brain_regions = HashMap::new();
let cortical_id = CoreCorticalType::Power.to_cortical_id();
let area = CorticalArea::new(
cortical_id.clone(),
0,
"Test Area".to_string(),
CorticalAreaDimensions::new(10, 10, 10).unwrap(),
(0, 0, 0),
CorticalAreaType::Sensory,
).unwrap();
cortical_areas.insert("test01".to_string(), area);
let region = BrainRegion::new(
"root".to_string(),
"Root".to_string(),
RegionType::Undefined,
).unwrap();
brain_regions.insert("root".to_string(), (region, None));
let json = GenomeSaver::save_to_json(
&cortical_areas,
&brain_regions,
Some("test-001".to_string()),
Some("Test Genome".to_string()),
).unwrap();
let parsed: Value = serde_json::from_str(&json).unwrap();
assert_eq!(parsed["genome_id"], "test-001");
assert_eq!(parsed["genome_title"], "Test Genome");
assert_eq!(parsed["version"], "2.1");
assert!(parsed["blueprint"].is_object());
assert!(parsed["brain_regions"].is_object());
}
#[test]
fn test_roundtrip() {
use crate::genome::GenomeParser;
let mut cortical_areas = HashMap::new();
let cortical_id = CoreCorticalType::Power.to_cortical_id();
let area = CorticalArea::new(
cortical_id.clone(),
0,
"Test Area".to_string(),
CorticalAreaDimensions::new(10, 10, 10).unwrap(),
(5, 5, 5),
CorticalAreaType::Motor,
).unwrap();
cortical_areas.insert(cortical_id, area);
let mut brain_regions = HashMap::new();
let region = BrainRegion::new(
"root".to_string(),
"Root Region".to_string(),
RegionType::Undefined,
).unwrap();
brain_regions.insert("root".to_string(), (region, None));
let json = GenomeSaver::save_to_json(
&cortical_areas,
&brain_regions,
Some("test-roundtrip".to_string()),
Some("Roundtrip Test".to_string()),
).unwrap();
let parsed = GenomeParser::parse(&json).unwrap();
assert_eq!(parsed.genome_id, "test-roundtrip");
assert_eq!(parsed.genome_title, "Roundtrip Test");
assert_eq!(parsed.cortical_areas.len(), 1);
assert_eq!(parsed.brain_regions.len(), 1);
let area = &parsed.cortical_areas[0];
assert_eq!(area.cortical_id, "test01");
assert_eq!(area.name, "Test Area");
assert_eq!(area.dimensions.width, 10);
assert_eq!(area.position, (5, 5, 5));
}
}