#![allow(dead_code)]
use crate::paths;
use crate::sim::{EnvironmentSelector, RobotGenerator, RobotProfile};
use anyhow::Result;
use std::path::{Path, PathBuf};
pub struct SimulationService {
base_path: PathBuf,
}
impl SimulationService {
pub fn new() -> Self {
Self {
base_path: PathBuf::from(paths::project::SIMULATION_OUTPUT_DIR),
}
}
pub fn with_base_path(base_path: impl Into<PathBuf>) -> Self {
Self {
base_path: base_path.into(),
}
}
pub fn generate(
&self,
config_path: &Path,
output_path: &Path,
max_envs: usize,
min_score: i32,
) -> Result<GenerationResult> {
let profile = RobotProfile::from_config_file(config_path)?;
let robot_output = output_path.join("robot.tscn");
let robot_generator = RobotGenerator::from_config_file(config_path)?;
robot_generator.generate(&robot_output)?;
let selector = EnvironmentSelector::new()?;
let matches = selector.select_environments(&profile, max_envs)?;
let filtered_matches: Vec<_> = matches.into_iter().filter(|m| m.score >= min_score).collect();
if filtered_matches.is_empty() {
return Err(anyhow::anyhow!(
"No matching environments found (min score: {})",
min_score
));
}
let _catalog_path = PathBuf::from(paths::framework::ROBOT_TASKS_CATALOG);
let base_path = PathBuf::from(paths::framework::ROBOT_TASKS_DIR);
let mut available_count = 0;
for env_match in &filtered_matches {
let env_path = base_path.join(&env_match.environment.path);
if env_path.exists() {
available_count += 1;
}
}
Ok(GenerationResult {
robot_scene: robot_output,
environments: filtered_matches.iter().map(|m| m.environment.id.clone()).collect(),
available_count,
})
}
pub fn generate_robot(&self, config_path: &Path, output_path: &Path) -> Result<()> {
let robot_generator = RobotGenerator::from_config_file(config_path)?;
robot_generator.generate(output_path)
}
pub fn list_environments(&self, config_path: &Path, verbose: bool) -> Result<Vec<EnvironmentInfo>> {
let profile = RobotProfile::from_config_file(config_path)?;
let selector = EnvironmentSelector::new()?;
let matches = selector.select_environments(&profile, 100)?;
let base_path = PathBuf::from(paths::framework::ROBOT_TASKS_DIR);
let mut environments = Vec::new();
for env_match in matches {
let env_path = base_path.join(&env_match.environment.path);
let available = env_path.exists();
if verbose || available {
environments.push(EnvironmentInfo {
id: env_match.environment.id.clone(),
name: env_match.environment.name.clone(),
description: env_match.environment.description.clone(),
score: env_match.score,
available,
});
}
}
Ok(environments)
}
pub fn validate_config(&self, config_path: &Path) -> Result<ValidationResult> {
let profile = RobotProfile::from_config_file(config_path)?;
let mut errors = Vec::new();
let mut warnings = Vec::new();
if profile.platform.is_empty() {
errors.push("Platform not specified".to_string());
}
if profile.sensors.is_empty() {
warnings.push("No sensors configured".to_string());
}
if profile.task_nodes.is_empty() {
warnings.push("No task nodes configured".to_string());
}
let is_valid = errors.is_empty();
Ok(ValidationResult {
is_valid,
errors,
warnings,
platform: profile.platform,
sensor_count: profile.sensors.len(),
node_count: profile.task_nodes.len(),
})
}
pub fn is_setup(&self) -> bool {
self.base_path.exists() && self.base_path.join("robot.tscn").exists()
}
pub fn base_path(&self) -> &Path {
&self.base_path
}
}
impl Default for SimulationService {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub struct GenerationResult {
pub robot_scene: PathBuf,
pub environments: Vec<String>,
pub available_count: usize,
}
#[derive(Debug, Clone)]
pub struct EnvironmentInfo {
pub id: String,
pub name: String,
pub description: String,
pub score: i32,
pub available: bool,
}
#[derive(Debug)]
pub struct ValidationResult {
pub is_valid: bool,
pub errors: Vec<String>,
pub warnings: Vec<String>,
pub platform: String,
pub sensor_count: usize,
pub node_count: usize,
}