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

// OffsetTraits is a convenient interface over the various type traits
// constants such as arrow.Int32Traits allowing types with offsets, like
// BinaryType, StringType, LargeBinaryType and LargeStringType to have
// a method to return information about their offset type and how many bytes
// would be required to allocate an offset buffer for them.
type OffsetTraits interface {
	// BytesRequired returns the number of bytes required to be allocated
	// in order to hold the passed in number of elements of this type.
	BytesRequired(int) int
}

type BinaryType struct{}

func ( *BinaryType) () Type            { return BINARY }
func ( *BinaryType) () string        { return "binary" }
func ( *BinaryType) () string      { return "binary" }
func ( *BinaryType) ()             {}
func ( *BinaryType) () string { return typeFingerprint() }
func ( *BinaryType) () DataTypeLayout {
	return DataTypeLayout{Buffers: []BufferSpec{SpecBitmap(),
		SpecFixedWidth(Int32SizeBytes), SpecVariableWidth()}}
}
func ( *BinaryType) () OffsetTraits { return Int32Traits }
func (BinaryType) () bool                      { return false }

type StringType struct{}

func ( *StringType) () Type            { return STRING }
func ( *StringType) () string        { return "utf8" }
func ( *StringType) () string      { return "utf8" }
func ( *StringType) ()             {}
func ( *StringType) () string { return typeFingerprint() }
func ( *StringType) () DataTypeLayout {
	return DataTypeLayout{Buffers: []BufferSpec{SpecBitmap(),
		SpecFixedWidth(Int32SizeBytes), SpecVariableWidth()}}
}
func ( *StringType) () OffsetTraits { return Int32Traits }
func (StringType) () bool                      { return true }

type LargeBinaryType struct{}

func ( *LargeBinaryType) () Type            { return LARGE_BINARY }
func ( *LargeBinaryType) () string        { return "large_binary" }
func ( *LargeBinaryType) () string      { return "large_binary" }
func ( *LargeBinaryType) ()             {}
func ( *LargeBinaryType) () string { return typeFingerprint() }
func ( *LargeBinaryType) () DataTypeLayout {
	return DataTypeLayout{Buffers: []BufferSpec{SpecBitmap(),
		SpecFixedWidth(Int64SizeBytes), SpecVariableWidth()}}
}
func ( *LargeBinaryType) () OffsetTraits { return Int64Traits }
func (LargeBinaryType) () bool                      { return false }

type LargeStringType struct{}

func ( *LargeStringType) () Type            { return LARGE_STRING }
func ( *LargeStringType) () string        { return "large_utf8" }
func ( *LargeStringType) () string      { return "large_utf8" }
func ( *LargeStringType) ()             {}
func ( *LargeStringType) () string { return typeFingerprint() }
func ( *LargeStringType) () DataTypeLayout {
	return DataTypeLayout{Buffers: []BufferSpec{SpecBitmap(),
		SpecFixedWidth(Int64SizeBytes), SpecVariableWidth()}}
}
func ( *LargeStringType) () OffsetTraits { return Int64Traits }
func (LargeStringType) () bool                      { return true }

type BinaryViewType struct{}

func (*BinaryViewType) () Type              { return BINARY_VIEW }
func (*BinaryViewType) () string          { return "binary_view" }
func (*BinaryViewType) () string        { return "binary_view" }
func (*BinaryViewType) () bool          { return false }
func (*BinaryViewType) ()               {}
func (*BinaryViewType) ()                 {}
func ( *BinaryViewType) () string { return typeFingerprint() }
func (*BinaryViewType) () DataTypeLayout {
	 := SpecVariableWidth()
	return DataTypeLayout{
		Buffers:      []BufferSpec{SpecBitmap(), SpecFixedWidth(ViewHeaderSizeBytes)},
		VariadicSpec: &,
	}
}

type StringViewType struct{}

func (*StringViewType) () Type              { return STRING_VIEW }
func (*StringViewType) () string          { return "string_view" }
func (*StringViewType) () string        { return "string_view" }
func (*StringViewType) () bool          { return true }
func (*StringViewType) ()               {}
func (*StringViewType) ()                 {}
func ( *StringViewType) () string { return typeFingerprint() }
func (*StringViewType) () DataTypeLayout {
	 := SpecVariableWidth()
	return DataTypeLayout{
		Buffers:      []BufferSpec{SpecBitmap(), SpecFixedWidth(ViewHeaderSizeBytes)},
		VariadicSpec: &,
	}
}

var (
	BinaryTypes = struct {
		Binary      BinaryDataType
		String      BinaryDataType
		LargeBinary BinaryDataType
		LargeString BinaryDataType
		BinaryView  BinaryDataType
		StringView  BinaryDataType
	}{
		Binary:      &BinaryType{},
		String:      &StringType{},
		LargeBinary: &LargeBinaryType{},
		LargeString: &LargeStringType{},
		BinaryView:  &BinaryViewType{},
		StringView:  &StringViewType{},
	}

	_ BinaryViewDataType = (*StringViewType)(nil)
	_ BinaryViewDataType = (*BinaryViewType)(nil)
)