1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
//! This module contains types related to handling and processing metric commands during railway simulations.
//!
//! `MetricsCommand` is an enumeration of subcommands for working with metrics in the simulation.
//! It provides the `List` and `Get` subcommands to list available metrics and get a specific metric's value.
//!
//! This module integrates with the `Simulation` struct and the `MetricsHandler` trait to process and display metric information.

use crate::simulation::commands::SimulationCommand;
use crate::simulation::metrics::{ActionCountHandler, MetricsHandler, TargetReachedHandler};
use crate::simulation::Simulation;
use clap::Parser;

/// An enumeration of subcommands for working with metrics in the simulation.
#[derive(Parser, Debug)]
#[command(name = "metrics")]
pub enum MetricsCommand {
    /// Lists the names of all available metrics.
    #[command(name = "list")]
    List,

    /// Retrieves the value of a specific metric.
    #[command(name = "get")]
    Get(GetMetric),
}

/// A struct representing the `Get` subcommand for retrieving a specific metric's value.
#[derive(Parser, Debug)]
#[command(name = "get")]
pub struct GetMetric {
    /// The identifier of the metric to retrieve.
    #[clap(name = "ID")]
    pub metric_id: String,
}

/// Implements the `SimulationCommand` trait for the `MetricsCommand` enumeration.
impl SimulationCommand for MetricsCommand {
    /// Executes the metric command, either listing available metrics or getting a specific metric's value.
    ///
    /// # Returns
    ///
    /// An optional `String` containing the command's output.
    fn execute(&self, simulation: &mut Simulation) -> Option<String> {
        match self {
            MetricsCommand::List => {
                let metric_names = vec!["ActionCount", "TargetReached"];
                Some(format!("Available metrics: {:?}", metric_names))
            }
            MetricsCommand::Get(get_metric) => {
                let metric_value = match get_metric.metric_id.as_str() {
                    "ActionCount" => {
                        let handler = simulation.metrics_handlers.iter().find_map(|handler| {
                            handler.as_any().downcast_ref::<ActionCountHandler>()
                        });
                        handler.map(|h| h.get_value())
                    }
                    "TargetReached" => {
                        let handler = simulation.metrics_handlers.iter().find_map(|handler| {
                            handler.as_any().downcast_ref::<TargetReachedHandler>()
                        });
                        handler.map(|h| h.get_value())
                    }
                    _ => None,
                };

                if let Some(value) = metric_value {
                    Some(format!("{}: {}", get_metric.metric_id, value))
                } else {
                    Some(format!("Metric '{}' not found", get_metric.metric_id))
                }
            }
        }
    }
}