use eframe::egui;
use std::sync::Arc;
use tokio::sync::{broadcast, RwLock};
use chrono::Utc;
use crate::config::Config;
use crate::sensors::{SensorManager, SensorReading, SensorType};
use crate::detection::{Detection, DetectionType, Severity};
use super::{GuiState, SystemStats, ThermalData, SpectrumData};
use super::panels::*;
use super::widgets::*;
use super::theme::*;
pub struct GlowBarnApp {
config: Config,
state: GuiState,
sensor_panel: SensorPanel,
waveform_panel: WaveformPanel,
thermal_panel: ThermalPanel,
spectrum_panel: SpectrumPanel,
detection_panel: DetectionPanel,
stats_panel: StatsPanel,
demo_mode: bool,
frame_count: u64,
last_update: std::time::Instant,
}
impl GlowBarnApp {
pub fn new(cc: &eframe::CreationContext<'_>, config: Config) -> Self {
let demo_mode = config.demo_mode;
Self {
config,
state: GuiState::default(),
sensor_panel: SensorPanel::new(),
waveform_panel: WaveformPanel::new(),
thermal_panel: ThermalPanel::new(),
spectrum_panel: SpectrumPanel::new(),
detection_panel: DetectionPanel::new(),
stats_panel: StatsPanel::new(),
demo_mode,
frame_count: 0,
last_update: std::time::Instant::now(),
}
}
fn update_demo_data(&mut self) {
let t = self.frame_count as f64 * 0.05;
for sensor_id in ["EMF-001", "Thermal-001", "Audio-001", "Seismic-001"] {
let waveform = self.state.waveforms
.entry(sensor_id.to_string())
.or_insert_with(Vec::new);
let value = match sensor_id {
"EMF-001" => (t * 0.3).sin() * 50.0 + 100.0 + (t * 2.1).sin() * 10.0,
"Thermal-001" => 22.0 + (t * 0.1).sin() * 2.0 + rand_f64() * 0.5,
"Audio-001" => (t * 5.0).sin() * 0.5 + rand_f64() * 0.2,
"Seismic-001" => (t * 0.5).sin() * 0.01 + rand_f64() * 0.002,
_ => 0.0,
};
waveform.push(value);
if waveform.len() > 500 {
waveform.drain(0..waveform.len() - 500);
}
}
if self.frame_count % 10 == 0 {
let mut thermal = vec![0.0f32; 24 * 32];
for y in 0..24 {
for x in 0..32 {
let base = 22.0 + (x as f32 - 16.0).abs() * 0.1 + (y as f32 - 12.0).abs() * 0.1;
let noise = rand_f64() as f32 * 0.5;
let spot_x = 16.0 + (t * 0.2).sin() as f32 * 8.0;
let spot_y = 12.0 + (t * 0.3).cos() as f32 * 6.0;
let dist = ((x as f32 - spot_x).powi(2) + (y as f32 - spot_y).powi(2)).sqrt();
let hot_spot = 5.0 * (-dist / 3.0).exp();
thermal[y * 32 + x] = base + noise + hot_spot;
}
}
self.state.thermal_data = Some(ThermalData {
width: 32,
height: 24,
data: thermal.clone(),
min_temp: thermal.iter().fold(f32::MAX, |a, &b| a.min(b)),
max_temp: thermal.iter().fold(f32::MIN, |a, &b| a.max(b)),
timestamp: Utc::now(),
});
}
if self.frame_count % 5 == 0 {
let mut frequencies = Vec::new();
let mut magnitudes = Vec::new();
let mut max_mag = 0.0f32;
let mut peak_freq = 0.0f32;
for i in 0..256 {
let freq = i as f32 * 100.0; frequencies.push(freq);
let mag =
10.0 * (-(freq - 1000.0).abs() / 200.0).exp() + 5.0 * (-(freq - 5000.0).abs() / 500.0).exp() + 2.0 * rand_f64() as f32;
magnitudes.push(mag);
if mag > max_mag {
max_mag = mag;
peak_freq = freq;
}
}
self.state.spectrum_data = Some(SpectrumData {
frequencies,
magnitudes,
peak_freq,
timestamp: Utc::now(),
});
}
if self.frame_count % 200 == 0 && rand_f64() > 0.5 {
let detection = Detection {
id: uuid::Uuid::new_v4().to_string(),
timestamp: Utc::now(),
detection_type: match (rand_f64() * 5.0) as u32 {
0 => DetectionType::EMFSpike,
1 => DetectionType::ThermalAnomaly,
2 => DetectionType::InfrasoundEvent,
3 => DetectionType::CorrelatedAnomaly,
_ => DetectionType::EntropyAnomaly,
},
confidence: 0.5 + rand_f64() * 0.5,
severity: match (rand_f64() * 4.0) as u32 {
0 => Severity::Low,
1 => Severity::Medium,
2 => Severity::High,
_ => Severity::Critical,
},
sensors: vec![],
entropy_deviation: rand_f64() * 0.3,
anomaly_count: (rand_f64() * 5.0) as usize,
correlation_score: rand_f64() * 0.8,
classification: None,
location: None,
data_window_start: Utc::now(),
data_window_end: Utc::now(),
};
self.state.detections.push(detection);
if self.state.detections.len() > 100 {
self.state.detections.drain(0..self.state.detections.len() - 100);
}
}
let elapsed = self.last_update.elapsed().as_secs_f64();
self.state.stats = SystemStats {
readings_per_sec: 100.0,
detections_total: self.state.detections.len(),
cpu_usage: 15.0 + rand_f64() as f32 * 10.0,
memory_mb: 128.0 + rand_f64() * 50.0,
uptime_secs: (self.frame_count / 60) as u64,
active_sensors: 14,
};
}
}
impl eframe::App for GlowBarnApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
self.frame_count += 1;
if self.demo_mode {
self.update_demo_data();
}
egui::TopBottomPanel::top("menu_bar").show(ctx, |ui| {
egui::menu::bar(ui, |ui| {
ui.menu_button("File", |ui| {
if ui.button("New Session").clicked() {
ui.close_menu();
}
if ui.button("Export Data...").clicked() {
ui.close_menu();
}
ui.separator();
if ui.button("Exit").clicked() {
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
}
});
ui.menu_button("View", |ui| {
ui.checkbox(&mut self.state.show_settings, "Settings");
});
ui.menu_button("Help", |ui| {
if ui.button("About").clicked() {
self.state.show_about = true;
ui.close_menu();
}
});
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
if self.state.recording {
ui.colored_label(egui::Color32::RED, "⏺ RECORDING");
}
if self.demo_mode {
ui.label("🎭 Demo Mode");
}
if self.config.gui.show_fps {
ui.label(format!("{:.0} FPS", 1.0 / ctx.input(|i| i.predicted_dt)));
}
});
});
});
egui::TopBottomPanel::bottom("status_bar").show(ctx, |ui| {
ui.horizontal(|ui| {
status_indicator(ui, true, "System");
ui.separator();
ui.label(format!("Sensors: {}", self.state.stats.active_sensors));
ui.separator();
ui.label(format!("Readings/s: {:.0}", self.state.stats.readings_per_sec));
ui.separator();
ui.label(format!("Detections: {}", self.state.stats.detections_total));
ui.separator();
ui.label(format!("CPU: {:.1}%", self.state.stats.cpu_usage));
ui.separator();
ui.label(format!("Mem: {:.0} MB", self.state.stats.memory_mb));
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
ui.label(chrono::Local::now().format("%H:%M:%S").to_string());
});
});
});
egui::SidePanel::left("sensor_panel")
.resizable(true)
.default_width(250.0)
.show(ctx, |ui| {
self.sensor_panel.show(ui, &mut self.state);
});
egui::SidePanel::right("detection_panel")
.resizable(true)
.default_width(300.0)
.show(ctx, |ui| {
self.detection_panel.show(ui, &mut self.state);
});
egui::CentralPanel::default().show(ctx, |ui| {
let available_height = ui.available_height();
egui::TopBottomPanel::top("viz_top")
.resizable(true)
.default_height(available_height * 0.5)
.show_inside(ui, |ui| {
ui.horizontal(|ui| {
ui.group(|ui| {
ui.set_min_width(ui.available_width() * 0.6);
self.waveform_panel.show(ui, &self.state);
});
ui.group(|ui| {
self.thermal_panel.show(ui, &self.state);
});
});
});
ui.horizontal(|ui| {
ui.group(|ui| {
ui.set_min_width(ui.available_width() * 0.7);
self.spectrum_panel.show(ui, &self.state);
});
ui.group(|ui| {
self.stats_panel.show(ui, &self.state);
});
});
});
if self.state.show_settings {
egui::Window::new("Settings")
.open(&mut self.state.show_settings)
.show(ctx, |ui| {
ui.heading("General");
ui.checkbox(&mut self.demo_mode, "Demo Mode");
ui.checkbox(&mut self.state.alerts_enabled, "Enable Alerts");
ui.separator();
ui.heading("Display");
});
}
if self.state.show_about {
egui::Window::new("About GlowBarn")
.open(&mut self.state.show_about)
.resizable(false)
.show(ctx, |ui| {
ui.vertical_centered(|ui| {
ui.heading("🌟 GlowBarn");
ui.label(format!("Version {}", env!("CARGO_PKG_VERSION")));
ui.label("High-Performance Paranormal Detection Suite");
ui.separator();
ui.label("Built with Rust 🦀");
ui.label("50+ sensor types • Advanced entropy analysis");
ui.label("Military-grade encryption • GPU acceleration");
});
});
}
ctx.request_repaint();
self.last_update = std::time::Instant::now();
}
}
fn rand_f64() -> f64 {
use std::time::{SystemTime, UNIX_EPOCH};
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.subsec_nanos();
(nanos as f64 / u32::MAX as f64)
}