Documentation
mod set;

pub use self::set::StateSet;

use std::ops::{Index, IndexMut, Range};

use crate::auto::{Automaton, ConstructorSet, FlowSet};
use crate::{Constructor, Polarity};

#[derive(Debug)]
pub struct State<C: Constructor> {
    #[cfg(debug_assertions)]
    pub(crate) pol: Polarity,
    pub(crate) cons: ConstructorSet<C>,
    pub(crate) flow: FlowSet,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct StateId(u32);

#[derive(Debug, Clone)]
pub struct StateRange(Range<u32>);

impl StateId {
    pub fn as_u32(self) -> u32 {
        self.0
    }

    pub fn shift(self, offset: u32) -> Self {
        StateId(self.0 + offset)
    }
}

impl<C: Constructor> State<C> {
    pub(crate) fn new(_pol: Polarity) -> Self {
        State {
            #[cfg(debug_assertions)]
            pol: _pol,
            cons: ConstructorSet::default(),
            flow: FlowSet::default(),
        }
    }

    pub fn constructors(&self) -> &ConstructorSet<C> {
        &self.cons
    }

    pub fn flow(&self) -> &FlowSet {
        &self.flow
    }

    fn shift(self, offset: u32) -> Self {
        State {
            #[cfg(debug_assertions)]
            pol: self.pol,
            cons: self.cons.shift(offset),
            flow: self.flow.shift(offset),
        }
    }
}

impl<C: Constructor> Clone for State<C> {
    fn clone(&self) -> Self {
        State {
            #[cfg(debug_assertions)]
            pol: self.pol,
            cons: self.cons.clone(),
            flow: self.flow.clone(),
        }
    }
}

impl<C: Constructor> Automaton<C> {
    pub(crate) fn next(&mut self) -> StateId {
        StateId(self.states.len() as u32)
    }

    pub(crate) fn add(&mut self, state: State<C>) -> StateId {
        let id = self.next();
        self.states.push(state);
        id
    }

    pub fn add_from(&mut self, other: &Self) -> u32 {
        let offset = self.states.len() as u32;
        self.states.extend(
            other
                .states
                .iter()
                .cloned()
                .map(|state| state.shift(offset)),
        );
        offset
    }

    pub(crate) fn index_mut2(
        &mut self,
        StateId(i): StateId,
        StateId(j): StateId,
    ) -> (&mut State<C>, &mut State<C>) {
        debug_assert_ne!(i, j);
        if i < j {
            let (l, r) = self.states.split_at_mut(j as usize);
            (&mut l[i as usize], &mut r[0])
        } else {
            let (l, r) = self.states.split_at_mut(i as usize);
            (&mut r[0], &mut l[j as usize])
        }
    }

    pub(crate) fn range_from(&mut self, StateId(start): StateId) -> StateRange {
        StateRange(start..(self.states.len() as u32))
    }

    pub(crate) fn enumerate(&self) -> impl Iterator<Item = (StateId, &State<C>)> {
        self.states
            .iter()
            .enumerate()
            .map(|(id, st)| (StateId(id as u32), st))
    }
}

impl<C: Constructor> Index<StateId> for Automaton<C> {
    type Output = State<C>;

    fn index(&self, StateId(id): StateId) -> &Self::Output {
        self.states.index(id as usize)
    }
}

impl<C: Constructor> IndexMut<StateId> for Automaton<C> {
    fn index_mut(&mut self, StateId(id): StateId) -> &mut Self::Output {
        self.states.index_mut(id as usize)
    }
}

impl StateRange {
    pub fn shift(self, offset: u32) -> Self {
        StateRange((self.0.start + offset)..(self.0.end + offset))
    }
}

impl Iterator for StateRange {
    type Item = StateId;

    fn next(&mut self) -> Option<Self::Item> {
        self.0.next().map(StateId)
    }
}