package goja

import (
	
	

	
)

func ( *Runtime) ( Value) Value {
	switch t := .(type) {
	case valueFloat, valueInt:
		return 
	case *Object:
		switch t := .self.(type) {
		case *primitiveValueObject:
			return .(.pValue)
		case *objectGoReflect:
			if .class == classNumber && .valueOf != nil {
				return .valueOf()
			}
		}
		if  == .global.NumberPrototype {
			return _positiveZero
		}
	}
	panic(.NewTypeError("Value is not a number: %s", ))
}

func ( *Runtime) ( FunctionCall) Value {
	return .toNumber(.This)
}

func ( *Runtime) ( FunctionCall) Value {
	var  Value
	switch t := .This.(type) {
	case valueFloat, valueInt:
		 = 
	case *Object:
		switch t := .self.(type) {
		case *primitiveValueObject:
			 = .toNumber(.pValue)
		case *objectGoReflect:
			if .class == classNumber {
				if .toString != nil {
					return .toString()
				}
				if .valueOf != nil {
					 = .valueOf()
				}
			}
		}
		if  == .global.NumberPrototype {
			return asciiString("0")
		}
	}
	if  == nil {
		panic(.NewTypeError("Value is not a number"))
	}
	var  int
	if  := .Argument(0);  != _undefined {
		 = int(.ToInteger())
	} else {
		 = 10
	}

	if  < 2 ||  > 36 {
		panic(.newError(.getRangeError(), "toString() radix argument must be between 2 and 36"))
	}

	 := .ToFloat()

	if math.IsNaN() {
		return stringNaN
	}

	if math.IsInf(, 1) {
		return stringInfinity
	}

	if math.IsInf(, -1) {
		return stringNegInfinity
	}

	if  == 10 {
		return asciiString(fToStr(, ftoa.ModeStandard, 0))
	}

	return asciiString(ftoa.FToBaseStr(, ))
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toNumber(.This).ToFloat()
	 := .Argument(0).ToInteger()

	if  < 0 ||  > 100 {
		panic(.newError(.getRangeError(), "toFixed() precision must be between 0 and 100"))
	}
	if math.IsNaN() {
		return stringNaN
	}
	return asciiString(fToStr(, ftoa.ModeFixed, int()))
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toNumber(.This).ToFloat()
	 := .Argument(0)
	var  int64
	if  == _undefined {
		return asciiString(fToStr(, ftoa.ModeStandardExponential, 0))
	} else {
		 = .ToInteger()
	}

	if math.IsNaN() {
		return stringNaN
	}
	if math.IsInf(, 1) {
		return stringInfinity
	}
	if math.IsInf(, -1) {
		return stringNegInfinity
	}

	if  < 0 ||  > 100 {
		panic(.newError(.getRangeError(), "toExponential() precision must be between 0 and 100"))
	}

	return asciiString(fToStr(, ftoa.ModeExponential, int(+1)))
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toNumber(.This)
	 := .Argument(0)
	if  == _undefined {
		return .toString()
	}
	 := .ToFloat()
	 := .ToInteger()

	if math.IsNaN() {
		return stringNaN
	}
	if math.IsInf(, 1) {
		return stringInfinity
	}
	if math.IsInf(, -1) {
		return stringNegInfinity
	}
	if  < 1 ||  > 100 {
		panic(.newError(.getRangeError(), "toPrecision() precision must be between 1 and 100"))
	}

	return asciiString(fToStr(, ftoa.ModePrecision, int()))
}

func ( *Runtime) ( FunctionCall) Value {
	switch arg := .Argument(0).(type) {
	case valueInt:
		return valueTrue
	case valueFloat:
		 := float64()
		return .toBoolean(!math.IsInf(, 0) && !math.IsNaN())
	default:
		return valueFalse
	}
}

func ( *Runtime) ( FunctionCall) Value {
	switch arg := .Argument(0).(type) {
	case valueInt:
		return valueTrue
	case valueFloat:
		 := float64()
		return .toBoolean(!math.IsNaN() && !math.IsInf(, 0) && math.Floor() == )
	default:
		return valueFalse
	}
}

func ( *Runtime) ( FunctionCall) Value {
	if ,  := .Argument(0).(valueFloat);  && math.IsNaN(float64()) {
		return valueTrue
	}
	return valueFalse
}

func ( *Runtime) ( FunctionCall) Value {
	 := .Argument(0)
	if ,  := .(valueInt);  &&  >= -(maxInt-1) &&  <= maxInt-1 {
		return valueTrue
	}
	if  == _negativeZero {
		return valueTrue
	}
	return valueFalse
}

func createNumberProtoTemplate() *objectTemplate {
	 := newObjectTemplate()
	.protoFactory = func( *Runtime) *Object {
		return .global.ObjectPrototype
	}

	.putStr("constructor", func( *Runtime) Value { return valueProp(.getNumber(), true, false, true) })

	.putStr("toExponential", func( *Runtime) Value { return .methodProp(.numberproto_toExponential, "toExponential", 1) })
	.putStr("toFixed", func( *Runtime) Value { return .methodProp(.numberproto_toFixed, "toFixed", 1) })
	.putStr("toLocaleString", func( *Runtime) Value { return .methodProp(.numberproto_toString, "toLocaleString", 0) })
	.putStr("toPrecision", func( *Runtime) Value { return .methodProp(.numberproto_toPrecision, "toPrecision", 1) })
	.putStr("toString", func( *Runtime) Value { return .methodProp(.numberproto_toString, "toString", 1) })
	.putStr("valueOf", func( *Runtime) Value { return .methodProp(.numberproto_valueOf, "valueOf", 0) })

	return 
}

var numberProtoTemplate *objectTemplate
var numberProtoTemplateOnce sync.Once

func getNumberProtoTemplate() *objectTemplate {
	numberProtoTemplateOnce.Do(func() {
		numberProtoTemplate = createNumberProtoTemplate()
	})
	return numberProtoTemplate
}

func ( *Runtime) () *Object {
	 := .global.NumberPrototype
	if  == nil {
		 = &Object{runtime: }
		.global.NumberPrototype = 
		 := .newTemplatedObject(getNumberProtoTemplate(), )
		.class = classNumber
	}
	return 
}

func ( *Runtime) () *Object {
	 := .global.parseFloat
	if  == nil {
		 = .newNativeFunc(.builtin_parseFloat, "parseFloat", 1)
		.global.parseFloat = 
	}
	return 
}

func ( *Runtime) () *Object {
	 := .global.parseInt
	if  == nil {
		 = .newNativeFunc(.builtin_parseInt, "parseInt", 2)
		.global.parseInt = 
	}
	return 
}

func createNumberTemplate() *objectTemplate {
	 := newObjectTemplate()
	.protoFactory = func( *Runtime) *Object {
		return .getFunctionPrototype()
	}
	.putStr("length", func( *Runtime) Value { return valueProp(intToValue(1), false, false, true) })
	.putStr("name", func( *Runtime) Value { return valueProp(asciiString("Number"), false, false, true) })

	.putStr("prototype", func( *Runtime) Value { return valueProp(.getNumberPrototype(), false, false, false) })

	.putStr("EPSILON", func( *Runtime) Value { return valueProp(_epsilon, false, false, false) })
	.putStr("isFinite", func( *Runtime) Value { return .methodProp(.number_isFinite, "isFinite", 1) })
	.putStr("isInteger", func( *Runtime) Value { return .methodProp(.number_isInteger, "isInteger", 1) })
	.putStr("isNaN", func( *Runtime) Value { return .methodProp(.number_isNaN, "isNaN", 1) })
	.putStr("isSafeInteger", func( *Runtime) Value { return .methodProp(.number_isSafeInteger, "isSafeInteger", 1) })
	.putStr("MAX_SAFE_INTEGER", func( *Runtime) Value { return valueProp(valueInt(maxInt-1), false, false, false) })
	.putStr("MIN_SAFE_INTEGER", func( *Runtime) Value { return valueProp(valueInt(-(maxInt - 1)), false, false, false) })
	.putStr("MIN_VALUE", func( *Runtime) Value { return valueProp(valueFloat(math.SmallestNonzeroFloat64), false, false, false) })
	.putStr("MAX_VALUE", func( *Runtime) Value { return valueProp(valueFloat(math.MaxFloat64), false, false, false) })
	.putStr("NaN", func( *Runtime) Value { return valueProp(_NaN, false, false, false) })
	.putStr("NEGATIVE_INFINITY", func( *Runtime) Value { return valueProp(_negativeInf, false, false, false) })
	.putStr("parseFloat", func( *Runtime) Value { return valueProp(.getParseFloat(), true, false, true) })
	.putStr("parseInt", func( *Runtime) Value { return valueProp(.getParseInt(), true, false, true) })
	.putStr("POSITIVE_INFINITY", func( *Runtime) Value { return valueProp(_positiveInf, false, false, false) })

	return 
}

var numberTemplate *objectTemplate
var numberTemplateOnce sync.Once

func getNumberTemplate() *objectTemplate {
	numberTemplateOnce.Do(func() {
		numberTemplate = createNumberTemplate()
	})
	return numberTemplate
}

func ( *Runtime) () *Object {
	 := .global.Number
	if  == nil {
		 = &Object{runtime: }
		.global.Number = 
		.newTemplatedFuncObject(getNumberTemplate(), , .builtin_Number,
			.wrapNativeConstruct(.builtin_newNumber, , .getNumberPrototype()))
	}
	return 
}