use std::collections::HashMap;
use crate::app_state::{AppState, ConnectionStatus, SortCriteria, SortDirection};
use crate::device::{ChassisInfo, CpuInfo, GpuInfo, MemoryInfo, ProcessInfo};
use crate::storage::info::StorageInfo;
use crate::ui::notification::NotificationManager;
use crate::utils::RuntimeEnvironment;
#[derive(Clone, Debug)]
pub struct RenderDecisions {
pub force_clear: bool,
#[allow(dead_code)] pub should_render: bool,
#[allow(dead_code)] pub animations_needed: bool,
}
#[derive(Clone)]
pub struct RenderSnapshot {
pub show_help: bool,
pub loading: bool,
pub is_local_mode: bool,
pub show_per_core_cpu: bool,
pub gpu_filter_enabled: bool,
pub tabs: Vec<String>,
pub current_tab: usize,
pub tab_scroll_offset: usize,
pub gpu_scroll_offset: usize,
pub storage_scroll_offset: usize,
pub selected_process_index: usize,
pub start_index: usize,
pub process_horizontal_scroll_offset: usize,
pub device_name_scroll_offsets: HashMap<String, usize>,
pub host_id_scroll_offsets: HashMap<String, usize>,
pub cpu_name_scroll_offsets: HashMap<String, usize>,
pub frame_counter: u64,
pub sort_criteria: SortCriteria,
pub sort_direction: SortDirection,
pub gpu_info: Vec<GpuInfo>,
pub cpu_info: Vec<CpuInfo>,
pub memory_info: Vec<MemoryInfo>,
pub process_info: Vec<ProcessInfo>,
pub chassis_info: Vec<ChassisInfo>,
pub storage_info: Vec<StorageInfo>,
pub connection_status: HashMap<String, ConnectionStatus>,
pub hostname_to_host_id: HashMap<String, String>,
pub runtime_environment: RuntimeEnvironment,
pub utilization_history: Vec<f64>,
pub memory_history: Vec<f64>,
pub temperature_history: Vec<f64>,
pub cpu_utilization_history: Vec<f64>,
pub system_memory_history: Vec<f64>,
pub cpu_temperature_history: Vec<f64>,
pub notifications: NotificationManager,
pub startup_status_lines: Vec<String>,
pub data_version: u64,
}
impl RenderSnapshot {
pub fn capture(state: &AppState) -> Self {
Self {
show_help: state.show_help,
loading: state.loading,
is_local_mode: state.is_local_mode,
show_per_core_cpu: state.show_per_core_cpu,
gpu_filter_enabled: state.gpu_filter_enabled,
tabs: state.tabs.clone(),
current_tab: state.current_tab,
tab_scroll_offset: state.tab_scroll_offset,
gpu_scroll_offset: state.gpu_scroll_offset,
storage_scroll_offset: state.storage_scroll_offset,
selected_process_index: state.selected_process_index,
start_index: state.start_index,
process_horizontal_scroll_offset: state.process_horizontal_scroll_offset,
device_name_scroll_offsets: state.device_name_scroll_offsets.clone(),
host_id_scroll_offsets: state.host_id_scroll_offsets.clone(),
cpu_name_scroll_offsets: state.cpu_name_scroll_offsets.clone(),
frame_counter: state.frame_counter,
sort_criteria: state.sort_criteria,
sort_direction: state.sort_direction,
gpu_info: state.gpu_info.clone(),
cpu_info: state.cpu_info.clone(),
memory_info: state.memory_info.clone(),
process_info: state.process_info.clone(),
chassis_info: state.chassis_info.clone(),
storage_info: state.storage_info.clone(),
connection_status: state.connection_status.clone(),
hostname_to_host_id: state.hostname_to_host_id.clone(),
runtime_environment: state.runtime_environment.clone(),
utilization_history: state.utilization_history.iter().copied().collect(),
memory_history: state.memory_history.iter().copied().collect(),
temperature_history: state.temperature_history.iter().copied().collect(),
cpu_utilization_history: state.cpu_utilization_history.iter().copied().collect(),
system_memory_history: state.system_memory_history.iter().copied().collect(),
cpu_temperature_history: state.cpu_temperature_history.iter().copied().collect(),
notifications: state.notifications.clone(),
startup_status_lines: state.startup_status_lines.clone(),
data_version: state.data_version,
}
}
pub fn as_app_state(&self) -> AppState {
let mut state = AppState::new();
state.show_help = self.show_help;
state.loading = self.loading;
state.is_local_mode = self.is_local_mode;
state.show_per_core_cpu = self.show_per_core_cpu;
state.gpu_filter_enabled = self.gpu_filter_enabled;
state.tabs = self.tabs.clone();
state.current_tab = self.current_tab;
state.tab_scroll_offset = self.tab_scroll_offset;
state.gpu_scroll_offset = self.gpu_scroll_offset;
state.storage_scroll_offset = self.storage_scroll_offset;
state.selected_process_index = self.selected_process_index;
state.start_index = self.start_index;
state.process_horizontal_scroll_offset = self.process_horizontal_scroll_offset;
state.device_name_scroll_offsets = self.device_name_scroll_offsets.clone();
state.host_id_scroll_offsets = self.host_id_scroll_offsets.clone();
state.cpu_name_scroll_offsets = self.cpu_name_scroll_offsets.clone();
state.frame_counter = self.frame_counter;
state.sort_criteria = self.sort_criteria;
state.sort_direction = self.sort_direction;
state.gpu_info = self.gpu_info.clone();
state.cpu_info = self.cpu_info.clone();
state.memory_info = self.memory_info.clone();
state.process_info = self.process_info.clone();
state.chassis_info = self.chassis_info.clone();
state.storage_info = self.storage_info.clone();
state.connection_status = self.connection_status.clone();
state.hostname_to_host_id = self.hostname_to_host_id.clone();
state.runtime_environment = self.runtime_environment.clone();
state.utilization_history = self.utilization_history.iter().copied().collect();
state.memory_history = self.memory_history.iter().copied().collect();
state.temperature_history = self.temperature_history.iter().copied().collect();
state.cpu_utilization_history = self.cpu_utilization_history.iter().copied().collect();
state.system_memory_history = self.system_memory_history.iter().copied().collect();
state.cpu_temperature_history = self.cpu_temperature_history.iter().copied().collect();
state.notifications = self.notifications.clone();
state.startup_status_lines = self.startup_status_lines.clone();
state.data_version = self.data_version;
state
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_snapshot_capture_preserves_flags() {
let mut state = AppState::new();
state.show_help = true;
state.loading = false;
state.is_local_mode = true;
state.show_per_core_cpu = true;
state.gpu_filter_enabled = true;
let snapshot = RenderSnapshot::capture(&state);
assert!(snapshot.show_help);
assert!(!snapshot.loading);
assert!(snapshot.is_local_mode);
assert!(snapshot.show_per_core_cpu);
assert!(snapshot.gpu_filter_enabled);
}
#[test]
fn test_snapshot_capture_preserves_tab_state() {
let mut state = AppState::new();
state.tabs = vec!["All".to_string(), "Node1".to_string(), "Node2".to_string()];
state.current_tab = 1;
state.tab_scroll_offset = 0;
let snapshot = RenderSnapshot::capture(&state);
assert_eq!(snapshot.tabs.len(), 3);
assert_eq!(snapshot.current_tab, 1);
assert_eq!(snapshot.tabs[1], "Node1");
}
#[test]
fn test_snapshot_capture_preserves_scroll_state() {
let mut state = AppState::new();
state.gpu_scroll_offset = 5;
state.storage_scroll_offset = 3;
state.selected_process_index = 10;
state.process_horizontal_scroll_offset = 20;
let snapshot = RenderSnapshot::capture(&state);
assert_eq!(snapshot.gpu_scroll_offset, 5);
assert_eq!(snapshot.storage_scroll_offset, 3);
assert_eq!(snapshot.selected_process_index, 10);
assert_eq!(snapshot.process_horizontal_scroll_offset, 20);
}
#[test]
fn test_snapshot_capture_preserves_sort_state() {
let mut state = AppState::new();
state.sort_criteria = SortCriteria::Utilization;
state.sort_direction = SortDirection::Ascending;
let snapshot = RenderSnapshot::capture(&state);
assert_eq!(snapshot.sort_criteria, SortCriteria::Utilization);
assert_eq!(snapshot.sort_direction, SortDirection::Ascending);
}
#[test]
fn test_snapshot_capture_preserves_data_version() {
let mut state = AppState::new();
state.mark_data_changed();
state.mark_data_changed();
let snapshot = RenderSnapshot::capture(&state);
assert_eq!(snapshot.data_version, 2);
}
#[test]
fn test_snapshot_capture_converts_history_from_vecdeque() {
let mut state = AppState::new();
state.utilization_history.push_back(50.0);
state.utilization_history.push_back(75.0);
state.memory_history.push_back(40.0);
let snapshot = RenderSnapshot::capture(&state);
assert_eq!(snapshot.utilization_history, vec![50.0, 75.0]);
assert_eq!(snapshot.memory_history, vec![40.0]);
}
#[test]
fn test_snapshot_is_independent_of_source_state() {
let mut state = AppState::new();
state.current_tab = 0;
state.gpu_scroll_offset = 5;
let snapshot = RenderSnapshot::capture(&state);
state.current_tab = 2;
state.gpu_scroll_offset = 99;
assert_eq!(snapshot.current_tab, 0);
assert_eq!(snapshot.gpu_scroll_offset, 5);
}
#[test]
fn test_as_app_state_roundtrip() {
let mut state = AppState::new();
state.show_help = true;
state.current_tab = 2;
state.gpu_scroll_offset = 10;
state.sort_criteria = SortCriteria::GpuMemory;
state.data_version = 42;
state.utilization_history.push_back(60.0);
let snapshot = RenderSnapshot::capture(&state);
let restored = snapshot.as_app_state();
assert!(restored.show_help);
assert_eq!(restored.current_tab, 2);
assert_eq!(restored.gpu_scroll_offset, 10);
assert_eq!(restored.sort_criteria, SortCriteria::GpuMemory);
assert_eq!(restored.data_version, 42);
assert_eq!(restored.utilization_history.len(), 1);
}
}