import numpy as np
import numpy.random as random


class Uniform:
    def __init__(self, lower_limits, upper_limits):
        self.lower_limits = lower_limits
        self.upper_limits = upper_limits

    def generate(self, number):
        assert isinstance(number, int)
        arrays = []
        for limits in zip(self.lower_limits, self.upper_limits):
            lower, upper = limits
            arrays.append(random.uniform(lower, upper, number))
        return np.vstack(arrays)


class Deterministic(object):
    def __init__(self, orientation):
        self.orientation = orientation

    def generate(self, number):
        return np.repeat(np.expand_dims(self.orientation, axis=1), number, axis=1)


class UniformOrientation:
    def __init__(self, lower_altidude, upper_altidude, lower_azimuth, upper_azimuth):
        self.angle_distribution = Uniform(np.array([lower_altidude, lower_azimuth]),
                                          np.array([upper_altidude, upper_azimuth]))

    def generate(self, number):
        angles = self.angle_distribution.generate(number)
        altidudes = angles[0, :]
        azimuths = angles[1, :]
        x = np.cos(altidudes) * np.cos(azimuths)
        y = np.cos(altidudes) * np.sin(azimuths)
        z = np.sin(altidudes)
        return np.vstack((x, y, z))
