package ui

import "strings"

// findOptimalFit tries to find the optimal (largest) fit for the interval [0..n] by doing a binary search.
func findOptimalFit(n int, fits func(i int) bool) int {
	if n < 0 || fits(n) {
		return n
	}
	min, max := 0, n
	for {
		if min == max {
			if min == 0 && !fits(min) {
				return -1
			}
			return min
		}
		middle := (max + min + 1) / 2
		if fits(middle) {
			min = middle
		} else {
			max = middle - 1
		}
	}
}

// findSpaces creates a slice with indices where spaces can be found in string s
func findSpaces(s string) []int {
	var spaces []int
	offset := 0
	for {
		space := strings.Index(s[offset:], " ")
		if space == -1 {
			return spaces
		}
		offset += space
		spaces = append(spaces, offset)
		offset++
	}
}

func fitTextEllipsis(font Font, text string, availableWidth float32) string {
	if font.WidthOf(text) <= availableWidth {
		return text
	}
	ellipsis := "..."
	availableWidth -= font.WidthOf(ellipsis)
	cut := findOptimalFit(len(text), func(i int) bool { return font.WidthOf(text[:i]) <= availableWidth })
	if cut == -1 {
		return ""
	}
	return text[:cut] + ellipsis
}

// fitTextWord tries to fit as much of string s in width space.
func fitTextWord(font Font, s string, availableWidth float32) string {
	if font.WidthOf(s) < availableWidth {
		return s
	}
	spaces := findSpaces(s)
	split := findOptimalFit(len(spaces)-1, func(i int) bool {
		return font.WidthOf(s[:spaces[i]]) <= availableWidth
	})
	if split == -1 {
		return s
	}
	return s[:spaces[split]]
}