//! Frame-timing simulation: a shared `Engine` driven by an `InputSource`.

pub mod config;
pub mod engine;
pub mod input;
pub mod replay_input;

pub use config::{EngineConfig, LeveledGravity};
pub use engine::Engine;
pub use input::{Action, FrameInput, InputKind, InputSource};
pub use replay_input::ReplayInputSource;

use crate::engine::board::Board;
use crate::engine::prng::generate_sequence;
use crate::replay::Replay;

/// Thin replay driver: an `Engine` fed by a `ReplayInputSource`.
pub struct ReplaySimulator {
    engine: Engine,
    input: ReplayInputSource,
}

impl ReplaySimulator {
    pub fn new(replay: &Replay, queue_size: usize) -> ReplaySimulator {
        let queue_size = queue_size.max(replay.pieces_placed as usize + 50);
        let board = Board::new(generate_sequence(replay.seed, queue_size, replay.no_szo));
        let engine = Engine::new(board, EngineConfig::from_replay(replay));
        let input = ReplayInputSource::new(replay);
        ReplaySimulator { engine, input }
    }

    pub fn step(&mut self) -> Option<i32> {
        self.engine.step(&mut self.input)
    }

    pub fn board(&self) -> &Board {
        &self.engine.board
    }
}

pub fn simulate(replay: &Replay) -> Board {
    let mut sim = ReplaySimulator::new(replay, 300);
    while sim.step().is_some() {}
    sim.engine.board
}
