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

	
	
	
)

type BinaryLike interface {
	arrow.Array
	ValueLen(int) int
	ValueBytes() []byte
	ValueOffset64(int) int64
}

// A type which represents an immutable sequence of variable-length binary strings.
type Binary struct {
	array
	valueOffsets []int32
	valueBytes   []byte
}

// NewBinaryData constructs a new Binary array from data.
func ( arrow.ArrayData) *Binary {
	 := &Binary{}
	.refCount.Add(1)
	.setData(.(*Data))
	return 
}

// Value returns the slice at index i. This value should not be mutated.
func ( *Binary) ( int) []byte {
	if  < 0 ||  >= .data.length {
		panic("arrow/array: index out of range")
	}
	 := .data.offset + 
	return .valueBytes[.valueOffsets[]:.valueOffsets[+1]]
}

// ValueStr returns a copy of the base64-encoded string value or NullValueStr
func ( *Binary) ( int) string {
	if .IsNull() {
		return NullValueStr
	}
	return base64.StdEncoding.EncodeToString(.Value())
}

// ValueString returns the string at index i without performing additional allocations.
// The string is only valid for the lifetime of the Binary array.
func ( *Binary) ( int) string {
	 := .Value()
	return *(*string)(unsafe.Pointer(&))
}

func ( *Binary) ( int) int {
	if  < 0 ||  >= .data.length {
		panic("arrow/array: index out of range")
	}
	return int(.valueOffsets[.data.offset+])
}

func ( *Binary) ( int) int64 {
	return int64(.ValueOffset())
}

func ( *Binary) ( int) int {
	if  < 0 ||  >= .data.length {
		panic("arrow/array: index out of range")
	}
	 := .data.offset + 
	return int(.valueOffsets[+1] - .valueOffsets[])
}

func ( *Binary) () []int32 {
	 := .data.offset
	 :=  + .data.length + 1
	return .valueOffsets[:]
}

func ( *Binary) () []byte {
	 := .data.offset
	 :=  + .data.length
	return .valueBytes[.valueOffsets[]:.valueOffsets[]]
}

func ( *Binary) () string {
	 := new(strings.Builder)
	.WriteString("[")
	for  := 0;  < .Len(); ++ {
		if  > 0 {
			.WriteString(" ")
		}
		switch {
		case .IsNull():
			.WriteString(NullValueStr)
		default:
			fmt.Fprintf(, "%q", .ValueString())
		}
	}
	.WriteString("]")
	return .String()
}

func ( *Binary) ( *Data) {
	if len(.buffers) != 3 {
		panic("len(data.buffers) != 3")
	}

	.array.setData()

	if  := .buffers[2];  != nil {
		.valueBytes = .Bytes()
	}

	if  := .buffers[1];  != nil {
		.valueOffsets = arrow.Int32Traits.CastFromBytes(.Bytes())
	}

	if .data.length < 1 {
		return
	}

	 := .data.offset + .data.length + 1
	if len(.valueOffsets) <  {
		panic(fmt.Errorf("arrow/array: binary offset buffer must have at least %d values", ))
	}

	if int(.valueOffsets[-1]) > len(.valueBytes) {
		panic("arrow/array: binary offsets out of bounds of data buffer")
	}
}

func ( *Binary) ( int) interface{} {
	if .IsNull() {
		return nil
	}
	return .Value()
}

func ( *Binary) () ([]byte, error) {
	 := make([]interface{}, .Len())
	for  := 0;  < .Len(); ++ {
		[] = .GetOneForMarshal()
	}
	// golang marshal standard says that []byte will be marshalled
	// as a base64-encoded string
	return json.Marshal()
}

func arrayEqualBinary(,  *Binary) bool {
	for  := 0;  < .Len(); ++ {
		if .IsNull() {
			continue
		}
		if !bytes.Equal(.Value(), .Value()) {
			return false
		}
	}
	return true
}

type LargeBinary struct {
	array
	valueOffsets []int64
	valueBytes   []byte
}

func ( arrow.ArrayData) *LargeBinary {
	 := &LargeBinary{}
	.refCount.Add(1)
	.setData(.(*Data))
	return 
}

func ( *LargeBinary) ( int) []byte {
	if  < 0 ||  >= .data.length {
		panic("arrow/array: index out of range")
	}
	 := .data.offset + 
	return .valueBytes[.valueOffsets[]:.valueOffsets[+1]]
}

func ( *LargeBinary) ( int) string {
	if .IsNull() {
		return NullValueStr
	}
	return base64.StdEncoding.EncodeToString(.Value())
}

func ( *LargeBinary) ( int) string {
	 := .Value()
	return *(*string)(unsafe.Pointer(&))
}

func ( *LargeBinary) ( int) int64 {
	if  < 0 ||  >= .data.length {
		panic("arrow/array: index out of range")
	}
	return .valueOffsets[.data.offset+]
}

func ( *LargeBinary) ( int) int64 {
	return .ValueOffset()
}

func ( *LargeBinary) ( int) int {
	if  < 0 ||  >= .data.length {
		panic("arrow/array: index out of range")
	}
	 := .data.offset + 
	return int(.valueOffsets[+1] - .valueOffsets[])
}

func ( *LargeBinary) () []int64 {
	 := .data.offset
	 :=  + .data.length + 1
	return .valueOffsets[:]
}

func ( *LargeBinary) () []byte {
	 := .data.offset
	 :=  + .data.length
	return .valueBytes[.valueOffsets[]:.valueOffsets[]]
}

func ( *LargeBinary) () string {
	var  strings.Builder
	.WriteString("[")
	for  := 0;  < .Len(); ++ {
		if  > 0 {
			.WriteString(" ")
		}
		switch {
		case .IsNull():
			.WriteString(NullValueStr)
		default:
			fmt.Fprintf(&, "%q", .ValueString())
		}
	}
	.WriteString("]")
	return .String()
}

func ( *LargeBinary) ( *Data) {
	if len(.buffers) != 3 {
		panic("len(data.buffers) != 3")
	}

	.array.setData()

	if  := .buffers[2];  != nil {
		.valueBytes = .Bytes()
	}

	if  := .buffers[1];  != nil {
		.valueOffsets = arrow.Int64Traits.CastFromBytes(.Bytes())
	}

	if .data.length < 1 {
		return
	}

	 := .data.offset + .data.length + 1
	if len(.valueOffsets) <  {
		panic(fmt.Errorf("arrow/array: large binary offset buffer must have at least %d values", ))
	}

	if int(.valueOffsets[-1]) > len(.valueBytes) {
		panic("arrow/array: large binary offsets out of bounds of data buffer")
	}
}

func ( *LargeBinary) ( int) interface{} {
	if .IsNull() {
		return nil
	}
	return .Value()
}

func ( *LargeBinary) () ([]byte, error) {
	 := make([]interface{}, .Len())
	for  := 0;  < .Len(); ++ {
		[] = .GetOneForMarshal()
	}
	// golang marshal standard says that []byte will be marshalled
	// as a base64-encoded string
	return json.Marshal()
}

func arrayEqualLargeBinary(,  *LargeBinary) bool {
	for  := 0;  < .Len(); ++ {
		if .IsNull() {
			continue
		}
		if !bytes.Equal(.Value(), .Value()) {
			return false
		}
	}
	return true
}

type ViewLike interface {
	arrow.Array
	ValueHeader(int) *arrow.ViewHeader
}

type BinaryView struct {
	array
	values      []arrow.ViewHeader
	dataBuffers []*memory.Buffer
}

func ( arrow.ArrayData) *BinaryView {
	 := &BinaryView{}
	.refCount.Add(1)
	.setData(.(*Data))
	return 
}

func ( *BinaryView) ( *Data) {
	if len(.buffers) < 2 {
		panic("len(data.buffers) < 2")
	}
	.array.setData()

	if  := .buffers[1];  != nil {
		.values = arrow.ViewHeaderTraits.CastFromBytes(.Bytes())
	}

	.dataBuffers = .buffers[2:]
}

func ( *BinaryView) ( int) *arrow.ViewHeader {
	if  < 0 ||  >= .data.length {
		panic("arrow/array: index out of range")
	}
	return &.values[.data.offset+]
}

func ( *BinaryView) ( int) []byte {
	 := .ValueHeader()
	if .IsInline() {
		return .InlineBytes()
	}
	 := .BufferOffset()
	 := .dataBuffers[.BufferIndex()]
	return .Bytes()[ : +int32(.Len())]
}

func ( *BinaryView) ( int) int {
	 := .ValueHeader()
	return .Len()
}

// ValueString returns the value at index i as a string instead of
// a byte slice, without copying the underlying data.
func ( *BinaryView) ( int) string {
	 := .Value()
	return *(*string)(unsafe.Pointer(&))
}

func ( *BinaryView) () string {
	var  strings.Builder
	.WriteString("[")
	for  := 0;  < .Len(); ++ {
		if  > 0 {
			.WriteString(" ")
		}
		switch {
		case .IsNull():
			.WriteString(NullValueStr)
		default:
			fmt.Fprintf(&, "%q", .ValueString())
		}
	}
	.WriteString("]")
	return .String()
}

// ValueStr is paired with AppendValueFromString in that it returns
// the value at index i as a string: Semantically this means that for
// a null value it will return the string "(null)", otherwise it will
// return the value as a base64 encoded string suitable for CSV/JSON.
//
// This is always going to be less performant than just using ValueString
// and exists to fulfill the Array interface to provide a method which
// can produce a human readable string for a given index.
func ( *BinaryView) ( int) string {
	if .IsNull() {
		return NullValueStr
	}
	return base64.StdEncoding.EncodeToString(.Value())
}

func ( *BinaryView) ( int) interface{} {
	if .IsNull() {
		return nil
	}
	return .Value()
}

func ( *BinaryView) () ([]byte, error) {
	 := make([]interface{}, .Len())
	for  := 0;  < .Len(); ++ {
		[] = .GetOneForMarshal()
	}
	// golang marshal standard says that []byte will be marshalled
	// as a base64-encoded string
	return json.Marshal()
}

func arrayEqualBinaryView(,  *BinaryView) bool {
	,  := .dataBuffers, .dataBuffers
	for  := 0;  < .Len(); ++ {
		if .IsNull() {
			continue
		}
		if !.ValueHeader().Equals(, .ValueHeader(), ) {
			return false
		}
	}
	return true
}

var (
	_ arrow.Array = (*Binary)(nil)
	_ arrow.Array = (*LargeBinary)(nil)
	_ arrow.Array = (*BinaryView)(nil)

	_ BinaryLike = (*Binary)(nil)
	_ BinaryLike = (*LargeBinary)(nil)

	_ arrow.TypedArray[[]byte] = (*Binary)(nil)
	_ arrow.TypedArray[[]byte] = (*LargeBinary)(nil)
	_ arrow.TypedArray[[]byte] = (*BinaryView)(nil)
)