// Copyright (C) 2025 Christian Mauduit <ufoot@ufoot.org>

use crate::errors::*;
use crate::mesh_3d::shape_3d::*;

/// Trait for converting between 3D coordinates and linear indices.
///
/// This trait provides bidirectional conversion between 3D `(x, y, z)` coordinates
/// and 1D linear indices, essential for mapping between volumetric positions
/// and array/vector storage.
///
/// # Coordinate System
///
/// - `x` increases from left to right (column index)
/// - `y` increases from top to bottom (row index)
/// - `z` increases from front to back (depth/layer index)
/// - Linear indices typically follow layer-major order: `index = z * (width * height) + y * width + x`
///
/// # Example
///
/// ```
/// use shortestpath::mesh_3d::{Index3D, Full3D};
///
/// let mesh = Full3D::new(5, 4, 3);
///
/// // Convert (x, y, z) to linear index
/// let index = mesh.xyz_to_index(2, 1, 1).unwrap();
/// assert_eq!(index, 27); // 1 * (5 * 4) + 1 * 5 + 2 = 27
///
/// // Convert back to coordinates
/// let (x, y, z) = mesh.index_to_xyz(27).unwrap();
/// assert_eq!((x, y, z), (2, 1, 1));
/// ```
pub trait Index3D: Shape3D {
    /// Converts a linear index to 3D coordinates.
    ///
    /// # Arguments
    ///
    /// * `index` - The linear index to convert
    ///
    /// # Returns
    ///
    /// `Ok((x, y, z))` if the index is valid, or an `Err` if out of bounds
    fn index_to_xyz(&self, index: usize) -> Result<(usize, usize, usize)>;

    /// Converts 3D coordinates to a linear index.
    ///
    /// # Arguments
    ///
    /// * `x` - The column coordinate (0-based)
    /// * `y` - The row coordinate (0-based)
    /// * `z` - The depth/layer coordinate (0-based)
    ///
    /// # Returns
    ///
    /// `Ok(index)` if the coordinates are valid, or an `Err` if out of bounds
    fn xyz_to_index(&self, x: usize, y: usize, z: usize) -> Result<usize>;
}
