organicomplex 0.7.0

Interactive complex-valued cellular automaton on 2D and 3D grids in search of that stuff - emergence, open-endedness, organicity etc.
use crate::{
	base::PrependErrorString,
	sys::Key
};

use super::{
	ERR_ALREADY_SET,
	ERR_NOT_SET_CANNOT_FINISH,
	ERR_NOT_SET_CANNOT_RUN,
	Context,
	Master
};

const MID: &str = "Sync";

const AUTOSAVE_INTERVAL: i128 = 60 * 60 * 1_000_000; // each play-time hour

pub enum MSync {
	Unset,
	Set {
		time_before_last_pause: i128,
		last_resume_instant: i128,
		last_autosave_time: i128,
	}
}

impl MSync {
	pub fn new() -> Box<Self> {
		Box::new(Self::Unset)
	}
}

impl Master for MSync {
	fn id(&self) -> String {
		String::from(MID)
	}

	fn start(&mut self, Context{sys, state, ..}: &mut Context) -> Result<(), String> {
		match self {
			Self::Unset => {
				*self = Self::Set {
					time_before_last_pause: state.playtime,
					last_resume_instant: sys.now(),
					last_autosave_time: state.playtime
				};

				sys.resume_audio();

				Ok(())
			},
			Self::Set{..} => Err(format!("{} {}", MID, ERR_ALREADY_SET))
		}
	}

    fn run(&mut self, Context{sys, state, ether, ..}: &mut Context) -> Result<(), String> {
		match self {
			&mut Self::Set{ref mut time_before_last_pause, ref mut last_resume_instant, ref mut last_autosave_time} => {
				if ether.paused { // resume
					*time_before_last_pause = state.playtime;
					*last_resume_instant = sys.now();
					ether.paused = false;

					sys.resume_audio();
				}

				sys.sync()?;

				let time_after_last_resume = sys.now() - (*last_resume_instant);

				state.playtime = (*time_before_last_pause) + time_after_last_resume;

				if state.playtime - (*last_autosave_time) > AUTOSAVE_INTERVAL {
					state.save().pre_err("cannot save state to autosave")?;
					*last_autosave_time = state.playtime;
				}

				if sys.poll_key(Key::V) {
					sys.set_draw_suspend(!sys.draw_suspended());
				}

				Ok(())
			},
			Self::Unset => Err(format!("{} {}", MID, ERR_NOT_SET_CANNOT_RUN))
		}
    }

	fn finish(&mut self, Context{sys, ..}: &mut Context) -> Result<(), String> {
		match self {
			Self::Set{..} => {
				sys.halt_audio();
				Ok(())
			},
			Self::Unset => Err(format!("{} {}", MID, ERR_NOT_SET_CANNOT_FINISH))
		}
	}

}