use std::cmp::PartialOrd;
use std::ops::{Div, Mul, Sub};

#[inline]
pub fn min<T>(a: T, b: T) -> T
where
    T: PartialOrd,
{
    if a.lt(&b) {
        a
    } else {
        b
    }
}

#[inline]
pub fn max<T>(a: T, b: T) -> T
where
    T: PartialOrd,
{
    if a.gt(&b) {
        a
    } else {
        b
    }
}

#[inline]
pub fn sqr<T>(a: T) -> T
where
    T: Mul<T, Output = T> + Copy,
{
    a * a
}

#[inline]
pub fn clamp<T>(low: T, high: T, value: T) -> T
where
    T: PartialOrd,
{
    min(max(value, low), high)
}

#[inline]
pub fn linear_step<T>(low: T, high: T, value: T) -> T
where
    T: PartialOrd + Copy + Sub<T, Output = T> + Div<T, Output = T>,
{
    clamp(low, high, (value - low) / (high - low))
}

#[inline]
pub fn smooth_step<T>(low: T, high: T, value: T) -> T
where
    T: PartialOrd + Copy + Sub<T, Output = T> + Div<T, Output = T> + Mul<T, Output = T>,
    f32: Mul<T, Output = T> + Sub<T, Output = T>,
{
    let x = linear_step(low, high, value);

    x * x * (3.0 - 2.0 * x)
}
