"""
Array Primitives Library

Vectorized operations on numpy arrays for coordinate transformations.
"""
import numpy as np


# Arithmetic
def prim_arr_add(a, b):
    return np.add(a, b)


def prim_arr_sub(a, b):
    return np.subtract(a, b)


def prim_arr_mul(a, b):
    return np.multiply(a, b)


def prim_arr_div(a, b):
    return np.divide(a, b)


def prim_arr_mod(a, b):
    return np.mod(a, b)


def prim_arr_neg(a):
    return np.negative(a)


# Math functions
def prim_arr_sin(a):
    return np.sin(a)


def prim_arr_cos(a):
    return np.cos(a)


def prim_arr_tan(a):
    return np.tan(a)


def prim_arr_sqrt(a):
    return np.sqrt(np.maximum(a, 0))


def prim_arr_pow(a, b):
    return np.power(a, b)


def prim_arr_abs(a):
    return np.abs(a)


def prim_arr_exp(a):
    return np.exp(a)


def prim_arr_log(a):
    return np.log(np.maximum(a, 1e-10))


def prim_arr_atan2(y, x):
    return np.arctan2(y, x)


# Comparison / selection
def prim_arr_min(a, b):
    return np.minimum(a, b)


def prim_arr_max(a, b):
    return np.maximum(a, b)


def prim_arr_clip(a, lo, hi):
    return np.clip(a, lo, hi)


def prim_arr_where(cond, a, b):
    return np.where(cond, a, b)


def prim_arr_floor(a):
    return np.floor(a)


def prim_arr_ceil(a):
    return np.ceil(a)


def prim_arr_round(a):
    return np.round(a)


# Interpolation
def prim_arr_lerp(a, b, t):
    return a + (b - a) * t


def prim_arr_smoothstep(edge0, edge1, x):
    t = prim_arr_clip((x - edge0) / (edge1 - edge0), 0.0, 1.0)
    return t * t * (3 - 2 * t)


# Creation
def prim_arr_zeros(shape):
    return np.zeros(shape, dtype=np.float32)


def prim_arr_ones(shape):
    return np.ones(shape, dtype=np.float32)


def prim_arr_full(shape, value):
    return np.full(shape, value, dtype=np.float32)


def prim_arr_arange(start, stop, step=1):
    return np.arange(start, stop, step, dtype=np.float32)


def prim_arr_linspace(start, stop, num):
    return np.linspace(start, stop, num, dtype=np.float32)


def prim_arr_meshgrid(x, y):
    return np.meshgrid(x, y)


# Coordinate transforms
def prim_polar_from_center(map_x, map_y, cx, cy):
    """Convert Cartesian to polar coordinates centered at (cx, cy)."""
    dx = map_x - cx
    dy = map_y - cy
    r = np.sqrt(dx**2 + dy**2)
    theta = np.arctan2(dy, dx)
    return (r, theta)


def prim_cart_from_polar(r, theta, cx, cy):
    """Convert polar to Cartesian, adding center offset."""
    x = r * np.cos(theta) + cx
    y = r * np.sin(theta) + cy
    return (x, y)


PRIMITIVES = {
    # Arithmetic
    'arr+': prim_arr_add,
    'arr-': prim_arr_sub,
    'arr*': prim_arr_mul,
    'arr/': prim_arr_div,
    'arr-mod': prim_arr_mod,
    'arr-neg': prim_arr_neg,

    # Math
    'arr-sin': prim_arr_sin,
    'arr-cos': prim_arr_cos,
    'arr-tan': prim_arr_tan,
    'arr-sqrt': prim_arr_sqrt,
    'arr-pow': prim_arr_pow,
    'arr-abs': prim_arr_abs,
    'arr-exp': prim_arr_exp,
    'arr-log': prim_arr_log,
    'arr-atan2': prim_arr_atan2,

    # Selection
    'arr-min': prim_arr_min,
    'arr-max': prim_arr_max,
    'arr-clip': prim_arr_clip,
    'arr-where': prim_arr_where,
    'arr-floor': prim_arr_floor,
    'arr-ceil': prim_arr_ceil,
    'arr-round': prim_arr_round,

    # Interpolation
    'arr-lerp': prim_arr_lerp,
    'arr-smoothstep': prim_arr_smoothstep,

    # Creation
    'arr-zeros': prim_arr_zeros,
    'arr-ones': prim_arr_ones,
    'arr-full': prim_arr_full,
    'arr-arange': prim_arr_arange,
    'arr-linspace': prim_arr_linspace,
    'arr-meshgrid': prim_arr_meshgrid,

    # Coordinates
    'polar-from-center': prim_polar_from_center,
    'cart-from-polar': prim_cart_from_polar,
}
