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

import (
	
	
	
	

	
)

type SortDirection string

const (
	SortASC  SortDirection = "asc"
	SortDESC SortDirection = "desc"
)

type NullOrder string

const (
	NullsFirst NullOrder = "nulls-first"
	NullsLast  NullOrder = "nulls-last"
)

var (
	ErrInvalidSortDirection = errors.New("invalid sort direction, must be 'asc' or 'desc'")
	ErrInvalidNullOrder     = errors.New("invalid null order, must be 'nulls-first' or 'nulls-last'")
)

// SortField describes a field used in a sort order definition.
type SortField struct {
	// SourceID is the source column id from the table's schema
	SourceID int `json:"source-id"`
	// Transform is the tranformation used to produce values to be
	// sorted on from the source column.
	Transform iceberg.Transform `json:"transform"`
	// Direction is an enum indicating ascending or descending direction.
	Direction SortDirection `json:"direction"`
	// NullOrder describes the order of null values when sorting
	// should be only either nulls-first or nulls-last enum values.
	NullOrder NullOrder `json:"null-order"`
}

func ( *SortField) () string {
	if ,  := .Transform.(iceberg.IdentityTransform);  {
		return fmt.Sprintf("%d %s %s", .SourceID, .Direction, .NullOrder)
	}
	return fmt.Sprintf("%s(%d) %s %s", .Transform, .SourceID, .Direction, .NullOrder)
}

func ( *SortField) () ([]byte, error) {
	if .Direction == "" {
		.Direction = SortASC
	}

	if .NullOrder == "" {
		if .Direction == SortASC {
			.NullOrder = NullsFirst
		} else {
			.NullOrder = NullsLast
		}
	}

	type  SortField
	return json.Marshal((*)())
}

func ( *SortField) ( []byte) error {
	type  SortField
	var  = struct {
		 string `json:"transform"`
		*
	}{
		: (*)(),
	}

	 := json.Unmarshal(, &)
	if  != nil {
		return 
	}

	if .Transform,  = iceberg.ParseTransform(.);  != nil {
		return 
	}

	switch .Direction {
	case SortASC, SortDESC:
	default:
		return ErrInvalidSortDirection
	}

	switch .NullOrder {
	case NullsFirst, NullsLast:
	default:
		return ErrInvalidNullOrder
	}

	return nil
}

const (
	InitialSortOrderID  = 1
	UnsortedSortOrderID = 0
)

// A default Sort Order indicating no sort order at all
var UnsortedSortOrder = SortOrder{OrderID: UnsortedSortOrderID, Fields: []SortField{}}

// SortOrder describes how the data is sorted within the table.
//
// Data can be sorted within partitions by columns to gain performance. The
// order of the sort fields within the list defines the order in which the
// sort is applied to the data.
type SortOrder struct {
	OrderID int         `json:"order-id"`
	Fields  []SortField `json:"fields"`
}

func ( SortOrder) () string {
	var  strings.Builder
	fmt.Fprintf(&, "%d: ", .OrderID)
	.WriteByte('[')
	for ,  := range .Fields {
		if  == 0 {
			.WriteByte('\n')
		}
		.WriteString(.String())
		.WriteByte('\n')
	}
	.WriteByte(']')
	return .String()
}

func ( *SortOrder) ( []byte) error {
	type  SortOrder
	 := (*)()

	if  := json.Unmarshal(, );  != nil {
		return 
	}

	if len(.Fields) == 0 {
		.Fields = []SortField{}
		.OrderID = 0
		return nil
	}

	if .OrderID == 0 {
		.OrderID = InitialSortOrderID // initialize default sort order id
	}

	return nil
}