use crate::{error::VoxelError, models::VoxelType};

pub struct VoxelGrid {
    pub width: u32,
    pub height: u32,
    pub depth: u32,
    data: Vec<Option<VoxelType>>,
}

impl VoxelGrid {
    pub fn new(width: u32, height: u32, depth: u32) -> Self {
        let capacity = (width * height * depth) as usize;

        Self {
            width,
            height,
            depth,
            data: vec![None; capacity],
        }
    }

    #[inline(always)]
    fn get_index(&self, x: u32, y: u32, z: u32) -> Option<usize> {
        if x >= self.width || y >= self.height || z >= self.depth {
            return None;
        }

        Some((x + self.width * (y + self.height * z)) as usize)
    }

    pub fn set(&mut self, x: u32, y: u32, z: u32, voxel: VoxelType) -> Result<(), VoxelError> {
        match self.get_index(x, y, z) {
            Some(index) => {
                self.data[index] = Some(voxel);
                Ok(())
            }
            None => Err(VoxelError::OutOfBounds { x, y, z }),
        }
    }

    pub fn get(&self, x: u32, y: u32, z: u32) -> Option<VoxelType> {
        self.get_index(x, y, z).and_then(|index| self.data[index])
    }
}
