use std::fs;
use bevy::prelude::*;
use native_dialog::{DialogBuilder, MessageLevel};
use crate::events::NumplesEvent;
use crate::game::{Board, Level};
use crate::gameplay::{Clock, Gameplay};
use crate::states::GameState;
use super::payload::Payload;
#[derive(Debug, Clone, Default, Resource)]
pub struct Persistence {
pub load: bool,
pub save: bool,
}
impl Persistence {
pub fn load_board(
mut this: ResMut<Self>,
mut commands: Commands,
mut event_writer: EventWriter<NumplesEvent>,
mut board_query: Query<&mut Board>,
mut level_query: Query<&mut Level>,
mut clock: ResMut<Clock>,
mut next_state: ResMut<NextState<GameState>>,
current_state: Res<State<GameState>>,
) {
if !this.load {
return;
}
this.load = false;
if let Some(filename) = this.load_file_name() {
match fs::read_to_string(filename) {
Ok(payload) => match serde_json::from_str::<Payload>(&payload) {
Ok(payload) => {
if let Ok(mut board) = board_query.single_mut() {
*board = payload.board;
} else {
commands.spawn((Gameplay, payload.board));
}
if let Ok(mut level) = level_query.single_mut() {
*level = payload.level;
} else {
commands.spawn((Gameplay, payload.level));
}
*clock = payload.clock;
if *current_state == GameState::Title {
next_state.set(GameState::Playing);
}
event_writer.write(NumplesEvent::RenderBoard);
}
Err(err) => {
eprintln!("{:?}", err);
eprintln!("content: {}", payload);
this.dialog(&err.to_string(), MessageLevel::Error);
}
}
Err(err) => {
eprintln!("{:?}", err);
this.dialog(&err.to_string(), MessageLevel::Error);
}
}
}
}
pub fn save_board(
board: Single<&Board>,
clock: Res<Clock>,
level: Single<&Level>,
mut persistence: ResMut<Self>,
) {
if !persistence.save {
return;
}
persistence.save = false;
if let Some(filename) = persistence.save_file_name(**level) {
let payload = Payload {
board: board.clone(),
clock: clock.clone(),
level: **level,
};
match serde_json::to_string(&payload) {
Ok(payload) => match fs::write(filename, payload) {
Ok(_) => (),
Err(err) => {
eprintln!("{:?}", err);
persistence.dialog(&err.to_string(), MessageLevel::Error);
}
},
Err(err) => {
eprintln!("{:?}", err);
persistence.dialog(&err.to_string(), MessageLevel::Error);
}
}
}
}
fn dialog(&self, message: &str, level: MessageLevel) {
DialogBuilder::message()
.set_title("Numplës Message")
.set_text(message)
.set_level(level)
.alert()
.show()
.expect("error showing dialog");
}
fn load_file_name(&self) -> Option<String> {
let path = DialogBuilder::file()
.set_title("Open Board")
.set_location(env!["HOME"])
.open_single_file()
.show();
match path {
Ok(Some(path)) => Some(path.to_string_lossy().into_owned()),
Ok(None) | Err(_) => None,
}
}
fn save_file_name(&self, level: Level) -> Option<String> {
let path = DialogBuilder::file()
.set_title("Save Board")
.set_location(env!["HOME"])
.set_filename(format!("{}.json", level.to_string()))
.add_filter("JSON", &["json", "jsonc"])
.save_single_file()
.show();
match path {
Ok(Some(path)) => Some(path.to_string_lossy().into_owned()),
Ok(None) | Err(_) => None,
}
}
}