use crate::Shape;

/// Repeat a shape in a linear array along a direction.
pub fn linear_array(
    shape: &Shape,
    count: usize,
    spacing: [f64; 3],
) -> Shape {
    let shapes: Vec<Shape> = (0..count)
        .map(|i| {
            let f = i as f64;
            shape.clone().translate(
                spacing[0] * f,
                spacing[1] * f,
                spacing[2] * f,
            )
        })
        .collect();
    Shape::union_all(shapes)
}

/// Repeat a shape in a circular pattern around the Z axis.
pub fn polar_array(shape: &Shape, count: usize) -> Shape {
    let step = 360.0 / count as f64;
    let shapes: Vec<Shape> = (0..count)
        .map(|i| shape.clone().rotate_z(step * i as f64))
        .collect();
    Shape::union_all(shapes)
}

/// Repeat a shape on a rectangular grid in XY.
pub fn grid_array(
    shape: &Shape,
    nx: usize,
    ny: usize,
    sx: f64,
    sy: f64,
) -> Shape {
    let mut shapes = Vec::with_capacity(nx * ny);
    for iy in 0..ny {
        for ix in 0..nx {
            shapes.push(shape.clone().translate(ix as f64 * sx, iy as f64 * sy, 0.0));
        }
    }
    Shape::union_all(shapes)
}

/// Mirror a shape across the XY plane (negate Z, union with original).
pub fn mirror_z(shape: &Shape) -> Shape {
    shape.clone() | shape.clone().scale(1.0, 1.0, -1.0)
}

/// Mirror a shape across the XZ plane (negate Y, union with original).
pub fn mirror_y(shape: &Shape) -> Shape {
    shape.clone() | shape.clone().scale(1.0, -1.0, 1.0)
}

/// Mirror a shape across the YZ plane (negate X, union with original).
pub fn mirror_x(shape: &Shape) -> Shape {
    shape.clone() | shape.clone().scale(-1.0, 1.0, 1.0)
}
