use std::path::PathBuf;
use std::sync::atomic::Ordering;
use RustedSciThe::command_interpreter::task_parser::DocumentParser;
use log::{info, warn};
use super::{
BvpGuiConfig, CombustionApp, GuiFileOperationKind, GuiFileOperationResult, ProblemsEnum,
};
impl CombustionApp {
pub fn save_document(&mut self, path: PathBuf) -> GuiFileOperationResult {
let content = self.document_to_string();
let result = match std::fs::write(&path, content) {
Ok(_) => GuiFileOperationResult::Saved { path: path.clone() },
Err(e) => GuiFileOperationResult::Failed {
kind: GuiFileOperationKind::Save,
path: Some(path.clone()),
message: e.to_string(),
},
};
match &result {
GuiFileOperationResult::Saved { path } => {
info!("Successfully saved to: {:?}", path);
}
GuiFileOperationResult::Failed { message, .. } => {
warn!("Error saving file: {}", message);
}
GuiFileOperationResult::Loaded { .. } => {}
}
if let GuiFileOperationResult::Saved { path } = &result {
self.set_document_path(Some(path.clone()));
self.document_lifecycle
.record_clean(result.clone(), self.current_document_fingerprint());
} else {
self.document_lifecycle.record(result.clone());
}
result
}
pub(crate) fn load_document_from_path(&mut self, path: PathBuf) -> GuiFileOperationResult {
let result = match std::fs::read_to_string(&path) {
Ok(content) => {
let mut parser = DocumentParser::new(content);
match parser.parse_document() {
Ok(_) => match parser.get_result() {
Some(parsed_doc) => {
self.document = parsed_doc.clone();
if matches!(self.selected_problem, ProblemsEnum::BVPSimple) {
super::seed_bvp_document_defaults(&mut self.document);
}
let (bvp_gui_config, bvp_gui_migration_report) =
BvpGuiConfig::from_document(&self.document);
self.bvp_gui_config = bvp_gui_config;
self.bvp_gui_migration_report = bvp_gui_migration_report;
self.validation_fingerprint = None;
self.refresh_validation_report();
self.set_document_path(Some(path.clone()));
self.document_lifecycle.record_clean(
GuiFileOperationResult::Loaded { path: path.clone() },
self.current_document_fingerprint(),
);
GuiFileOperationResult::Loaded { path: path.clone() }
}
None => GuiFileOperationResult::Failed {
kind: GuiFileOperationKind::Load,
path: Some(path.clone()),
message: "Parser returned no result".to_string(),
},
},
Err(error) => GuiFileOperationResult::Failed {
kind: GuiFileOperationKind::Load,
path: Some(path.clone()),
message: error.to_string(),
},
}
}
Err(error) => GuiFileOperationResult::Failed {
kind: GuiFileOperationKind::Load,
path: Some(path.clone()),
message: error.to_string(),
},
};
match &result {
GuiFileOperationResult::Loaded { path } => {
info!("Successfully loaded and parsed file: {:?}", path);
}
GuiFileOperationResult::Failed { message, .. } => {
warn!("Error loading file: {}", message);
}
GuiFileOperationResult::Saved { .. } => {}
}
if matches!(result, GuiFileOperationResult::Failed { .. }) {
self.document_lifecycle.record(result.clone());
}
result
}
pub(crate) fn sync_document_state_after_edit(&mut self) {
self.refresh_bvp_gui_snapshot();
self.refresh_document_lifecycle_dirty_state();
}
fn set_document_path(&mut self, path: Option<PathBuf>) {
self.current_file_path = path.clone();
self.document_lifecycle.current_path = path;
}
fn current_document_fingerprint(&self) -> String {
self.current_validation_fingerprint()
}
pub(crate) fn refresh_document_lifecycle_dirty_state(&mut self) {
self.document_lifecycle
.sync_dirty_state(self.current_document_fingerprint());
}
fn problem_switch_requires_confirmation(&mut self) -> bool {
self.refresh_document_lifecycle_dirty_state();
self.document_lifecycle.dirty || self.calculation_state.is_active()
}
pub(crate) fn request_document_load(&mut self, path: PathBuf) -> bool {
if self.problem_switch_requires_confirmation() {
self.pending_document_load = Some(path.clone());
self.last_run_message = Some(format!(
"Confirm loading {} before discarding the current task state.",
path.display()
));
self.last_run_is_error = false;
false
} else {
self.load_document_from_path(path);
true
}
}
pub(crate) fn confirm_pending_document_load(&mut self) -> bool {
let Some(path) = self.pending_document_load.take() else {
return false;
};
!self.load_document_from_path(path).is_error()
}
pub(crate) fn cancel_pending_document_load(&mut self) {
if let Some(path) = self.pending_document_load.take() {
self.last_run_message = Some(format!(
"Load cancelled; the current task was preserved instead of loading {}.",
path.display()
));
self.last_run_is_error = false;
}
}
pub(crate) fn request_window_close(&mut self) -> bool {
if self.problem_switch_requires_confirmation() {
self.pending_window_close = true;
self.last_run_message = Some(
"Confirm closing the window before discarding the current task state.".to_string(),
);
self.last_run_is_error = false;
false
} else {
true
}
}
pub(crate) fn confirm_pending_window_close(&mut self) -> bool {
if !self.pending_window_close {
return false;
}
self.pending_window_close = false;
if self.calculation_state.is_active() {
self.cancel_calculation();
}
true
}
pub(crate) fn cancel_pending_window_close(&mut self) {
if self.pending_window_close {
self.pending_window_close = false;
self.last_run_message =
Some("Close cancelled; the current task was preserved.".to_string());
self.last_run_is_error = false;
}
}
pub(crate) fn request_problem_switch(&mut self, problem: ProblemsEnum) -> bool {
if self.selected_problem == problem {
return true;
}
if self.problem_switch_requires_confirmation() {
self.pending_problem_switch = Some(problem.clone());
self.last_run_message = Some(format!(
"Confirm switching to {} before discarding the current task state.",
problem
));
self.last_run_is_error = false;
false
} else {
self.replace_problem(problem);
true
}
}
pub(crate) fn confirm_pending_problem_switch(&mut self) -> bool {
let Some(problem) = self.pending_problem_switch.take() else {
return false;
};
self.replace_problem(problem);
true
}
pub(crate) fn cancel_pending_problem_switch(&mut self) {
if self.pending_problem_switch.take().is_some() {
self.last_run_message =
Some("Problem switch cancelled; the current task was preserved.".to_string());
self.last_run_is_error = false;
}
}
pub(crate) fn replace_problem(&mut self, problem: ProblemsEnum) {
if let Some(cancel) = &self.calculation_cancel {
cancel.store(true, Ordering::Release);
}
*self = Self::new_with_problem(problem);
}
}