// 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 BinaryScalar interface {
	Scalar

	Retain()
	Release()
	Buffer() *memory.Buffer
	Data() []byte
}

type Binary struct {
	scalar

	Value *memory.Buffer
}

func ( *Binary) () {
	if .Value != nil {
		.Value.Retain()
	}
}

func ( *Binary) () {
	if .Value != nil {
		.Value.Release()
	}
}

func ( *Binary) () interface{} { return .Value }
func ( *Binary) () []byte       { return .Value.Bytes() }
func ( *Binary) ( Scalar) bool {
	return bytes.Equal(.Value.Bytes(), .(BinaryScalar).Data())
}
func ( *Binary) () *memory.Buffer { return .Value }
func ( *Binary) () string {
	if !.Valid {
		return "null"
	}

	return string(.Value.Bytes())
}

func ( *Binary) ( arrow.DataType) (Scalar, error) {
	if !.Valid {
		return MakeNullScalar(), nil
	}

	switch .ID() {
	case arrow.BINARY:
		return NewBinaryScalar(.Value, .Type), nil
	case arrow.LARGE_BINARY:
		return NewLargeBinaryScalar(.Value), nil
	case arrow.STRING:
		return NewStringScalarFromBuffer(.Value), nil
	case arrow.LARGE_STRING:
		return NewLargeStringScalarFromBuffer(.Value), nil
	case arrow.FIXED_SIZE_BINARY:
		if .Value.Len() == .(*arrow.FixedSizeBinaryType).ByteWidth {
			return NewFixedSizeBinaryScalar(.Value, ), nil
		}
	}

	return nil, fmt.Errorf("cannot cast non-null binary scalar to type %s", )
}

func ( *Binary) () ( error) {
	 = .scalar.Validate()
	if  == nil {
		 = validateOptional(&.scalar, .Value, "value")
	}
	return
}

func ( *Binary) () error {
	return .Validate()
}

func ( *memory.Buffer,  arrow.DataType) *Binary {
	.Retain()
	return &Binary{scalar{, true}, }
}

type LargeBinary struct {
	*Binary
}

func ( *memory.Buffer) *LargeBinary {
	return &LargeBinary{NewBinaryScalar(, arrow.BinaryTypes.LargeBinary)}
}

type String struct {
	*Binary
}

func ( *String) () error {
	return .Binary.Validate()
}

func ( *String) () ( error) {
	if  = .Validate();  != nil {
		return
	}
	if .Valid && !utf8.ValidString(string(.Value.Bytes())) {
		 = fmt.Errorf("%s scalar contains invalid utf8 data", .Type)
	}
	return
}

func ( *String) ( arrow.DataType) (Scalar, error) {
	if !.Valid {
		return MakeNullScalar(), nil
	}

	if .ID() == arrow.FIXED_SIZE_BINARY {
		if .Value.Len() == .(*arrow.FixedSizeBinaryType).ByteWidth {
			return NewFixedSizeBinaryScalar(.Value, ), nil
		}
		return nil, fmt.Errorf("cannot convert string scalar of %s to type %s", string(.Value.Bytes()), )
	}

	return ParseScalar(, string(.Value.Bytes()))
}

func ( string) *String {
	 := memory.NewBufferBytes([]byte())
	defer .Release()
	return NewStringScalarFromBuffer()
}

func ( *memory.Buffer) *String {
	// NewBinaryScalar will call Retain on val, so we don't have to
	return &String{NewBinaryScalar(, arrow.BinaryTypes.String)}
}

// alias the String struct we are embedding so it doesn't hide the
// String() function that we want to expose
type stringScalar = String

type LargeString struct {
	*stringScalar
}

func ( string) *LargeString {
	 := memory.NewBufferBytes([]byte())
	defer .Release()
	return NewLargeStringScalarFromBuffer()
}

func ( *memory.Buffer) *LargeString {
	// NewBinaryScalar will call retain on val, so we don't have to
	return &LargeString{stringScalar: &String{NewBinaryScalar(, arrow.BinaryTypes.LargeString)}}
}

type FixedSizeBinary struct {
	*Binary
}

func ( *FixedSizeBinary) () ( error) {
	if  = .Binary.Validate();  != nil {
		return
	}

	if .Valid {
		 := .Type.(*arrow.FixedSizeBinaryType).ByteWidth
		if .Value.Len() !=  {
			 = fmt.Errorf("%s scalar should have a value of size %d, got %d", .Type, , .Value.Len())
		}
	}
	return
}

func ( *FixedSizeBinary) () error { return .Validate() }

func ( *memory.Buffer,  arrow.DataType) *FixedSizeBinary {
	// NewBinaryScalar will call Retain on val, so we don't have to
	return &FixedSizeBinary{NewBinaryScalar(, )}
}