use crate::Arena;
use crate::utils::{FileLoc, ParameterDictionary};
use anyhow::{Result, anyhow};
use shared::core::geometry::Point2i;
use shared::core::sampler::{
    HaltonSampler, IndependentSampler, PaddedSobolSampler, Sampler, SobolSampler,
    StratifiedSampler, ZSobolSampler,
};

pub trait CreateSampler {
    fn create(
        params: &ParameterDictionary,
        full_res: Point2i,
        loc: &FileLoc,
        arena: &mut Arena,
    ) -> Result<Self>;
}

pub trait SamplerFactory {
    fn create(
        name: &str,
        params: &ParameterDictionary,
        full_res: Point2i,
        loc: &FileLoc,
        arena: &mut Arena,
    ) -> Result<Self>;
}

impl SamplerFactory for Sampler {
    fn create(
        name: &str,
        params: &ParameterDictionary,
        full_res: Point2i,
        loc: &FileLoc,
        arena: &mut Arena,
    ) -> Result<Self> {
        match name {
            "zsobol" => {
                let sampler = ZSobolSampler::create(params, full_res, loc, arena)?;
                Ok(Sampler::ZSobol(sampler))
            }
            "paddedsobol" => {
                let sampler = PaddedSobolSampler::create(params, full_res, loc, arena)?;
                Ok(Sampler::PaddedSobol(sampler))
            }
            "halton" => {
                let sampler = HaltonSampler::create(params, full_res, loc, arena)?;
                Ok(Sampler::Halton(sampler))
            }
            "sobol" => {
                let sampler = SobolSampler::create(params, full_res, loc, arena)?;
                Ok(Sampler::Sobol(sampler))
            }
            "Independent" => {
                let sampler = IndependentSampler::create(params, full_res, loc, arena)?;
                Ok(Sampler::Independent(sampler))
            }
            "stratified" => {
                let sampler = StratifiedSampler::create(params, full_res, loc, arena)?;
                Ok(Sampler::Stratified(sampler))
            }
            _ => Err(anyhow!("Film type '{}' unknown at {}", name, loc)),
        }
    }
}
