from packaging.version import Version, parse

import numpy as np
import scipy

SP_VERSION = parse(scipy.__version__)
SP_LT_15 = SP_VERSION < Version("1.4.99")
SCIPY_GT_14 = not SP_LT_15
SP_LT_16 = SP_VERSION < Version("1.5.99")
SP_LT_19 = SP_VERSION < Version("1.8.99")


def _next_regular(target):
    """
    Find the next regular number greater than or equal to target.
    Regular numbers are composites of the prime factors 2, 3, and 5.
    Also known as 5-smooth numbers or Hamming numbers, these are the optimal
    size for inputs to FFTPACK.

    Target must be a positive integer.
    """
    if target <= 6:
        return target

    # Quickly check if it's already a power of 2
    if not (target & (target - 1)):
        return target

    match = float("inf")  # Anything found will be smaller
    p5 = 1
    while p5 < target:
        p35 = p5
        while p35 < target:
            # Ceiling integer division, avoiding conversion to float
            # (quotient = ceil(target / p35))
            quotient = -(-target // p35)
            # Quickly find next power of 2 >= quotient
            p2 = 2 ** ((quotient - 1).bit_length())

            N = p2 * p35
            if N == target:
                return N
            elif N < match:
                match = N
            p35 *= 3
            if p35 == target:
                return p35
        if p35 < match:
            match = p35
        p5 *= 5
        if p5 == target:
            return p5
    if p5 < match:
        match = p5
    return match


def _valarray(shape, value=np.nan, typecode=None):
    """Return an array of all value."""

    out = np.ones(shape, dtype=bool) * value
    if typecode is not None:
        out = out.astype(typecode)
    if not isinstance(out, np.ndarray):
        out = np.asarray(out)
    return out


if SP_LT_16:
    # copied from scipy, added to scipy in 1.6.0
    from ._scipy_multivariate_t import multivariate_t  # noqa: F401
else:
    from scipy.stats import multivariate_t  # noqa: F401
