use crate::Arena;
use crate::core::sampler::CreateSampler;
use crate::utils::{FileLoc, ParameterDictionary};
use shared::core::geometry::Point2i;
use shared::core::options::get_options;
use shared::core::sampler::{PaddedSobolSampler, RandomizeStrategy, SobolSampler, ZSobolSampler};
use std::fmt::Error;

impl CreateSampler for SobolSampler {
    fn create(
        params: &ParameterDictionary,
        full_res: Point2i,
        loc: &FileLoc,
        arena: &mut Arena,
    ) -> Result<Self, Error> {
        let options = get_options();
        let nsamp = options
            .quick_render
            .then_some(1)
            .or(options.pixel_samples)
            .unwrap_or_else(|| params.get_one_int("pixelsamples", 16));
        let seed = params.get_one_int("seed", options.seed);
        let s = match params.get_one_string("randomization", "fastowen").as_str() {
            "none" => RandomizeStrategy::None,
            "permutedigits" => RandomizeStrategy::PermuteDigits,
            "fastowen" => RandomizeStrategy::FastOwen,
            "owen" => RandomizeStrategy::Owen,
            _ => {
                return Err(format!("{}: Unknown randomization strategy for Sobol", loc));
            }
        };

        let sampler = Self::new(nsamp as usize, full_res, s, Some(seed as u64));
        arena.alloc(sampler);
        Ok(sampler)
    }
}

impl CreateSampler for PaddedSobolSampler {
    fn create(
        params: &ParameterDictionary,
        _full_res: Point2i,
        loc: &FileLoc,
        arena: &mut Arena,
    ) -> Result<Self, Error> {
        let options = get_options();
        let nsamp = options
            .quick_render
            .then_some(1)
            .or(options.pixel_samples)
            .unwrap_or_else(|| params.get_one_int("pixelsamples", 16));
        let seed = params.get_one_int("seed", options.seed);
        let s = match params.get_one_string("randomization", "fastowen").as_str() {
            "none" => RandomizeStrategy::None,
            "permutedigits" => RandomizeStrategy::PermuteDigits,
            "fastowen" => RandomizeStrategy::FastOwen,
            "owen" => RandomizeStrategy::Owen,
            _ => {
                return Err(format!(
                    "{}: Unknown randomization strategy for ZSobol",
                    loc
                ));
            }
        };

        let sampler = Self::new(nsamp as u32, s, Some(seed as u64));
        arena.alloc(sampler);
        Ok(sampler)
    }
}

impl CreateSampler for ZSobolSampler {
    fn create(
        params: &ParameterDictionary,
        full_res: Point2i,
        loc: &FileLoc,
        arena: &mut Arena,
    ) -> Result<Self, Error> {
        let options = get_options();
        let nsamp = options
            .quick_render
            .then_some(1)
            .or(options.pixel_samples)
            .unwrap_or_else(|| params.get_one_int("pixelsamples", 16));
        let seed = params.get_one_int("seed", options.seed);
        let s = match params.get_one_string("randomization", "fastowen").as_str() {
            "none" => RandomizeStrategy::None,
            "permutedigits" => RandomizeStrategy::PermuteDigits,
            "fastowen" => RandomizeStrategy::FastOwen,
            "owen" => RandomizeStrategy::Owen,
            _ => {
                return Err(format!(
                    "{}: Unknown randomization strategy for ZSobol",
                    loc
                ));
            }
        };

        let sampler = ZSobolSampler::new(nsamp as u32, full_res, s, Some(seed as u64));
        arena.alloc(sampler);
        Ok(sampler)
    }
}
