import time

powerlaw_const = None

###
# Function/test to see the speed up of making values global so we dont have to calculate them each time
# Theres only a factor ~2 increase here.


def with_glob():
    global powerlaw_const
    if not powerlaw_const:
        # print('not defined')
        powerlaw_const = powerlaw_constant(10, 100, -2)
    else:
        # print('defined')
        return powerlaw_const


def without_glob():
    powerlaw_const = powerlaw_constant(10, 100, -2)
    return powerlaw_const


def powerlaw_constant(min_val, max_val, k):
    """
    Function that returns the constant to normalise a powerlaw
    """

    k1 = k + 1.0
    # print(
    #     "Powerlaw consts from {} to {}, k={} where k1={}".format(
    #         min_val, max_val, k, k1
    #     )
    # )

    global powerlaw_const
    powerlaw_const = k1 / (max_val ** k1 - min_val ** k1)
    return powerlaw_const


def powerlaw(min_val, max_val, k, x):
    """
    Single powerlaw with index k at x from min to max
    """

    # Handle faulty value
    if k == -1:
        print("wrong value for k")
        raise ValueError

    if (x < min_val) or (x > max_val):
        print("value is out of bounds")
        return 0

    else:
        powerlaw_const = powerlaw_constant(min_val, max_val, k)

        # powerlaw
        y = powerlaw_const * (x ** k)
        # print(y)
        # print(
        #     "Power law from {} to {}: const = {}, y = {}".format(
        #         min_val, max_val, const, y
        #     )
        # )
        return y


def powerlaw_with(min_val, max_val, k, x):
    """
    Single powerlaw with index k at x from min to max
    """

    # Handle faulty value
    if k == -1:
        print("wrong value for k")
        raise ValueError

    if (x < min_val) or (x > max_val):
        return 0

    else:
        global powerlaw_const
        if not powerlaw_const:
            powerlaw_const = powerlaw_constant(min_val, max_val, k)

        # powerlaw
        y = powerlaw_const * (x ** k)
        # print(
        #     "Power law from {} to {}: const = {}, y = {}".format(
        #         min_val, max_val, const, y
        #     )
        # )
        return y


steps = 1000000

start_time_without_glob = time.time()
for i in range(steps):
    powerlaw(10, 100, -2, 20)
stop_time_without_glob = time.time()

start_time_with_glob = time.time()
for i in range(steps):
    powerlaw_with(10, 100, -2, 20)
stop_time_with_glob = time.time()

total_time_without = stop_time_without_glob - start_time_without_glob
total_time_with = stop_time_with_glob - start_time_with_glob

print(
    "without: {}\nwith: {}\nRatio: {}".format(
        total_time_without, total_time_with, total_time_without / total_time_with
    )
)