import six
if six.PY3:
    basestring = str
    long = int
    xrange = range
    unicode = str


RADIX_SYMBOLS = {0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9',
                 10: 'a', 11: 'b', 12: 'c', 13: 'd', 14: 'e', 15: 'f', 16: 'g', 17: 'h', 18: 'i', 19: 'j', 20: 'k',
                 21: 'l', 22: 'm', 23: 'n', 24: 'o', 25: 'p', 26: 'q', 27: 'r', 28: 's', 29: 't', 30: 'u', 31: 'v',
                 32: 'w', 33: 'x', 34: 'y', 35: 'z'}


def to_str_rep(num):
    if num.is_nan():
        return num.Js('NaN')
    elif num.is_infinity():
        sign = '-' if num.value<0 else ''
        return num.Js(sign+'Infinity')
    elif isinstance(num.value, (long, int)) or num.value.is_integer():  # dont print .0
        return num.Js(unicode(int(num.value)))
    return num.Js(unicode(num.value)) # accurate enough


class NumberPrototype:
    def toString(radix):
        if this.Class!='Number':
            raise this.MakeError('TypeError', 'Number.prototype.valueOf is not generic')
        if radix.is_undefined():
            return to_str_rep(this)
        r = radix.to_int()
        if r==10:
            return to_str_rep(this)
        if r not in xrange(2, 37): 
            raise this.MakeError('RangeError', 'Number.prototype.toString() radix argument must be between 2 and 36')
        num = this.to_int()
        if num < 0:
            num = -num
            sign = '-'
        else:
            sign = ''
        res = ''
        while num:
            s = RADIX_SYMBOLS[num % r]
            num = num // r
            res = s + res
        return sign + (res if res else '0')

    def valueOf():
        if this.Class!='Number':
            raise this.MakeError('TypeError', 'Number.prototype.valueOf is not generic')
        return this.value

    def toLocaleString():
        return this.to_string()

    def toFixed (fractionDigits):
        if this.Class!='Number':
            raise this.MakeError('TypeError', 'Number.prototype.toFixed called on incompatible receiver')
        digs = fractionDigits.to_int()
        if digs<0 or digs>20:
            raise this.MakeError('RangeError', 'toFixed() digits argument must be between 0 and 20')
        elif this.is_infinity():
            return 'Infinity' if this.value>0 else '-Infinity'
        elif this.is_nan():
            return 'NaN'
        return format(this.value, '-.%df'%digs)


    def toExponential (fractionDigits):
        if this.Class!='Number':
            raise this.MakeError('TypeError', 'Number.prototype.toExponential called on incompatible receiver')
        digs = fractionDigits.to_int()
        if digs<0 or digs>20:
            raise this.MakeError('RangeError', 'toFixed() digits argument must be between 0 and 20')
        elif this.is_infinity():
            return 'Infinity' if this.value>0 else '-Infinity'
        elif this.is_nan():
            return 'NaN'
        return format(this.value, '-.%de'%digs)

    def toPrecision (precision):
        if this.Class!='Number':
            raise this.MakeError('TypeError', 'Number.prototype.toPrecision called on incompatible receiver')
        if precision.is_undefined():
            return this.to_string()
        prec = precision.to_int()
        if this.is_nan():
            return 'NaN'
        elif this.is_infinity():
            return 'Infinity' if this.value>0 else '-Infinity'
        digs = prec - len(str(int(this.value)))
        if digs>=0:
            return format(this.value, '-.%df'%digs)
        else:
            return format(this.value, '-.%df'%(prec-1))



