use rand::Rng;
use crate::system::model::DLASystem;
use crate::system::{Position, Storage};
use crate::system::spawner::Spawner;
use crate::system::sticker::Sticker;
use crate::system::walker::Walker;
use std::time::SystemTime;

pub mod cli;
pub mod output;

pub fn drive_system<R: Rng, P: Position, S: Storage<P>, W: Walker<P>, Sp: Spawner<P>, St: Sticker<P, S>>(
    sys: &mut DLASystem<R, P, S, W, Sp, St>,
    max_frames: Option<usize>,
    notify_every: Option<usize>,
) {
    let start = SystemTime::now();
    let mut prev = start.clone();
    let mut previous_n: usize = 0;
    while sys.running {
        sys.update();

        if let Some(notify_every) = notify_every && (sys.history.len() % notify_every) == 0 && previous_n != sys.history.len() {
            let now = SystemTime::now();

            println!("[{}ms, d = {}ms] On frame {}, deposited {} particles",
                     now.duration_since(start).unwrap().as_millis(),
                     now.duration_since(prev).unwrap().as_millis(),
                     sys.frame, sys.history.len()
            );

            prev = now;
            previous_n = sys.history.len();
        }

        match max_frames {
            Some(max_frames) if max_frames <= sys.frame => {
                sys.running = false;
                eprintln!("System halted as it ran to {frame} frames (max_frames = {max_frames}) and did not complete", frame = sys.frame)
            }
            _ => {}
        }
    }
}

