package goja

import (
	
	
)

var setExportType = reflectTypeArray

type setObject struct {
	baseObject
	m *orderedMap
}

type setIterObject struct {
	baseObject
	iter *orderedMapIter
	kind iterationKind
}

func ( *setIterObject) () 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 iterationKindValue:
		 = .key
	default:
		 = .val.runtime.newArrayValues([]Value{.key, .key})
	}

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

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

func ( *setObject) () reflect.Type {
	return setExportType
}

func ( *setObject) ( *objectExportCtx) interface{} {
	 := make([]interface{}, .m.size)
	.put(.val, )
	 := .m.newIter()
	for  := 0;  < len(); ++ {
		 := .next()
		if  == nil {
			break
		}
		[] = exportValue(.key, )
	}
	return 
}

func ( *setObject) ( reflect.Value,  reflect.Type,  *objectExportCtx) error {
	 := .m.size
	if .Kind() == reflect.Array {
		if .Len() !=  {
			return fmt.Errorf("cannot convert a Set into an array, lengths mismatch: have %d, need %d)", , .Len())
		}
	} else {
		.Set(reflect.MakeSlice(, , ))
	}
	.putTyped(.val, , .Interface())
	 := .m.newIter()
	 := .val.runtime
	for  := 0;  < ; ++ {
		 := .next()
		if  == nil {
			break
		}
		 := .toReflectValue(.key, .Index(), )
		if  != nil {
			return 
		}
	}
	return nil
}

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

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

	.m.set(.Argument(0), nil)
	return .This
}

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

	.m.clear()
	return _undefined
}

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

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

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

func ( *Runtime) ( FunctionCall) Value {
	 := .toObject(.This)
	,  := .self.(*setObject)
	if ! {
		panic(.NewTypeError("Method Set.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{.key, .key, }})
	}

	return _undefined
}

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

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

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

	return intToValue(int64(.m.size))
}

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

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

	 := &setObject{}
	.class = classObject
	.val = 
	.extensible = true
	.self = 
	.prototype = 
	.init()
	if len() > 0 {
		if  := [0];  != nil &&  != _undefined &&  != _null {
			 := .getStr("add", nil)
			 := .checkStdArrayIter()
			if  == .global.setAdder {
				if  != nil {
					for ,  := range .values {
						.m.set(, nil)
					}
				} else {
					.getIterator(, nil).iterate(func( Value) {
						.m.set(, nil)
					})
				}
			} else {
				 := toMethod()
				if  == nil {
					panic(.NewTypeError("Set.add in missing"))
				}
				if  != nil {
					for ,  := range .values {
						(FunctionCall{This: , Arguments: []Value{}})
					}
				} else {
					.getIterator(, nil).iterate(func( Value) {
						(FunctionCall{This: , Arguments: []Value{}})
					})
				}
			}
		}
	}
	return 
}

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

	 := &Object{runtime: }

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

	return 
}

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

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

	._putProp("constructor", .getSet(), true, false, true)
	.global.setAdder = .newNativeFunc(.setProto_add, "add", 1)
	._putProp("add", .global.setAdder, true, false, true)

	._putProp("clear", .newNativeFunc(.setProto_clear, "clear", 0), true, false, true)
	._putProp("delete", .newNativeFunc(.setProto_delete, "delete", 1), true, false, true)
	._putProp("forEach", .newNativeFunc(.setProto_forEach, "forEach", 1), true, false, true)
	._putProp("has", .newNativeFunc(.setProto_has, "has", 1), true, false, true)
	.setOwnStr("size", &valueProperty{
		getterFunc:   .newNativeFunc(.setProto_getSize, "get size", 0),
		accessor:     true,
		writable:     true,
		configurable: true,
	}, true)

	 := .newNativeFunc(.setProto_values, "values", 0)
	._putProp("values", , true, false, true)
	._putProp("keys", , true, false, true)
	._putProp("entries", .newNativeFunc(.setProto_entries, "entries", 0), true, false, true)
	._putSym(SymIterator, valueProp(, true, false, true))
	._putSym(SymToStringTag, valueProp(asciiString(classSet), false, false, true))

	return 
}

func ( *Runtime) ( *Object) objectImpl {
	 := .newNativeConstructOnly(, .builtin_newSet, .getSetPrototype(), "Set", 0)
	.putSpeciesReturnThis()

	return 
}

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

	._putProp("next", .newNativeFunc(.setIterProto_next, "next", 0), true, false, true)
	._putSym(SymToStringTag, valueProp(asciiString(classSetIterator), false, false, true))

	return 
}

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

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

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