package slice_test

import (
	"errors"
	"fmt"
	"slices"
	"strings"

	"github.com/creachadair/mds/slice"
)

func isOdd(v int) bool  { return v%2 == 1 }
func isEven(v int) bool { return v%2 == 0 }

func ExamplePartition() {
	vs := []int{3, 1, 8, 4, 2, 6, 9, 10, 5, 7}

	// After partitioning, odd is a prefix of vs, which has been rearranged to
	// contain only the odd elements in their original order.
	odd := slice.Partition(vs, isOdd)

	// Reslice the input after the length of the partition if you
	// want to address the un-kept elements explicitly.
	// Note that their order is unspecified, however, so we sort
	// them for stable example output.
	rest := vs[len(odd):]
	slices.Sort(rest)

	fmt.Println(odd)
	fmt.Println(rest)
	// Output:
	// [3 1 9 5 7]
	// [2 4 6 8 10]
}

func ExampleMatchingKeys() {
	vs := map[string]int{"red": 3, "yellow": 6, "blue": 4, "green": 5}

	for key := range slice.MatchingKeys(vs, isEven) {
		fmt.Println(key, vs[key])
	}
	// Unordered output:
	// blue 4
	// yellow 6
}

func ExampleRotate() {
	vs := []int{8, 6, 7, 5, 3, 0, 9}

	slice.Rotate(vs, -3)
	fmt.Println(vs)
	// Output:
	// [5 3 0 9 8 6 7]
}

func ExampleChunks() {
	vs := strings.Fields("my heart is a fish hiding in the water grass")

	for c := range slice.Chunks(vs, 3) {
		fmt.Println(c)
	}
	// Output:
	// [my heart is]
	// [a fish hiding]
	// [in the water]
	// [grass]
}

func ExampleBatches() {
	vs := strings.Fields("the freckles in our eyes are mirror images that when we kiss are perfectly aligned")

	for b := range slice.Batches(vs, 4) {
		fmt.Println(b)
	}
	// Output:
	// [the freckles in our]
	// [eyes are mirror images]
	// [that when we kiss]
	// [are perfectly aligned]
}

func ExampleLCS() {
	fmt.Println(slice.LCS(
		[]int{1, 0, 3, 4, 2, 7, 9, 9},
		[]int{1, 3, 5, 7, 9, 11},
	))
	// Output:
	// [1 3 7 9]
}

func ExampleEditScript() {
	lhs := strings.Fields("if you mix red with green you get blue")
	rhs := strings.Fields("red mixed with green does not give blue at all")

	fmt.Println("start", lhs)
	var out []string
	for _, e := range slice.EditScript(lhs, rhs) {
		switch e.Op {
		case slice.OpDrop:
			fmt.Println("drop", e.X)
		case slice.OpEmit:
			fmt.Println("emit", e.X)
			out = append(out, e.X...)
		case slice.OpCopy:
			fmt.Println("copy", e.Y)
			out = append(out, e.Y...)
		case slice.OpReplace:
			fmt.Println("replace", e.X, "with", e.Y)
			out = append(out, e.Y...)
		default:
			panic("invalid")
		}
	}
	fmt.Println("end", out)
	// Output:
	// start [if you mix red with green you get blue]
	// drop [if you mix]
	// emit [red]
	// copy [mixed]
	// emit [with green]
	// replace [you get] with [does not give]
	// emit [blue]
	// copy [at all]
	// end [red mixed with green does not give blue at all]
}

func ExampleMap() {
	ss := []string{"apple", "pear", "plum", "cherry"}
	errs := slice.Map(ss, func(s string) error {
		if len(s) > 4 {
			return errors.New("too long")
		}
		return nil
	})
	fmt.Println(errs)
	// Output:
	// [too long <nil> <nil> too long]
}
