from ..base import *
import math
import random

Math = PyJsObject(prototype=ObjectPrototype)
Math.Class = 'Math'

CONSTANTS = {'E': 2.7182818284590452354,
             'LN10': 2.302585092994046,
             'LN2': 0.6931471805599453,
             'LOG2E': 1.4426950408889634,
             'LOG10E': 0.4342944819032518,
             'PI': 3.1415926535897932,
             'SQRT1_2': 0.7071067811865476,
             'SQRT2': 1.4142135623730951}

for constant, value in CONSTANTS.items():
    Math.define_own_property(constant, {'value': Js(value),
                                        'writable': False,
                                        'enumerable': False,
                                        'configurable': False})

class MathFunctions:
    def abs(x):
        a = x.to_number().value
        if a!=a: # it must be a nan
            return NaN
        return abs(a)

    def acos(x):
        a = x.to_number().value
        if a!=a: # it must be a nan
            return NaN
        try:
            return math.acos(a)
        except:
            return NaN

    def asin(x):
        a = x.to_number().value
        if a!=a: # it must be a nan
            return NaN
        try:
            return math.asin(a)
        except:
            return NaN

    def atan(x):
        a = x.to_number().value
        if a!=a: # it must be a nan
            return NaN
        return math.atan(a)

    def atan2(y, x):
        a = x.to_number().value
        b = y.to_number().value
        if a!=a or b!=b: # it must be a nan
            return NaN
        return math.atan2(b, a)

    def ceil(x):
        a = x.to_number().value
        if a!=a: # it must be a nan
            return NaN
        return math.ceil(a)

    def floor(x):
        a = x.to_number().value
        if a!=a: # it must be a nan
            return NaN
        return math.floor(a)

    def round(x):
        a = x.to_number().value
        if a!=a: # it must be a nan
            return NaN
        return round(a)

    def sin(x):
        a = x.to_number().value
        if a!=a: # it must be a nan
            return NaN
        return math.sin(a)

    def cos(x):
        a = x.to_number().value
        if a!=a: # it must be a nan
            return NaN
        return  math.cos(a)

    def tan(x):
        a = x.to_number().value
        if a!=a: # it must be a nan
            return NaN
        return math.tan(a)

    def log(x):
        a = x.to_number().value
        if a!=a: # it must be a nan
            return NaN
        try:
            return math.log(a)
        except:
            return NaN

    def exp(x):
        a = x.to_number().value
        if a!=a: # it must be a nan
            return NaN
        return math.exp(a)

    def pow(x, y):
        a = x.to_number().value
        b = y.to_number().value
        if a!=a or b!=b: # it must be a nan
            return NaN
        try:
            return a**b
        except:
            return NaN

    def sqrt(x):
        a = x.to_number().value
        if a!=a: # it must be a nan
            return NaN
        try:
            return a**0.5
        except:
            return NaN

    def min():
        if not len(arguments):
            return -Infinity
        lis = tuple(e.to_number().value for e in arguments.to_list())
        if any(e!=e for e in lis): # we dont want NaNs
            return NaN
        return min(*lis)

    def max():
        if not len(arguments):
            return -Infinity
        lis = tuple(e.to_number().value for e in arguments.to_list())
        if any(e!=e for e in lis): # we dont want NaNs
            return NaN
        return max(*lis)

    def random():
        return random.random()


fill_prototype(Math, MathFunctions, default_attrs)