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

use crate::op::{Op, OpRef};
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OpPool(Vec<Op>);

impl OpPool {
    pub fn new(initial_capacity: usize) -> OpPool {
        OpPool(Vec::with_capacity(initial_capacity))
    }

    pub fn len(&self) -> usize {
        self.0.len()
    }

    pub fn insert(&mut self, op: Op) -> OpRef {
        let ix = self.0.len();
        self.0.push(op);

        OpRef::new(ix)
    }

    pub fn iter(&self) -> std::slice::Iter<'_, Op> {
        self.0.iter()
    }

    pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, Op> {
        self.0.iter_mut()
    }

    pub fn get(&self, opref: OpRef) -> Option<&Op> {
        self.0.get(opref.0)
    }

    pub fn get_mut(&mut self, opref: OpRef) -> Option<&mut Op> {
        self.0.get_mut(opref.0)
    }
}

impl<'a> IntoIterator for &'a OpPool {
    type Item = &'a Op;
    type IntoIter = std::slice::Iter<'a, Op>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter()
    }
}

impl<'a> IntoIterator for &'a mut OpPool {
    type Item = &'a mut Op;
    type IntoIter = std::slice::IterMut<'a, Op>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.iter_mut()
    }
}

impl IntoIterator for OpPool {
    type Item = Op;
    type IntoIter = std::vec::IntoIter<Op>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl From<Vec<Op>> for OpPool {
    fn from(value: Vec<Op>) -> Self {
        Self(value)
    }
}

impl Index<usize> for OpPool {
    type Output = Op;

    fn index(&self, index: usize) -> &Self::Output {
        &self.0[index]
    }
}

impl IndexMut<usize> for OpPool {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        &mut self.0[index]
    }
}

impl Index<OpRef> for OpPool {
    type Output = Op;

    fn index(&self, index: OpRef) -> &Self::Output {
        &self.0[index.0]
    }
}

impl IndexMut<OpRef> for OpPool {
    fn index_mut(&mut self, index: OpRef) -> &mut Self::Output {
        &mut self.0[index.0]
    }
}
