#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum Error {
    BadWidth { expected: usize, got: usize },
}

/// A two-dimensional grid of values.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Grid<T> {
    width: usize,
    height: usize,
    rows: Vec<Vec<T>>,
}

impl<T> Grid<T> {
    /// Creates a new grid with a given `width` and `height`. The data is given as a [`Vec`] of
    /// rows, each row a [`Vec`] of values.
    ///
    /// # Errors
    ///
    /// Returns an error if the given data does not match up with the dimensions.
    pub fn from_rows(rows: Vec<Vec<T>>) -> Result<Self, Error> {
        let row_len = rows.get(0).map_or(0, Vec::len);
        if let Some(err) = rows.iter().map(Vec::len).find_map(|l| {
            (l != row_len).then_some(Error::BadWidth {
                expected: row_len,
                got: l,
            })
        }) {
            return Err(err);
        }

        Ok(Self {
            width: rows.get(0).map_or(0, std::vec::Vec::len),
            height: rows.len(),
            rows,
        })
    }

    pub fn rows(&self) -> impl Iterator<Item = impl Iterator<Item = &T>> {
        self.rows.iter().map(|row| row.iter())
    }

    pub fn cols(&self) -> impl Iterator<Item = impl Iterator<Item = &T>> {
        (0..self.width).map(|i| self.rows.iter().map(move |r| &r[i]))
    }

    pub fn rows_mut(&mut self) -> impl Iterator<Item = impl Iterator<Item = &mut T>> {
        self.rows.iter_mut().map(|row| row.iter_mut())
    }

    /*
    pub fn cols_mut(&mut self) -> impl Iterator<Item = impl Iterator<Item = &mut T>> {
        (0..self.width).map(move |i| {
            self.rows.iter_mut().map(move |r| {
                let i: usize = i;
                let x: &mut T = &mut r[i];
                x
            })
        })
    }
    */
}
