package vals

import (
	"errors"
	"unicode/utf8"
)

var errIndexNotAtRuneBoundary = errors.New("index not at rune boundary")

func indexString(s string, index interface{}) (string, error) {
	i, j, err := convertStringIndex(index, s)
	if err != nil {
		return "", err
	}
	return s[i:j], nil
}

func convertStringIndex(rawIndex interface{}, s string) (int, int, error) {
	index, err := ConvertListIndex(rawIndex, len(s))
	if err != nil {
		return 0, 0, err
	}
	if index.Slice {
		lower, upper := index.Lower, index.Upper
		if startsWithRuneBoundary(s[lower:]) && endsWithRuneBoundary(s[:upper]) {
			return lower, upper, nil
		}
		return 0, 0, errIndexNotAtRuneBoundary
	}
	// Not slice
	r, size := utf8.DecodeRuneInString(s[index.Lower:])
	if r == utf8.RuneError {
		return 0, 0, errIndexNotAtRuneBoundary
	}
	return index.Lower, index.Lower + size, nil
}

func startsWithRuneBoundary(s string) bool {
	if s == "" {
		return true
	}
	r, _ := utf8.DecodeRuneInString(s)
	return r != utf8.RuneError
}

func endsWithRuneBoundary(s string) bool {
	if s == "" {
		return true
	}
	r, _ := utf8.DecodeLastRuneInString(s)
	return r != utf8.RuneError
}
