// Package splitter manages splitting of object data into chunks.
package splitter

import (
	"sort"
)

const (
	splitterSlidingWindowSize = 64

	splitterSize1MB = 1 << 20
	splitterSize2MB = 2 << 20
	splitterSize4MB = 4 << 20
	splitterSize8MB = 8 << 20
)

// Splitter determines when to split a given object.
type Splitter interface {
	// NextSplitPoint() determines the location of the next split point in the given slice of bytes.
	// It returns value `n` between 1..len(b) if a split point happens AFTER byte n and the splitter
	// has consumed `n` bytes.
	// If there is no split point, the splitter returns -1 and consumes all bytes from the slice.
	NextSplitPoint(b []byte) int
	MaxSegmentSize() int
	Reset()
	Close()
}

// SupportedAlgorithms returns the list of supported splitters.
func SupportedAlgorithms() []string {
	var supportedSplitters []string

	for k := range splitterFactories {
		supportedSplitters = append(supportedSplitters, k)
	}

	sort.Strings(supportedSplitters)

	return supportedSplitters
}

// Factory creates instances of Splitter.
type Factory func() Splitter

// splitterFactories is a map of registered splitter factories.
// nolint:gochecknoglobals
var splitterFactories = map[string]Factory{
	"FIXED-1M": Fixed(splitterSize1MB),
	"FIXED-2M": Fixed(splitterSize2MB),
	"FIXED-4M": Fixed(splitterSize4MB),
	"FIXED-8M": Fixed(splitterSize8MB),

	"DYNAMIC-1M-BUZHASH": newBuzHash32SplitterFactory(splitterSize1MB),
	"DYNAMIC-2M-BUZHASH": newBuzHash32SplitterFactory(splitterSize2MB),
	"DYNAMIC-4M-BUZHASH": newBuzHash32SplitterFactory(splitterSize4MB),
	"DYNAMIC-8M-BUZHASH": newBuzHash32SplitterFactory(splitterSize8MB),

	"DYNAMIC-1M-RABINKARP": newRabinKarp64SplitterFactory(splitterSize1MB),
	"DYNAMIC-2M-RABINKARP": newRabinKarp64SplitterFactory(splitterSize2MB),
	"DYNAMIC-4M-RABINKARP": newRabinKarp64SplitterFactory(splitterSize4MB),
	"DYNAMIC-8M-RABINKARP": newRabinKarp64SplitterFactory(splitterSize8MB),

	// handle deprecated legacy names to splitters of arbitrary size
	"FIXED": Fixed(splitterSize4MB),

	// we don't want to use old DYNAMIC splitter because of its license, so
	// map this one to arbitrary buzhash32 (different)
	"DYNAMIC": newBuzHash32SplitterFactory(splitterSize4MB),
}

// GetFactory gets splitter factory with a specified name or nil if not found.
func GetFactory(name string) Factory {
	return splitterFactories[name]
}

// DefaultAlgorithm is the name of the splitter used by default for new repositories.
const DefaultAlgorithm = "DYNAMIC-4M-BUZHASH"
