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

import (
	
	
	
	
	
	
	

	
	
	
	
	
	
)

type TypeToScalar interface {
	ToScalar() (Scalar, error)
}

type TypeFromScalar interface {
	FromStructScalar(*Struct) error
}

type hasTypename interface {
	TypeName() string
}

var (
	hasTypenameType = reflect.TypeOf((*hasTypename)(nil)).Elem()
	dataTypeType    = reflect.TypeOf((*arrow.DataType)(nil)).Elem()
)

func ( *Struct,  interface{}) error {
	if  == nil || len(.Value) == 0 {
		return nil
	}

	if ,  := .(TypeFromScalar);  {
		return .FromStructScalar()
	}

	 := reflect.ValueOf()
	if .Kind() != reflect.Ptr {
		return errors.New("fromscalar must be given a pointer to an object to populate")
	}
	 := reflect.Indirect()

	for  := 0;  < .Type().NumField(); ++ {
		 := .Type().Field()
		 := .Tag.Get("compute")
		if  == "-" || .Name == "_type_name" {
			continue
		}

		,  := .Field()
		if  != nil {
			return 
		}
		if  := setFromScalar(, .Field());  != nil {
			return 
		}
	}

	return nil
}

func setFromScalar( Scalar,  reflect.Value) error {
	if .Type() == dataTypeType {
		.Set(reflect.ValueOf(.DataType()))
		return nil
	}

	switch s := .(type) {
	case BinaryScalar:
		 := .value().(*memory.Buffer)
		switch .Kind() {
		case reflect.String:
			if  == nil {
				.SetString("")
			} else {
				.SetString(string(.Bytes()))
			}
		default:
			if  == nil {
				.SetBytes(nil)
			} else {
				.SetBytes(.Bytes())
			}
		}
	case ListScalar:
		return fromListScalar(, )
	case *Struct:
		return FromScalar(, .Interface())
	default:
		if .Type() == reflect.TypeOf(arrow.TimeUnit(0)) {
			.Set(reflect.ValueOf(arrow.TimeUnit(.value().(uint32))))
		} else {
			.Set(reflect.ValueOf(.value()))
		}
	}
	return nil
}

func ( interface{},  memory.Allocator) (Scalar, error) {
	switch v := .(type) {
	case arrow.DataType:
		return MakeScalar(), nil
	case TypeToScalar:
		return .ToScalar()
	}

	 := reflect.Indirect(reflect.ValueOf())
	switch .Kind() {
	case reflect.Struct:
		 := make([]Scalar, 0, .Type().NumField())
		 := make([]string, 0, .Type().NumField())
		for  := 0;  < .Type().NumField(); ++ {
			 := .Type().Field()
			 := .Tag.Get("compute")
			if  == "-" {
				continue
			}

			 := .Field()
			,  := (.Interface(), )
			if  != nil {
				return nil, 
			}
			 = append(, )
			 = append(, )
		}

		if .Type().Implements(hasTypenameType) {
			 := .(hasTypename)
			 = append(, NewBinaryScalar(memory.NewBufferBytes([]byte(.TypeName())), arrow.BinaryTypes.Binary))
			 = append(, "_type_name")
		}

		return NewStructScalarWithNames(, )
	case reflect.Slice:
		return createListScalar(, )
	default:
		return MakeScalar(), nil
	}
}

func createListScalar( reflect.Value,  memory.Allocator) (Scalar, error) {
	if .Kind() != reflect.Slice {
		return nil, fmt.Errorf("createListScalar only works for slices, not %s", .Kind())
	}

	var  arrow.Array

	switch .Type().Elem().Kind() {
	case reflect.String:
		 := array.NewStringBuilder()
		defer .Release()
		.AppendValues(.Interface().([]string), nil)
		 = .NewArray()
	case reflect.Bool:
		 := array.NewBooleanBuilder()
		defer .Release()
		.AppendValues(.Interface().([]bool), nil)
		 = .NewArray()
	case reflect.Int8:
		 := array.NewInt8Builder()
		defer .Release()
		.AppendValues(.Interface().([]int8), nil)
		 = .NewArray()
	case reflect.Uint8:
		 := array.NewUint8Builder()
		defer .Release()
		.AppendValues(.Interface().([]uint8), nil)
		 = .NewArray()
	case reflect.Int16:
		 := array.NewInt16Builder()
		defer .Release()
		.AppendValues(.Interface().([]int16), nil)
		 = .NewArray()
	case reflect.Uint16:
		 := array.NewUint16Builder()
		defer .Release()
		.AppendValues(.Interface().([]uint16), nil)
		 = .NewArray()
	case reflect.Int32:
		 := array.NewInt32Builder()
		defer .Release()
		.AppendValues(.Interface().([]int32), nil)
		 = .NewArray()
	case reflect.Uint32:
		 := array.NewUint32Builder()
		defer .Release()
		.AppendValues(.Interface().([]uint32), nil)
		 = .NewArray()
	case reflect.Int64:
		 := array.NewInt64Builder()
		defer .Release()
		.AppendValues(.Interface().([]int64), nil)
		 = .NewArray()
	case reflect.Uint64:
		 := array.NewUint64Builder()
		defer .Release()
		.AppendValues(.Interface().([]uint64), nil)
		 = .NewArray()
	case reflect.Int:
		if bits.UintSize == 32 {
			 := array.NewInt32Builder()
			defer .Release()
			for ,  := range .Interface().([]int) {
				.Append(int32())
			}
			 = .NewArray()
			break
		}
		 := array.NewInt64Builder()
		defer .Release()
		for ,  := range .Interface().([]int) {
			.Append(int64())
		}
		 = .NewArray()
	case reflect.Uint:
		if bits.UintSize == 32 {
			 := array.NewUint32Builder()
			defer .Release()
			for ,  := range .Interface().([]uint) {
				.Append(uint32())
			}
			 = .NewArray()
			break
		}
		 := array.NewUint64Builder()
		defer .Release()
		for ,  := range .Interface().([]uint) {
			.Append(uint64())
		}
		 = .NewArray()
	case reflect.Ptr:
		,  := .Interface().([]*arrow.Metadata)
		if ! {
			break
		}

		 := array.NewMapBuilder(, arrow.BinaryTypes.Binary, arrow.BinaryTypes.Binary, false)
		defer .Release()

		 := .KeyBuilder().(*array.BinaryBuilder)
		 := .ItemBuilder().(*array.BinaryBuilder)
		for ,  := range  {
			.Append(true)
			if  != nil {
				.AppendStringValues(.Keys(), nil)
				.AppendStringValues(.Values(), nil)
			}
		}

		 := .NewMapArray()
		defer .Release()

		return NewListScalar(), nil
	}

	if  == nil {
		return nil, fmt.Errorf("createListScalar not implemented for %s", .Type())
	}

	defer .Release()
	return MakeScalarParam(, arrow.ListOf(.DataType()))
}

func fromListScalar( ListScalar,  reflect.Value) error {
	if .Kind() != reflect.Slice {
		return fmt.Errorf("could not populate field from list scalar, incompatible types: %s is not a slice", .Type().String())
	}

	 := .GetList()
	.Set(reflect.MakeSlice(.Type(), .Len(), .Len()))
	switch arr := .(type) {
	case *array.Boolean:
		for  := 0;  < .Len(); ++ {
			.Index().SetBool(.Value())
		}
	case *array.Int8:
		reflect.Copy(, reflect.ValueOf(.Int8Values()))
	case *array.Uint8:
		reflect.Copy(, reflect.ValueOf(.Uint8Values()))
	case *array.Int16:
		reflect.Copy(, reflect.ValueOf(.Int16Values()))
	case *array.Uint16:
		reflect.Copy(, reflect.ValueOf(.Uint16Values()))
	case *array.Int32:
		reflect.Copy(, reflect.ValueOf(.Int32Values()))
	case *array.Uint32:
		reflect.Copy(, reflect.ValueOf(.Uint32Values()))
	case *array.Int64:
		reflect.Copy(, reflect.ValueOf(.Int64Values()))
	case *array.Uint64:
		reflect.Copy(, reflect.ValueOf(.Uint64Values()))
	case *array.Float32:
		reflect.Copy(, reflect.ValueOf(.Float32Values()))
	case *array.Float64:
		reflect.Copy(, reflect.ValueOf(.Float64Values()))
	case *array.Binary:
		for  := 0;  < .Len(); ++ {
			.Index().SetString(.ValueString())
		}
	case *array.String:
		for  := 0;  < .Len(); ++ {
			.Index().SetString(.Value())
		}
	case *array.Map:
		// only implementing slice of metadata for now
		if .Type().Elem() != reflect.PointerTo(reflect.TypeOf(arrow.Metadata{})) {
			return fmt.Errorf("unimplemented fromListScalar type %s to %s", .DataType(), .Type().String())
		}

		var (
			    = .Offsets()
			       = .Keys().(*array.Binary)
			     = .Items().(*array.Binary)
			   []string
			 []string
		)

		for ,  := range [:len()-1] {
			 := 
			 := [+1]

			 = make([]string, -)
			 = make([]string, -)
			for  := ;  < ; ++ {
				 = append(, .ValueString(int()))
				 = append(, .ValueString(int()))
			}

			 := arrow.NewMetadata(, )
			.Index().Set(reflect.ValueOf(&))
		}

	default:
		return fmt.Errorf("unimplemented fromListScalar type: %s", .DataType())
	}

	return nil
}

// MakeScalarParam is for converting a value to a scalar when it requires a
// parameterized data type such as a time type that needs units, or a fixed
// size list which needs it's size.
//
// Will fall back to MakeScalar without the passed in type if not one of the
// parameterized types.
func ( interface{},  arrow.DataType) (Scalar, error) {
	switch v := .(type) {
	case []byte:
		 := memory.NewBufferBytes()
		defer .Release()

		switch .ID() {
		case arrow.BINARY:
			return NewBinaryScalar(, ), nil
		case arrow.LARGE_BINARY:
			return NewLargeBinaryScalar(), nil
		case arrow.STRING:
			return NewStringScalarFromBuffer(), nil
		case arrow.LARGE_STRING:
			return NewLargeStringScalarFromBuffer(), nil
		case arrow.FIXED_SIZE_BINARY:
			if .Len() == .(*arrow.FixedSizeBinaryType).ByteWidth {
				return NewFixedSizeBinaryScalar(, ), nil
			}
			return nil, fmt.Errorf("invalid scalar value of len %d for type %s", , )
		}
	case *memory.Buffer:
		switch .ID() {
		case arrow.BINARY:
			return NewBinaryScalar(, ), nil
		case arrow.LARGE_BINARY:
			return NewLargeBinaryScalar(), nil
		case arrow.STRING:
			return NewStringScalarFromBuffer(), nil
		case arrow.LARGE_STRING:
			return NewLargeStringScalarFromBuffer(), nil
		case arrow.FIXED_SIZE_BINARY:
			if .Len() == .(*arrow.FixedSizeBinaryType).ByteWidth {
				return NewFixedSizeBinaryScalar(, ), nil
			}
			return nil, fmt.Errorf("invalid scalar value of len %d for type %s", .Len(), )
		}
	case string:
		switch {
		case arrow.IsBaseBinary(.ID()):
			 := memory.NewBufferBytes([]byte())
			defer .Release()

			switch .ID() {
			case arrow.BINARY:
				return NewBinaryScalar(, ), nil
			case arrow.LARGE_BINARY:
				return NewLargeBinaryScalar(), nil
			case arrow.STRING:
				return NewStringScalar(), nil
			case arrow.LARGE_STRING:
				return NewLargeStringScalar(), nil
			}
		case arrow.IsInteger(.ID()):
			 := .(arrow.FixedWidthDataType).BitWidth()
			if arrow.IsUnsignedInteger(.ID()) {
				,  := strconv.ParseUint(, 0, )
				if  != nil {
					return nil, 
				}
				return MakeUnsignedIntegerScalar(, )
			}
			,  := strconv.ParseInt(, 0, )
			if  != nil {
				return nil, 
			}
			return MakeIntegerScalar(, )
		case arrow.IsFixedSizeBinary(.ID()):
			switch .ID() {
			case arrow.FIXED_SIZE_BINARY:
				 := .(*arrow.FixedSizeBinaryType)
				if len() != .ByteWidth {
					return nil, fmt.Errorf("%w: invalid length for fixed size binary scalar", arrow.ErrInvalid)
				}
				return NewFixedSizeBinaryScalar(memory.NewBufferBytes([]byte()), ), nil
			case arrow.DECIMAL128:
				 := .(*arrow.Decimal128Type)
				,  := decimal128.FromString(, .Precision, .Scale)
				if  != nil {
					return nil, 
				}
				return NewDecimal128Scalar(, ), nil
			case arrow.DECIMAL256:
				 := .(*arrow.Decimal256Type)
				,  := decimal256.FromString(, .Precision, .Scale)
				if  != nil {
					return nil, 
				}
				return NewDecimal256Scalar(, ), nil
			}
		case arrow.IsFloating(.ID()):
			 := .(arrow.FixedWidthDataType).BitWidth()
			,  := strconv.ParseFloat(, )
			if  != nil {
				return nil, 
			}
			if  == 32 {
				return NewFloat32Scalar(float32()), nil
			}
			return NewFloat64Scalar(), nil
		case .ID() == arrow.TIMESTAMP:
			 := .(*arrow.TimestampType)
			if .TimeZone == "" || strings.ToLower(.TimeZone) == "utc" {
				,  := arrow.TimestampFromString(, .Unit)
				if  != nil {
					return nil, 
				}
				return NewTimestampScalar(, ), nil
			}
			,  := time.LoadLocation(.TimeZone)
			if  != nil {
				return nil, 
			}
			, ,  := arrow.TimestampFromStringInLocation(, .Unit, )
			if  != nil {
				return nil, 
			}
			return NewTimestampScalar(, ), nil
		}
	case arrow.Time32:
		return NewTime32Scalar(, ), nil
	case arrow.Time64:
		return NewTime64Scalar(, ), nil
	case arrow.Timestamp:
		return NewTimestampScalar(, ), nil
	case arrow.Array:
		switch .ID() {
		case arrow.LIST:
			if !arrow.TypeEqual(.DataType(), .(*arrow.ListType).Elem()) {
				return nil, fmt.Errorf("inconsistent type for list scalar array and data type")
			}
			return NewListScalar(), nil
		case arrow.LARGE_LIST:
			if !arrow.TypeEqual(.DataType(), .(*arrow.LargeListType).Elem()) {
				return nil, fmt.Errorf("inconsistent type for large list scalar array and data type")
			}
			return NewLargeListScalar(), nil
		case arrow.FIXED_SIZE_LIST:
			if !arrow.TypeEqual(.DataType(), .(*arrow.FixedSizeListType).Elem()) {
				return nil, fmt.Errorf("inconsistent type for list scalar array and data type")
			}
			return NewFixedSizeListScalarWithType(, ), nil
		case arrow.MAP:
			if !arrow.TypeEqual(.(*arrow.MapType).Elem(), .DataType()) {
				return nil, fmt.Errorf("inconsistent type for map scalar type")
			}
			return NewMapScalar(), nil
		}
	case decimal128.Num:
		if ,  := .(*arrow.Decimal128Type); ! {
			return nil, fmt.Errorf("mismatch cannot create decimal128 scalar with incorrect data type")
		}

		return NewDecimal128Scalar(, ), nil
	case decimal256.Num:
		if ,  := .(*arrow.Decimal256Type); ! {
			return nil, fmt.Errorf("mismatch cannot create decimal256 scalar with incorrect data type")
		}

		return NewDecimal256Scalar(, ), nil

	}

	if arrow.IsInteger(.ID()) {
		 := .(arrow.FixedWidthDataType).BitWidth()
		 := reflect.ValueOf()
		if arrow.IsUnsignedInteger(.ID()) {
			return MakeUnsignedIntegerScalar(.Convert(reflect.TypeOf(uint64(0))).Uint(), )
		}
		return MakeIntegerScalar(.Convert(reflect.TypeOf(int64(0))).Int(), )
	}

	if .ID() == arrow.DICTIONARY {
		return (, .(*arrow.DictionaryType).ValueType)
	}
	return MakeScalar(), nil
}

// MakeScalar creates a scalar of the passed in type via reflection.
func ( interface{}) Scalar {
	switch v := .(type) {
	case nil:
		return ScalarNull
	case bool:
		return NewBooleanScalar()
	case int8:
		return NewInt8Scalar()
	case uint8:
		return NewUint8Scalar()
	case int16:
		return NewInt16Scalar()
	case uint16:
		return NewUint16Scalar()
	case int32:
		return NewInt32Scalar()
	case uint32:
		return NewUint32Scalar()
	case int64:
		return NewInt64Scalar()
	case uint64:
		return NewUint64Scalar()
	case int:
		// determine size of an int on this system
		switch bits.UintSize {
		case 32:
			return NewInt32Scalar(int32())
		case 64:
			return NewInt64Scalar(int64())
		}
	case uint:
		// determine size of an int on this system
		switch bits.UintSize {
		case 32:
			return NewUint32Scalar(uint32())
		case 64:
			return NewUint64Scalar(uint64())
		}
	case []byte:
		 := memory.NewBufferBytes()
		defer .Release()
		return NewBinaryScalar(, arrow.BinaryTypes.Binary)
	case string:
		return NewStringScalar()
	case arrow.Date32:
		return NewDate32Scalar()
	case arrow.Date64:
		return NewDate64Scalar()
	case float16.Num:
		return NewFloat16Scalar()
	case float32:
		return NewFloat32Scalar()
	case float64:
		return NewFloat64Scalar()
	case arrow.MonthInterval:
		return NewMonthIntervalScalar()
	case arrow.DayTimeInterval:
		return NewDayTimeIntervalScalar()
	case arrow.MonthDayNanoInterval:
		return NewMonthDayNanoIntervalScalar()
	case arrow.DataType:
		return MakeNullScalar()
	default:
		 := reflect.ValueOf()
		if .Type().ConvertibleTo(reflect.TypeOf(uint32(0))) {
			return NewUint32Scalar(uint32(.Convert(reflect.TypeOf(uint32(0))).Uint()))
		}
	}

	panic(fmt.Errorf("makescalar not implemented for type value %#v", ))
}

// MakeIntegerScalar is a helper function for creating an integer scalar of a
// given bitsize.
func ( int64,  int) (Scalar, error) {
	switch  {
	case 8:
		return NewInt8Scalar(int8()), nil
	case 16:
		return NewInt16Scalar(int16()), nil
	case 32:
		return NewInt32Scalar(int32()), nil
	case 64:
		return NewInt64Scalar(int64()), nil
	}
	return nil, fmt.Errorf("invalid bitsize for integer scalar: %d", )
}

// MakeUnsignedIntegerScalar is a helper function for creating an unsigned int
// scalar of the specified bit width.
func ( uint64,  int) (Scalar, error) {
	switch  {
	case 8:
		return NewUint8Scalar(uint8()), nil
	case 16:
		return NewUint16Scalar(uint16()), nil
	case 32:
		return NewUint32Scalar(uint32()), nil
	case 64:
		return NewUint64Scalar(uint64()), nil
	}
	return nil, fmt.Errorf("invalid bitsize for uint scalar: %d", )
}

// ParseScalar parses a string to create a scalar of the passed in type. Currently
// does not support any nested types such as Structs or Lists.
func ( arrow.DataType,  string) (Scalar, error) {
	switch .ID() {
	case arrow.STRING:
		return NewStringScalar(), nil
	case arrow.BINARY:
		 := memory.NewBufferBytes([]byte())
		defer .Release()
		return NewBinaryScalar(, ), nil
	case arrow.FIXED_SIZE_BINARY:
		if len() != .(*arrow.FixedSizeBinaryType).ByteWidth {
			return nil, fmt.Errorf("invalid value %s for scalar of type %s", , )
		}
		 := memory.NewBufferBytes([]byte())
		defer .Release()
		return NewFixedSizeBinaryScalar(, ), nil
	case arrow.BOOL:
		,  := strconv.ParseBool()
		if  != nil {
			return nil, 
		}
		return NewBooleanScalar(), nil
	case arrow.INT8, arrow.INT16, arrow.INT32, arrow.INT64:
		 := .(arrow.FixedWidthDataType).BitWidth()
		,  := strconv.ParseInt(, 0, )
		if  != nil {
			return nil, 
		}
		return MakeIntegerScalar(, )
	case arrow.UINT8, arrow.UINT16, arrow.UINT32, arrow.UINT64:
		 := .(arrow.FixedWidthDataType).BitWidth()
		,  := strconv.ParseUint(, 0, )
		if  != nil {
			return nil, 
		}
		return MakeUnsignedIntegerScalar(, )
	case arrow.FLOAT16:
		,  := strconv.ParseFloat(, 32)
		if  != nil {
			return nil, 
		}
		return NewFloat16ScalarFromFloat32(float32()), nil
	case arrow.FLOAT32, arrow.FLOAT64:
		 := .(arrow.FixedWidthDataType).BitWidth()
		,  := strconv.ParseFloat(, )
		if  != nil {
			return nil, 
		}
		switch  {
		case 32:
			return NewFloat32Scalar(float32()), nil
		case 64:
			return NewFloat64Scalar(float64()), nil
		}
	case arrow.TIMESTAMP:
		,  := arrow.TimestampFromString(, .(*arrow.TimestampType).Unit)
		if  != nil {
			return nil, 
		}
		return NewTimestampScalar(, ), nil
	case arrow.DURATION:
		,  := time.ParseDuration()
		if  != nil {
			return nil, 
		}
		 := .(*arrow.DurationType).Unit
		var  arrow.Duration
		switch  {
		case arrow.Nanosecond:
			 = arrow.Duration(.Nanoseconds())
		case arrow.Microsecond:
			 = arrow.Duration(.Microseconds())
		case arrow.Millisecond:
			 = arrow.Duration(.Milliseconds())
		case arrow.Second:
			 = arrow.Duration(.Seconds())
		}
		return NewDurationScalar(, ), nil
	case arrow.DATE32, arrow.DATE64:
		,  := time.ParseInLocation("2006-01-02", , time.UTC)
		if  != nil {
			return nil, 
		}
		if .ID() == arrow.DATE32 {
			return NewDate32Scalar(arrow.Date32FromTime()), nil
		} else {
			return NewDate64Scalar(arrow.Date64FromTime()), nil
		}
	case arrow.TIME32:
		,  := arrow.Time32FromString(, .(*arrow.Time32Type).Unit)
		if  != nil {
			return nil, 
		}

		return NewTime32Scalar(, ), nil
	case arrow.TIME64:
		,  := arrow.Time64FromString(, .(*arrow.Time64Type).Unit)
		if  != nil {
			return nil, 
		}

		return NewTime64Scalar(, ), nil
	case arrow.DICTIONARY:
		return (.(*arrow.DictionaryType).ValueType, )
	case arrow.DECIMAL128:
		 := .(*arrow.Decimal128Type)
		,  := decimal128.FromString(, .Precision, .Scale)
		if  != nil {
			return nil, 
		}
		return NewDecimal128Scalar(, ), nil
	case arrow.DECIMAL256:
		 := .(*arrow.Decimal256Type)
		,  := decimal256.FromString(, .Precision, .Scale)
		if  != nil {
			return nil, 
		}
		return NewDecimal256Scalar(, ), nil
	}

	return nil, fmt.Errorf("parsing of scalar for type %s not implemented", )
}