package goja

import (
	
)

var mapExportType = reflect.TypeOf([][2]interface{}{})

type mapObject struct {
	baseObject
	m *orderedMap
}

type mapIterObject struct {
	baseObject
	iter *orderedMapIter
	kind iterationKind
}

func ( *mapIterObject) () Value {
	if .iter == nil {
		return .val.runtime.createIterResultObject(_undefined, true)
	}

	 := .iter.next()
	if  == nil {
		.iter = nil
		return .val.runtime.createIterResultObject(_undefined, true)
	}

	var  Value
	switch .kind {
	case iterationKindKey:
		 = .key
	case iterationKindValue:
		 = .value
	default:
		 = .val.runtime.newArrayValues([]Value{.key, .value})
	}

	return .val.runtime.createIterResultObject(, false)
}

func ( *mapObject) () {
	.baseObject.init()
	.m = newOrderedMap(.val.runtime.getHash())
}

func ( *mapObject) () reflect.Type {
	return mapExportType
}

func ( *mapObject) ( *objectExportCtx) interface{} {
	 := make([][2]interface{}, .m.size)
	.put(.val, )

	 := .m.newIter()
	for  := 0;  < len(); ++ {
		 := .next()
		if  == nil {
			break
		}
		[][0] = exportValue(.key, )
		[][1] = exportValue(.value, )
	}

	return 
}

func ( *mapObject) ( reflect.Value,  reflect.Type,  *objectExportCtx) error {
	.Set(reflect.MakeMap())
	.putTyped(.val, , .Interface())
	 := .Key()
	 := .Elem()
	 := .m.newIter()
	 := .val.runtime
	for {
		 := .next()
		if  == nil {
			break
		}
		 := reflect.New().Elem()
		 := .toReflectValue(.key, , )
		if  != nil {
			return 
		}
		 := reflect.New().Elem()
		 = .toReflectValue(.value, , )
		if  != nil {
			return 
		}
		.SetMapIndex(, )
	}
	return nil
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toObject(.This)
	,  := .self.(*mapObject)
	if ! {
		panic(.NewTypeError("Method Map.prototype.clear called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: })))
	}

	.m.clear()

	return _undefined
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toObject(.This)
	,  := .self.(*mapObject)
	if ! {
		panic(.NewTypeError("Method Map.prototype.delete called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: })))
	}

	return .toBoolean(.m.remove(.Argument(0)))
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toObject(.This)
	,  := .self.(*mapObject)
	if ! {
		panic(.NewTypeError("Method Map.prototype.get called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: })))
	}

	return nilSafe(.m.get(.Argument(0)))
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toObject(.This)
	,  := .self.(*mapObject)
	if ! {
		panic(.NewTypeError("Method Map.prototype.has called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: })))
	}
	if .m.has(.Argument(0)) {
		return valueTrue
	}
	return valueFalse
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toObject(.This)
	,  := .self.(*mapObject)
	if ! {
		panic(.NewTypeError("Method Map.prototype.set called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: })))
	}
	.m.set(.Argument(0), .Argument(1))
	return .This
}

func ( *Runtime) ( FunctionCall) Value {
	return .createMapIterator(.This, iterationKindKeyValue)
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toObject(.This)
	,  := .self.(*mapObject)
	if ! {
		panic(.NewTypeError("Method Map.prototype.forEach called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: })))
	}
	,  := .toObject(.Argument(0)).self.assertCallable()
	if ! {
		panic(.NewTypeError("object is not a function %s"))
	}
	 := .Argument(1)
	 := .m.newIter()
	for {
		 := .next()
		if  == nil {
			break
		}
		(FunctionCall{This: , Arguments: []Value{.value, .key, }})
	}

	return _undefined
}

func ( *Runtime) ( FunctionCall) Value {
	return .createMapIterator(.This, iterationKindKey)
}

func ( *Runtime) ( FunctionCall) Value {
	return .createMapIterator(.This, iterationKindValue)
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toObject(.This)
	,  := .self.(*mapObject)
	if ! {
		panic(.NewTypeError("Method get Map.prototype.size called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: })))
	}
	return intToValue(int64(.m.size))
}

func ( *Runtime) ( []Value,  *Object) *Object {
	if  == nil {
		panic(.needNew("Map"))
	}
	 := .getPrototypeFromCtor(, .global.Map, .global.MapPrototype)
	 := &Object{runtime: }

	 := &mapObject{}
	.class = classObject
	.val = 
	.extensible = true
	.self = 
	.prototype = 
	.init()
	if len() > 0 {
		if  := [0];  != nil &&  != _undefined &&  != _null {
			 := .getStr("set", nil)
			 := toMethod()
			if  == nil {
				panic(.NewTypeError("Map.set in missing"))
			}
			 := .getIterator(, nil)
			 := valueInt(0)
			 := valueInt(1)
			if  == .global.mapAdder {
				.iterate(func( Value) {
					 := .toObject()
					 := nilSafe(.self.getIdx(, nil))
					 := nilSafe(.self.getIdx(, nil))
					.m.set(, )
				})
			} else {
				.iterate(func( Value) {
					 := .toObject()
					 := .self.getIdx(, nil)
					 := .self.getIdx(, nil)
					(FunctionCall{This: , Arguments: []Value{, }})
				})
			}
		}
	}
	return 
}

func ( *Runtime) ( Value,  iterationKind) Value {
	 := .toObject()
	,  := .self.(*mapObject)
	if ! {
		panic(.NewTypeError("Object is not a Map"))
	}

	 := &Object{runtime: }

	 := &mapIterObject{
		iter: .m.newIter(),
		kind: ,
	}
	.class = classObject
	.val = 
	.extensible = true
	.self = 
	.prototype = .getMapIteratorPrototype()
	.init()

	return 
}

func ( *Runtime) ( FunctionCall) Value {
	 := .toObject(.This)
	if ,  := .self.(*mapIterObject);  {
		return .next()
	}
	panic(.NewTypeError("Method Map Iterator.prototype.next called on incompatible receiver %s", .objectproto_toString(FunctionCall{This: })))
}

func ( *Runtime) ( *Object) objectImpl {
	 := newBaseObjectObj(, .global.ObjectPrototype, classObject)

	._putProp("constructor", .getMap(), true, false, true)
	._putProp("clear", .newNativeFunc(.mapProto_clear, "clear", 0), true, false, true)
	.global.mapAdder = .newNativeFunc(.mapProto_set, "set", 2)
	._putProp("set", .global.mapAdder, true, false, true)
	._putProp("delete", .newNativeFunc(.mapProto_delete, "delete", 1), true, false, true)
	._putProp("forEach", .newNativeFunc(.mapProto_forEach, "forEach", 1), true, false, true)
	._putProp("has", .newNativeFunc(.mapProto_has, "has", 1), true, false, true)
	._putProp("get", .newNativeFunc(.mapProto_get, "get", 1), true, false, true)
	.setOwnStr("size", &valueProperty{
		getterFunc:   .newNativeFunc(.mapProto_getSize, "get size", 0),
		accessor:     true,
		writable:     true,
		configurable: true,
	}, true)
	._putProp("keys", .newNativeFunc(.mapProto_keys, "keys", 0), true, false, true)
	._putProp("values", .newNativeFunc(.mapProto_values, "values", 0), true, false, true)

	 := .newNativeFunc(.mapProto_entries, "entries", 0)
	._putProp("entries", , true, false, true)
	._putSym(SymIterator, valueProp(, true, false, true))
	._putSym(SymToStringTag, valueProp(asciiString(classMap), false, false, true))

	return 
}

func ( *Runtime) ( *Object) objectImpl {
	 := .newNativeConstructOnly(, .builtin_newMap, .getMapPrototype(), "Map", 0)
	.putSpeciesReturnThis()

	return 
}

func ( *Runtime) ( *Object) objectImpl {
	 := newBaseObjectObj(, .getIteratorPrototype(), classObject)

	._putProp("next", .newNativeFunc(.mapIterProto_next, "next", 0), true, false, true)
	._putSym(SymToStringTag, valueProp(asciiString(classMapIterator), false, false, true))

	return 
}

func ( *Runtime) () *Object {
	var  *Object
	if  = .global.MapIteratorPrototype;  == nil {
		 = &Object{runtime: }
		.global.MapIteratorPrototype = 
		.self = .createMapIterProto()
	}
	return 
}

func ( *Runtime) () *Object {
	 := .global.MapPrototype
	if  == nil {
		 = &Object{runtime: }
		.global.MapPrototype = 
		.self = .createMapProto()
	}
	return 
}

func ( *Runtime) () *Object {
	 := .global.Map
	if  == nil {
		 = &Object{runtime: }
		.global.Map = 
		.self = .createMap()
	}
	return 
}