package goja

import (
	
	

	
)

type objectGoMapReflect struct {
	objectGoReflect

	keyType, valueType reflect.Type
}

func ( *objectGoMapReflect) () {
	.objectGoReflect.init()
	.keyType = .fieldsValue.Type().Key()
	.valueType = .fieldsValue.Type().Elem()
}

func ( *objectGoMapReflect) ( Value,  bool) reflect.Value {
	 := reflect.New(.keyType).Elem()
	 := .val.runtime.toReflectValue(, , &objectExportCtx{})
	if  != nil {
		.val.runtime.typeErrorResult(, "map key conversion error: %v", )
		return reflect.Value{}
	}
	return 
}

func ( *objectGoMapReflect) ( string,  bool) reflect.Value {
	if .keyType.Kind() == reflect.String {
		return reflect.ValueOf().Convert(.keyType)
	}
	return .toKey(newStringValue(), )
}

func ( *objectGoMapReflect) ( reflect.Value) Value {
	if !.IsValid() {
		return nil
	}
	if  := .fieldsValue.MapIndex(); .IsValid() {
		 := 
		if .Kind() == reflect.Interface {
			 = .Elem()
		}
		return .val.runtime.toValue(.Interface(), )
	}

	return nil
}

func ( *objectGoMapReflect) ( Value) Value {
	return ._getKey(.toKey(, false))
}

func ( *objectGoMapReflect) ( string) Value {
	return ._getKey(.strToKey(, false))
}

func ( *objectGoMapReflect) ( unistring.String,  Value) Value {
	if  := ._getStr(.String());  != nil {
		return 
	}
	return .objectGoReflect.getStr(, )
}

func ( *objectGoMapReflect) ( valueInt,  Value) Value {
	if  := ._get();  != nil {
		return 
	}
	return .objectGoReflect.getIdx(, )
}

func ( *objectGoMapReflect) ( unistring.String) Value {
	if  := ._getStr(.String());  != nil {
		return &valueProperty{
			value:      ,
			writable:   true,
			enumerable: true,
		}
	}
	return .objectGoReflect.getOwnPropStr()
}

func ( *objectGoMapReflect) ( valueInt) Value {
	if  := ._get();  != nil {
		return &valueProperty{
			value:      ,
			writable:   true,
			enumerable: true,
		}
	}
	return .objectGoReflect.getOwnPropStr(.string())
}

func ( *objectGoMapReflect) ( Value,  bool) (reflect.Value, bool) {
	 := reflect.New(.valueType).Elem()
	 := .val.runtime.toReflectValue(, , &objectExportCtx{})
	if  != nil {
		.val.runtime.typeErrorResult(, "map value conversion error: %v", )
		return reflect.Value{}, false
	}

	return , true
}

func ( *objectGoMapReflect) ( reflect.Value,  Value,  bool) bool {
	if .IsValid() {
		if .extensible || .fieldsValue.MapIndex().IsValid() {
			,  := .toValue(, )
			if ! {
				return false
			}
			.fieldsValue.SetMapIndex(, )
		} else {
			.val.runtime.typeErrorResult(, "Cannot set property %v, object is not extensible", )
			return false
		}
		return true
	}
	return false
}

func ( *objectGoMapReflect) ( unistring.String,  Value,  bool) bool {
	 := .String()
	 := .strToKey(, false)
	if !.IsValid() || !.fieldsValue.MapIndex().IsValid() {
		if  := .prototype;  != nil {
			// we know it's foreign because prototype loops are not allowed
			if ,  := .self.setForeignStr(, , .val, );  {
				return 
			}
		}
		// new property
		if !.extensible {
			.val.runtime.typeErrorResult(, "Cannot add property %s, object is not extensible", )
			return false
		} else {
			if  && !.IsValid() {
				.strToKey(, true)
				return false
			}
		}
	}
	._put(, , )
	return true
}

func ( *objectGoMapReflect) ( valueInt,  Value,  bool) bool {
	 := .toKey(, false)
	if !.IsValid() || !.fieldsValue.MapIndex().IsValid() {
		if  := .prototype;  != nil {
			// we know it's foreign because prototype loops are not allowed
			if ,  := .self.setForeignIdx(, , .val, );  {
				return 
			}
		}
		// new property
		if !.extensible {
			.val.runtime.typeErrorResult(, "Cannot add property %d, object is not extensible", )
			return false
		} else {
			if  && !.IsValid() {
				.toKey(, true)
				return false
			}
		}
	}
	._put(, , )
	return true
}

func ( *objectGoMapReflect) ( unistring.String, ,  Value,  bool) (bool, bool) {
	return ._setForeignStr(, trueValIfPresent(.hasOwnPropertyStr()), , , )
}

func ( *objectGoMapReflect) ( valueInt, ,  Value,  bool) (bool, bool) {
	return ._setForeignIdx(, trueValIfPresent(.hasOwnPropertyIdx()), , , )
}

func ( *objectGoMapReflect) ( unistring.String,  PropertyDescriptor,  bool) bool {
	if !.val.runtime.checkHostObjectPropertyDescr(, , ) {
		return false
	}

	return ._put(.strToKey(.String(), ), .Value, )
}

func ( *objectGoMapReflect) ( valueInt,  PropertyDescriptor,  bool) bool {
	if !.val.runtime.checkHostObjectPropertyDescr(.string(), , ) {
		return false
	}

	return ._put(.toKey(, ), .Value, )
}

func ( *objectGoMapReflect) ( unistring.String) bool {
	 := .strToKey(.String(), false)
	if .IsValid() && .fieldsValue.MapIndex().IsValid() {
		return true
	}
	return false
}

func ( *objectGoMapReflect) ( valueInt) bool {
	 := .toKey(, false)
	if .IsValid() && .fieldsValue.MapIndex().IsValid() {
		return true
	}
	return false
}

func ( *objectGoMapReflect) ( unistring.String,  bool) bool {
	 := .strToKey(.String(), )
	if !.IsValid() {
		return false
	}
	.fieldsValue.SetMapIndex(, reflect.Value{})
	return true
}

func ( *objectGoMapReflect) ( valueInt,  bool) bool {
	 := .toKey(, )
	if !.IsValid() {
		return false
	}
	.fieldsValue.SetMapIndex(, reflect.Value{})
	return true
}

type gomapReflectPropIter struct {
	o    *objectGoMapReflect
	keys []reflect.Value
	idx  int
}

func ( *gomapReflectPropIter) () (propIterItem, iterNextFunc) {
	for .idx < len(.keys) {
		 := .keys[.idx]
		 := .o.fieldsValue.MapIndex()
		.idx++
		if .IsValid() {
			return propIterItem{name: .o.keyToString(), enumerable: _ENUM_TRUE}, .
		}
	}

	return propIterItem{}, nil
}

func ( *objectGoMapReflect) () iterNextFunc {
	return (&gomapReflectPropIter{
		o:    ,
		keys: .fieldsValue.MapKeys(),
	}).next
}

func ( *objectGoMapReflect) ( bool,  []Value) []Value {
	// all own keys are enumerable
	for ,  := range .fieldsValue.MapKeys() {
		 = append(, .keyToString())
	}

	return 
}

func (*objectGoMapReflect) ( reflect.Value) String {
	 := .Kind()

	if  == reflect.String {
		return newStringValue(.String())
	}

	 := fmt.Sprintf("%v", )

	switch  {
	case reflect.Int,
		reflect.Int8,
		reflect.Int16,
		reflect.Int32,
		reflect.Int64,
		reflect.Uint,
		reflect.Uint8,
		reflect.Uint16,
		reflect.Uint32,
		reflect.Uint64,
		reflect.Float32,
		reflect.Float64:
		return asciiString()
	default:
		return newStringValue()
	}
}