use crate::{MessagePtr, random::Seed, timer::TimerId};

/// Unique identifier for a process within the simulation. Pids are assigned
/// sequentially starting from 0 in the order pools are added.
pub type Pid = usize;

/// Core trait for defining process behavior in the simulation.
///
/// Each process reacts to three kinds of events: startup, incoming messages,
/// and timer firings. Inside any handler you may call the global interaction
/// functions ([`crate::send_to`], [`crate::broadcast`], [`crate::schedule_timer_after`], etc.).
pub trait Process {
    /// Called once when the simulation starts, before any messages are delivered. Provides simulation seed for process.
    fn on_start(&mut self, seed: Seed);

    /// Called when a message arrives from another process.
    fn on_message(&mut self, from: Pid, message: MessagePtr);

    /// Called when a previously scheduled timer fires.
    fn on_timer(&mut self, id: TimerId);
}

impl<T: Process + ?Sized> Process for Box<T> {
    fn on_start(&mut self, seed: Seed) {
        (**self).on_start(seed)
    }

    fn on_message(&mut self, from: Pid, message: MessagePtr) {
        (**self).on_message(from, message)
    }

    fn on_timer(&mut self, id: TimerId) {
        (**self).on_timer(id)
    }
}

pub(crate) type ProcessPtr = Box<dyn Process + Send>;
