// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package array

import (
	
	

	
	
	
)

// Map represents an immutable sequence of Key/Value structs. It is a
// logical type that is implemented as a List<Struct: key, value>.
type Map struct {
	*List
	keys, items arrow.Array
}

var _ ListLike = (*Map)(nil)

// NewMapData returns a new Map array value, from data
func ( arrow.ArrayData) *Map {
	 := &Map{List: &List{}}
	.refCount.Add(1)
	.setData(.(*Data))
	return 
}

// KeysSorted checks the datatype that was used to construct this array and
// returns the KeysSorted boolean value used to denote if the key array is
// sorted for each list element.
//
// Important note: Nothing is enforced regarding the KeysSorted value, it is
// solely a metadata field that should be set if keys within each value are sorted.
// This value is not used at all in regards to comparisons / equality.
func ( *Map) () bool { return .DataType().(*arrow.MapType).KeysSorted }

func ( *Map) ( *Data) {
	if len(.childData) != 1 || .childData[0] == nil {
		panic("arrow/array: expected one child array for map array")
	}

	if .childData[0].DataType().ID() != arrow.STRUCT {
		panic("arrow/array: map array child should be struct type")
	}

	if .childData[0].NullN() != 0 {
		panic("arrow/array: map array child array should have no nulls")
	}

	if len(.childData[0].Children()) != 2 {
		panic("arrow/array: map array child array should have two fields")
	}

	if .childData[0].Children()[0].NullN() != 0 {
		panic("arrow/array: map array keys array should have no nulls")
	}
}

func ( *Map) ( *Data) {
	.validateData()

	.List.setData()
	.keys = MakeFromData(.childData[0].Children()[0])
	.items = MakeFromData(.childData[0].Children()[1])
}

// Keys returns the full Array of Key values, equivalent to grabbing
// the key field of the child struct.
func ( *Map) () arrow.Array { return .keys }

// Items returns the full Array of Item values, equivalent to grabbing
// the Value field (the second field) of the child struct.
func ( *Map) () arrow.Array { return .items }

// Retain increases the reference count by 1.
// Retain may be called simultaneously from multiple goroutines.
func ( *Map) () {
	.List.Retain()
	.keys.Retain()
	.items.Retain()
}

// Release decreases the reference count by 1.
// Release may be called simultaneously from multiple goroutines.
// When the reference count goes to zero, the memory is freed.
func ( *Map) () {
	.List.Release()
	.keys.Release()
	.items.Release()
}

func arrayEqualMap(,  *Map) bool {
	// since Map is implemented using a list, we can just use arrayEqualList
	return arrayEqualList(.List, .List)
}

type MapBuilder struct {
	listBuilder *ListBuilder

	etype                   *arrow.MapType
	keytype, itemtype       arrow.DataType
	keyBuilder, itemBuilder Builder
	keysSorted              bool
}

// NewMapBuilder returns a builder, using the provided memory allocator.
// The created Map builder will create a map array whose keys will be a non-nullable
// array of type `keytype` and whose mapped items will be a nullable array of itemtype.
//
// KeysSorted is not enforced at all by the builder, it should only be set to true
// building using keys in sorted order for each value. The KeysSorted value will just be
// used when creating the DataType for the map.
//
// # Example
//
// Simple example provided of converting a []map[string]int32 to an array.Map
// by using a MapBuilder:
//
//	/* assume maplist == []map[string]int32 */
//	bldr := array.NewMapBuilder(memory.DefaultAllocator, arrow.BinaryTypes.String, arrow.PrimitiveTypes.Int32, false)
//	defer bldr.Release()
//	kb := bldr.KeyBuilder().(*array.StringBuilder)
//	ib := bldr.ItemBuilder().(*array.Int32Builder)
//	for _, m := range maplist {
//	    bldr.Append(true)
//	    for k, v := range m {
//	         kb.Append(k)
//	         ib.Append(v)
//	    }
//	}
//	maparr := bldr.NewMapArray()
//	defer maparr.Release()
func ( memory.Allocator, ,  arrow.DataType,  bool) *MapBuilder {
	 := arrow.MapOf(, )
	.KeysSorted = 
	 := NewListBuilder(, .Elem())
	 := .ValueBuilder().(*StructBuilder).FieldBuilder(0)
	.Retain()
	 := .ValueBuilder().(*StructBuilder).FieldBuilder(1)
	.Retain()
	return &MapBuilder{
		listBuilder: ,
		keyBuilder:  ,
		itemBuilder: ,
		etype:       ,
		keytype:     ,
		itemtype:    ,
		keysSorted:  ,
	}
}

func ( memory.Allocator,  *arrow.MapType) *MapBuilder {
	 := NewListBuilder(, .Elem())
	 := .ValueBuilder().(*StructBuilder).FieldBuilder(0)
	.Retain()
	 := .ValueBuilder().(*StructBuilder).FieldBuilder(1)
	.Retain()
	return &MapBuilder{
		listBuilder: ,
		keyBuilder:  ,
		itemBuilder: ,
		etype:       ,
		keytype:     .KeyType(),
		itemtype:    .ItemType(),
		keysSorted:  .KeysSorted,
	}
}

func ( *MapBuilder) () arrow.DataType { return .etype }

// Retain increases the reference count by 1 for the sub-builders (list, key, item).
// Retain may be called simultaneously from multiple goroutines.
func ( *MapBuilder) () {
	.listBuilder.Retain()
	.keyBuilder.Retain()
	.itemBuilder.Retain()
}

// Release decreases the reference count by 1 for the sub builders (list, key, item).
func ( *MapBuilder) () {
	.listBuilder.Release()
	.keyBuilder.Release()
	.itemBuilder.Release()
}

// Len returns the current number of Maps that are in the builder
func ( *MapBuilder) () int { return .listBuilder.Len() }

// Cap returns the total number of elements that can be stored
// without allocating additional memory.
func ( *MapBuilder) () int { return .listBuilder.Cap() }

// NullN returns the number of null values in the array builder.
func ( *MapBuilder) () int { return .listBuilder.NullN() }

// IsNull returns if a previously appended value at a given index is null or not.
func ( *MapBuilder) ( int) bool {
	return .listBuilder.IsNull()
}

// Append adds a new Map element to the array, calling Append(false) is
// equivalent to calling AppendNull.
func ( *MapBuilder) ( bool) {
	.adjustStructBuilderLen()
	.listBuilder.Append()
}

func ( *MapBuilder) ( bool,  int) {
	.Append()
}

// AppendNull adds a null map entry to the array.
func ( *MapBuilder) () {
	.Append(false)
}

// AppendNulls adds null map entry to the array.
func ( *MapBuilder) ( int) {
	for  := 0;  < ; ++ {
		.AppendNull()
	}
}

func ( *MapBuilder) ( int) {
	.listBuilder.SetNull()
}

func ( *MapBuilder) () {
	.Append(true)
}

func ( *MapBuilder) ( int) {
	for  := 0;  < ; ++ {
		.AppendEmptyValue()
	}
}

// Reserve enough space for n maps
func ( *MapBuilder) ( int) { .listBuilder.Reserve() }

// Resize adjust the space allocated by b to n map elements. If n is greater than
// b.Cap(), additional memory will be allocated. If n is smaller, the allocated memory may be reduced.
func ( *MapBuilder) ( int) { .listBuilder.Resize() }

// AppendValues is for bulk appending a group of elements with offsets provided
// and validity booleans provided.
func ( *MapBuilder) ( []int32,  []bool) {
	.adjustStructBuilderLen()
	.listBuilder.AppendValues(, )
}

func ( *MapBuilder) ( bool) {
	.listBuilder.UnsafeAppendBoolToBitmap()
}

func ( *MapBuilder) ( int)                  { .listBuilder.init() }
func ( *MapBuilder) ( int,  func(int)) { .listBuilder.resize(, ) }

func ( *MapBuilder) () {
	 := .listBuilder.ValueBuilder().(*StructBuilder)
	if .Len() < .keyBuilder.Len() {
		 := make([]bool, .keyBuilder.Len()-.Len())
		for  := range  {
			[] = true
		}
		.AppendValues()
	}
}

// NewArray creates a new Map array from the memory buffers used by the builder, and
// resets the builder so it can be used again to build a new Map array.
func ( *MapBuilder) () arrow.Array {
	return .NewMapArray()
}

// NewMapArray creates a new Map array from the memory buffers used by the builder, and
// resets the builder so it can be used again to build a new Map array.
func ( *MapBuilder) () ( *Map) {
	if !.etype.ItemField().Nullable && .ItemBuilder().NullN() > 0 {
		panic("arrow/array: item not nullable")
	}

	 := .newData()
	defer .Release()
	 = NewMapData()
	return
}

func ( *MapBuilder) () ( *Data) {
	.adjustStructBuilderLen()
	 := .listBuilder.NewListArray()
	defer .Release()

	 = NewData(.etype,
		.Len(), .data.buffers,
		.data.childData, .NullN(), 0)
	return
}

// KeyBuilder returns a builder that can be used to populate the keys of the maps.
func ( *MapBuilder) () Builder { return .keyBuilder }

// ItemBuilder returns a builder that can be used to populate the values that the
// keys point to.
func ( *MapBuilder) () Builder { return .itemBuilder }

// ValueBuilder can be used instead of separately using the Key/Item builders
// to build the list as a List of Structs rather than building the keys/items
// separately.
func ( *MapBuilder) () Builder {
	return .listBuilder.ValueBuilder()
}

func ( *MapBuilder) ( string) error {
	return .listBuilder.AppendValueFromString()
}

func ( *MapBuilder) ( *json.Decoder) error {
	return .listBuilder.UnmarshalOne()
}

func ( *MapBuilder) ( *json.Decoder) error {
	return .listBuilder.Unmarshal()
}

func ( *MapBuilder) ( []byte) error {
	 := json.NewDecoder(bytes.NewReader())
	,  := .Token()
	if  != nil {
		return 
	}

	if ,  := .(json.Delim); ! ||  != '[' {
		return fmt.Errorf("map builder must unpack from json array, found %s", )
	}

	return .Unmarshal()
}

var (
	_ arrow.Array     = (*Map)(nil)
	_ Builder         = (*MapBuilder)(nil)
	_ ListLikeBuilder = (*MapBuilder)(nil)
)