use nonstdfloat::f128;
use strafe_type::{p64, r64, tof64, w64, Checked, Positive64, Real64};
use crate::{distribution::binom::rbinom, traits::RNG};
static NaInt: i32 = std::i32::MIN;
pub fn rmultinom<R>(
mut n: i32,
prob: &[Checked<Positive64>],
K: usize,
rN: &mut [Checked<Real64>],
rng: &mut R,
) where
R: RNG,
{
let prob = prob.iter().map(|p_i| tof64!(p_i)).collect::<Vec<_>>();
let mut k = 0;
let mut pp = 0.0;
let mut p_tot = f128::new(0.0);
if K < 1 {}
if n == NaInt || n < 0 {
rN[0] = r64!(NaInt);
}
k = 0;
while k < K {
pp = prob[k];
if !pp.is_finite() || pp < 0.0 || pp > 1.0 {
rN[k] = r64!(NaInt);
}
p_tot += f128::new(pp);
rN[k] = r64!(0);
k += 1
}
if tof64!(p_tot - f128::new(1.0)).abs() > 1e-7 {
warn!(
"rbinom: probability sum should be 1, but is {}",
tof64!(p_tot)
);
}
if n == 0 {}
if K == 1 && p_tot == f128::new(0.0) {}
k = 0;
while k < K - 1 {
if prob[k] != 0.0 {
pp = tof64!(f128::new(prob[k]) / p_tot);
rN[k] = r64!(if pp < 1.0 {
tof64!(rbinom(w64!(n), p64!(pp), rng)) as i32
} else {
n
});
n -= tof64!(rN[k]) as i32
} else {
rN[k] = r64!(0)
}
if n <= 0 {
return;
}
p_tot -= f128::new(prob[k]);
k += 1
}
rN[K - 1] = r64!(n);
}