// 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 numericArray[ arrow.IntType | arrow.UintType | arrow.FloatType] struct {
	array
	values []
}

func newNumericData[ arrow.IntType | arrow.UintType | arrow.FloatType]( arrow.ArrayData) numericArray[] {
	 := numericArray[]{}
	.refCount.Add(1)
	.setData(.(*Data))
	return 
}

func ( *numericArray[]) ( *Data) {
	.setData()
}

func ( *numericArray[]) ( int)  { return .values[] }
func ( *numericArray[]) () []   { return .values }
func ( *numericArray[]) () string {
	 := new(strings.Builder)
	.WriteString("[")
	for ,  := range .values {
		if  > 0 {
			fmt.Fprintf(, " ")
		}
		switch {
		case .IsNull():
			.WriteString(NullValueStr)
		default:
			fmt.Fprintf(, "%v", )
		}
	}
	.WriteString("]")
	return .String()
}

func ( *numericArray[]) ( *Data) {
	.array.setData()
	 := .buffers[1]
	if  != nil {
		.values = arrow.GetData[](.Bytes())
		 := .data.offset
		 :=  + .data.length
		.values = .values[:]
	}
}

func ( *numericArray[]) ( int) string {
	if .IsNull() {
		return NullValueStr
	}

	return fmt.Sprintf("%v", .values[])
}

func ( *numericArray[]) ( int) any {
	if .IsNull() {
		return nil
	}

	return .values[]
}

func ( *numericArray[]) () ([]byte, error) {
	 := make([]any, .Len())
	for  := range .Len() {
		if .IsValid() {
			[] = .values[]
		} else {
			[] = nil
		}
	}
	return json.Marshal()
}

type oneByteArrs[ int8 | uint8] struct {
	numericArray[]
}

func ( *oneByteArrs[]) ( int) any {
	if .IsNull() {
		return nil
	}

	return float64(.values[]) // prevent uint8/int8 from being seen as binary data
}

func ( *oneByteArrs[]) () ([]byte, error) {
	 := make([]any, .Len())
	for  := range .Len() {
		if .IsValid() {
			[] = float64(.values[]) // prevent uint8/int8 from being seen as binary data
		} else {
			[] = nil
		}
	}
	return json.Marshal()
}

type floatArray[ float32 | float64] struct {
	numericArray[]
}

func ( *floatArray[]) ( int) string {
	if .IsNull() {
		return NullValueStr
	}

	 := .Value()
	 := int(unsafe.Sizeof() * 8)
	return strconv.FormatFloat(float64(.Value()), 'g', -1, )
}

func ( *floatArray[]) ( int) any {
	if .IsNull() {
		return nil
	}

	 := .Value()
	 := int(unsafe.Sizeof() * 8)
	 := strconv.FormatFloat(float64(.Value()), 'g', -1, )
	switch  {
	case "NaN", "+Inf", "-Inf":
		return 
	default:
		return 
	}
}

func ( *floatArray[]) () ([]byte, error) {
	 := make([]any, .Len())
	for  := range .values {
		[] = .GetOneForMarshal()
	}
	return json.Marshal()
}

type dateArray[ interface {
	arrow.Date32 | arrow.Date64
	FormattedString() string
	ToTime() time.Time
}] struct {
	numericArray[]
}

func ( *dateArray[]) () ([]byte, error) {
	 := make([]any, .Len())
	for  := range .values {
		[] = .GetOneForMarshal()
	}
	return json.Marshal()
}

func ( *dateArray[]) ( int) string {
	if .IsNull() {
		return NullValueStr
	}

	return .values[].FormattedString()
}

func ( *dateArray[]) ( int) interface{} {
	if .IsNull() {
		return nil
	}

	return .values[].FormattedString()
}

type timeType interface {
	TimeUnit() arrow.TimeUnit
}

type timeArray[ interface {
	arrow.Time32 | arrow.Time64
	FormattedString(arrow.TimeUnit) string
	ToTime(arrow.TimeUnit) time.Time
}] struct {
	numericArray[]
}

func ( *timeArray[]) () ([]byte, error) {
	 := make([]any, .Len())
	for  := range .values {
		[] = .GetOneForMarshal()
	}
	return json.Marshal()
}

func ( *timeArray[]) ( int) string {
	if .IsNull() {
		return NullValueStr
	}

	return .values[].FormattedString(.DataType().(timeType).TimeUnit())
}

func ( *timeArray[]) ( int) interface{} {
	if .IsNull() {
		return nil
	}

	return .values[].ToTime(.DataType().(timeType).TimeUnit()).Format("15:04:05.999999999")
}

type Duration struct {
	numericArray[arrow.Duration]
}

func ( arrow.ArrayData) *Duration {
	return &Duration{numericArray: newNumericData[arrow.Duration]()}
}

func ( *Duration) () []arrow.Duration { return .Values() }

func ( *Duration) () ([]byte, error) {
	 := make([]any, .Len())
	for  := range .values {
		[] = .GetOneForMarshal()
	}
	return json.Marshal()
}

func ( *Duration) ( int) string {
	if .IsNull() {
		return NullValueStr
	}

	return fmt.Sprintf("%d%s", .values[], .DataType().(timeType).TimeUnit())
}

func ( *Duration) ( int) any {
	if .IsNull() {
		return nil
	}
	return fmt.Sprintf("%d%s", .values[], .DataType().(timeType).TimeUnit())
}

type Int64 struct {
	numericArray[int64]
}

func ( arrow.ArrayData) *Int64 {
	return &Int64{numericArray: newNumericData[int64]()}
}

func ( *Int64) () []int64 { return .Values() }

type Uint64 struct {
	numericArray[uint64]
}

func ( arrow.ArrayData) *Uint64 {
	return &Uint64{numericArray: newNumericData[uint64]()}
}

func ( *Uint64) () []uint64 { return .Values() }

type Float32 struct {
	floatArray[float32]
}

func ( arrow.ArrayData) *Float32 {
	return &Float32{floatArray[float32]{newNumericData[float32]()}}
}

func ( *Float32) () []float32 { return .Values() }

type Float64 struct {
	floatArray[float64]
}

func ( arrow.ArrayData) *Float64 {
	return &Float64{floatArray: floatArray[float64]{newNumericData[float64]()}}
}

func ( *Float64) () []float64 { return .Values() }

type Int32 struct {
	numericArray[int32]
}

func ( arrow.ArrayData) *Int32 {
	return &Int32{newNumericData[int32]()}
}

func ( *Int32) () []int32 { return .Values() }

type Uint32 struct {
	numericArray[uint32]
}

func ( arrow.ArrayData) *Uint32 {
	return &Uint32{numericArray: newNumericData[uint32]()}
}

func ( *Uint32) () []uint32 { return .Values() }

type Int16 struct {
	numericArray[int16]
}

func ( arrow.ArrayData) *Int16 {
	return &Int16{newNumericData[int16]()}
}

func ( *Int16) () []int16 { return .Values() }

type Uint16 struct {
	numericArray[uint16]
}

func ( arrow.ArrayData) *Uint16 {
	return &Uint16{numericArray: newNumericData[uint16]()}
}

func ( *Uint16) () []uint16 { return .Values() }

type Int8 struct {
	oneByteArrs[int8]
}

func ( arrow.ArrayData) *Int8 {
	return &Int8{oneByteArrs[int8]{newNumericData[int8]()}}
}

func ( *Int8) () []int8 { return .Values() }

type Uint8 struct {
	oneByteArrs[uint8]
}

func ( arrow.ArrayData) *Uint8 {
	return &Uint8{oneByteArrs[uint8]{newNumericData[uint8]()}}
}

func ( *Uint8) () []uint8 { return .Values() }

type Time32 struct {
	timeArray[arrow.Time32]
}

func ( arrow.ArrayData) *Time32 {
	return &Time32{timeArray[arrow.Time32]{newNumericData[arrow.Time32]()}}
}

func ( *Time32) () []arrow.Time32 { return .Values() }

type Time64 struct {
	timeArray[arrow.Time64]
}

func ( arrow.ArrayData) *Time64 {
	return &Time64{timeArray[arrow.Time64]{newNumericData[arrow.Time64]()}}
}

func ( *Time64) () []arrow.Time64 { return .Values() }

type Date32 struct {
	dateArray[arrow.Date32]
}

func ( arrow.ArrayData) *Date32 {
	return &Date32{dateArray[arrow.Date32]{newNumericData[arrow.Date32]()}}
}

func ( *Date32) () []arrow.Date32 { return .Values() }

type Date64 struct {
	dateArray[arrow.Date64]
}

func ( arrow.ArrayData) *Date64 {
	return &Date64{dateArray[arrow.Date64]{newNumericData[arrow.Date64]()}}
}

func ( *Date64) () []arrow.Date64 { return .Values() }

func arrayEqualFixedWidth[ arrow.FixedWidthType](,  arrow.TypedArray[]) bool {
	for  := range .Len() {
		if .IsNull() {
			continue
		}
		if .Value() != .Value() {
			return false
		}
	}
	return true
}