use crate::noise::NoiseSource;
use crate::noise::NoiseType;
use crate::texture::Texture;
use crate::vec3::Vec3;

pub struct NoiseTexture<N>
where
    N: NoiseSource,
{
    noise_source: N,
    noise_type: NoiseType,
}

impl<N> NoiseTexture<N>
where
    N: NoiseSource,
{
    pub fn new(noise_source: N, noise_type: NoiseType) -> NoiseTexture<N> {
        NoiseTexture {
            noise_source,
            noise_type,
        }
    }
}

impl<N> Texture for NoiseTexture<N>
where
    N: NoiseSource,
{
    fn value(&self, _u: f32, _v: f32, p: Vec3) -> Vec3 {
        let v = match self.noise_type {
            NoiseType::Scale(scale) => self.noise_source.scaled(p, scale),

            NoiseType::Turbulence(turbulence) => self.noise_source.turbulence(p, turbulence),
            NoiseType::Marble {
                period,
                power,
                size,
                scale,
            } => self.noise_source.marble(p, period, power, size, scale),
        };
        debug_assert!(v >= 0., "Cold pixel @ {}: {}", p, v);
        debug_assert!(v <= 1., "Hot pixel @ {}: {}", p, v);
        Vec3::new(1., 1., 1.) * v
    }
}
