// 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 (
	
	

	
	
	
	
)

const (
	minBuilderCapacity = 1 << 5
)

// Builder provides an interface to build arrow arrays.
type Builder interface {
	// you can unmarshal a json array to add the values to a builder
	json.Unmarshaler

	// Type returns the datatype that this is building
	Type() arrow.DataType

	// Retain increases the reference count by 1.
	// Retain may be called simultaneously from multiple goroutines.
	Retain()

	// Release decreases the reference count by 1.
	Release()

	// Len returns the number of elements in the array builder.
	Len() int

	// Cap returns the total number of elements that can be stored
	// without allocating additional memory.
	Cap() int

	// NullN returns the number of null values in the array builder.
	NullN() int

	// AppendNull adds a new null value to the array being built.
	AppendNull()

	// AppendNulls adds new n null values to the array being built.
	AppendNulls(n int)

	// AppendEmptyValue adds a new zero value of the appropriate type
	AppendEmptyValue()

	// AppendEmptyValues adds new n zero values of the appropriate type
	AppendEmptyValues(n int)

	// AppendValueFromString adds a new value from a string. Inverse of array.ValueStr(i int) string
	AppendValueFromString(string) error

	// Reserve ensures there is enough space for appending n elements
	// by checking the capacity and calling Resize if necessary.
	Reserve(n int)

	// Resize adjusts the space allocated by b to n elements. If n is greater than b.Cap(),
	// additional memory will be allocated. If n is smaller, the allocated memory may reduced.
	Resize(n int)

	// NewArray creates a new array from the memory buffers used
	// by the builder and resets the Builder so it can be used to build
	// a new array.
	NewArray() arrow.Array

	// IsNull returns if a previously appended value at a given index is null or not.
	IsNull(i int) bool

	// SetNull sets the value at index i to null.
	SetNull(i int)

	UnsafeAppendBoolToBitmap(bool)

	init(capacity int)
	resize(newBits int, init func(int))

	UnmarshalOne(*json.Decoder) error
	Unmarshal(*json.Decoder) error

	newData() *Data
}

// builder provides common functionality for managing the validity bitmap (nulls) when building arrays.
type builder struct {
	refCount   atomic.Int64
	mem        memory.Allocator
	nullBitmap *memory.Buffer
	nulls      int
	length     int
	capacity   int
}

// Retain increases the reference count by 1.
// Retain may be called simultaneously from multiple goroutines.
func ( *builder) () {
	.refCount.Add(1)
}

// Len returns the number of elements in the array builder.
func ( *builder) () int { return .length }

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

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

func ( *builder) ( int) bool {
	return .nullBitmap.Len() != 0 && bitutil.BitIsNotSet(.nullBitmap.Bytes(), )
}

func ( *builder) ( int) {
	if  < 0 ||  >= .length {
		panic("arrow/array: index out of range")
	}
	bitutil.ClearBit(.nullBitmap.Bytes(), )
}

func ( *builder) ( int) {
	 := bitutil.CeilByte() / 8
	.nullBitmap = memory.NewResizableBuffer(.mem)
	.nullBitmap.Resize()
	.capacity = 
	memory.Set(.nullBitmap.Buf(), 0)
}

func ( *builder) () {
	if .nullBitmap != nil {
		.nullBitmap.Release()
		.nullBitmap = nil
	}

	.nulls = 0
	.length = 0
	.capacity = 0
}

func ( *builder) ( int,  func(int)) {
	if .nullBitmap == nil {
		()
		return
	}

	 := bitutil.CeilByte() / 8
	 := .nullBitmap.Len()
	.nullBitmap.Resize()
	.capacity = 
	if  <  {
		// TODO(sgc): necessary?
		memory.Set(.nullBitmap.Buf()[:], 0)
	}
	if  < .length {
		.length = 
		.nulls =  - bitutil.CountSetBits(.nullBitmap.Buf(), 0, )
	}
}

func ( *builder) ( int,  func(int)) {
	if .length+ > .capacity {
		 := bitutil.NextPowerOf2(.length + )
		()
	}
	if .nullBitmap == nil {
		.nullBitmap = memory.NewResizableBuffer(.mem)
	}
}

// unsafeAppendBoolsToBitmap appends the contents of valid to the validity bitmap.
// As an optimization, if the valid slice is empty, the next length bits will be set to valid (not null).
func ( *builder) ( []bool,  int) {
	if len() == 0 {
		.unsafeSetValid()
		return
	}

	 := .length / 8
	 := byte(.length % 8)
	 := .nullBitmap.Bytes()
	 := []

	for ,  := range  {
		if  == 8 {
			 = 0
			[] = 
			++
			 = []
		}

		if  {
			 |= bitutil.BitMask[]
		} else {
			 &= bitutil.FlippedBitMask[]
			.nulls++
		}
		++
	}

	if  != 0 {
		[] = 
	}
	.length += len()
}

// unsafeSetValid sets the next length bits to valid in the validity bitmap.
func ( *builder) ( int) {
	 := min(8-(.length%8), )
	if  == 8 {
		 = 0
	}
	 := .nullBitmap.Bytes()
	for  := .length;  < .length+; ++ {
		bitutil.SetBit(, )
	}

	 := (.length + ) / 8
	 := ( - ) / 8
	memory.Set([:+], 0xff)

	 := .length + 
	// trailing bytes
	for  := .length +  + ( * 8);  < ; ++ {
		bitutil.SetBit(, )
	}

	.length = 
}

func ( *builder) ( bool) {
	if  {
		bitutil.SetBit(.nullBitmap.Bytes(), .length)
	} else {
		.nulls++
	}
	.length++
}

func ( memory.Allocator,  arrow.DataType) Builder {
	// FIXME(sbinet): use a type switch on dtype instead?
	switch .ID() {
	case arrow.NULL:
		return NewNullBuilder()
	case arrow.BOOL:
		return NewBooleanBuilder()
	case arrow.UINT8:
		return NewUint8Builder()
	case arrow.INT8:
		return NewInt8Builder()
	case arrow.UINT16:
		return NewUint16Builder()
	case arrow.INT16:
		return NewInt16Builder()
	case arrow.UINT32:
		return NewUint32Builder()
	case arrow.INT32:
		return NewInt32Builder()
	case arrow.UINT64:
		return NewUint64Builder()
	case arrow.INT64:
		return NewInt64Builder()
	case arrow.FLOAT16:
		return NewFloat16Builder()
	case arrow.FLOAT32:
		return NewFloat32Builder()
	case arrow.FLOAT64:
		return NewFloat64Builder()
	case arrow.STRING:
		return NewStringBuilder()
	case arrow.LARGE_STRING:
		return NewLargeStringBuilder()
	case arrow.BINARY:
		return NewBinaryBuilder(, arrow.BinaryTypes.Binary)
	case arrow.LARGE_BINARY:
		return NewBinaryBuilder(, arrow.BinaryTypes.LargeBinary)
	case arrow.FIXED_SIZE_BINARY:
		 := .(*arrow.FixedSizeBinaryType)
		return NewFixedSizeBinaryBuilder(, )
	case arrow.DATE32:
		return NewDate32Builder()
	case arrow.DATE64:
		return NewDate64Builder()
	case arrow.TIMESTAMP:
		 := .(*arrow.TimestampType)
		return NewTimestampBuilder(, )
	case arrow.TIME32:
		 := .(*arrow.Time32Type)
		return NewTime32Builder(, )
	case arrow.TIME64:
		 := .(*arrow.Time64Type)
		return NewTime64Builder(, )
	case arrow.INTERVAL_MONTHS:
		return NewMonthIntervalBuilder()
	case arrow.INTERVAL_DAY_TIME:
		return NewDayTimeIntervalBuilder()
	case arrow.INTERVAL_MONTH_DAY_NANO:
		return NewMonthDayNanoIntervalBuilder()
	case arrow.DECIMAL32:
		if ,  := .(*arrow.Decimal32Type);  {
			return NewDecimal32Builder(, )
		}
	case arrow.DECIMAL64:
		if ,  := .(*arrow.Decimal64Type);  {
			return NewDecimal64Builder(, )
		}
	case arrow.DECIMAL128:
		if ,  := .(*arrow.Decimal128Type);  {
			return NewDecimal128Builder(, )
		}
	case arrow.DECIMAL256:
		if ,  := .(*arrow.Decimal256Type);  {
			return NewDecimal256Builder(, )
		}
	case arrow.LIST:
		 := .(*arrow.ListType)
		return NewListBuilderWithField(, .ElemField())
	case arrow.STRUCT:
		 := .(*arrow.StructType)
		return NewStructBuilder(, )
	case arrow.SPARSE_UNION:
		 := .(*arrow.SparseUnionType)
		return NewSparseUnionBuilder(, )
	case arrow.DENSE_UNION:
		 := .(*arrow.DenseUnionType)
		return NewDenseUnionBuilder(, )
	case arrow.DICTIONARY:
		 := .(*arrow.DictionaryType)
		return NewDictionaryBuilder(, )
	case arrow.LARGE_LIST:
		 := .(*arrow.LargeListType)
		return NewLargeListBuilderWithField(, .ElemField())
	case arrow.MAP:
		 := .(*arrow.MapType)
		return NewMapBuilderWithType(, )
	case arrow.LIST_VIEW:
		 := .(*arrow.ListViewType)
		return NewListViewBuilderWithField(, .ElemField())
	case arrow.LARGE_LIST_VIEW:
		 := .(*arrow.LargeListViewType)
		return NewLargeListViewBuilderWithField(, .ElemField())
	case arrow.EXTENSION:
		if ,  := .(CustomExtensionBuilder);  {
			return .NewBuilder()
		}
		if ,  := .(arrow.ExtensionType);  {
			return NewExtensionBuilder(, )
		}
		panic(fmt.Errorf("arrow/array: invalid extension type: %T", ))
	case arrow.FIXED_SIZE_LIST:
		 := .(*arrow.FixedSizeListType)
		return NewFixedSizeListBuilderWithField(, .Len(), .ElemField())
	case arrow.DURATION:
		 := .(*arrow.DurationType)
		return NewDurationBuilder(, )
	case arrow.RUN_END_ENCODED:
		 := .(*arrow.RunEndEncodedType)
		return NewRunEndEncodedBuilder(, .RunEnds(), .Encoded())
	case arrow.BINARY_VIEW:
		return NewBinaryViewBuilder()
	case arrow.STRING_VIEW:
		return NewStringViewBuilder()
	}
	panic(fmt.Errorf("arrow/array: unsupported builder for %T", ))
}