package slices

import "bytes"

{{with $types := .}}{{range $k := $types}}

// Merge uses a k-way merge to merge n collections of sorted byte slices.
//
// The resulting slice is returned in ascending order, with any duplicate values
// removed.
func MergeSorted{{$k.Name}}(n ...[]{{$k.Type}}) []{{$k.Type}} {
	var result []{{$k.Type}}
	if len(n) == 0 {
		return nil
	} else if len(n) == 1 {
		// Special case. Merge single slice with a nil slice, to remove any
		// duplicates from the single slice.
		return MergeSorted{{$k.Name}}(n[0], nil)
	}

	var maxSize int
	for _, a := range n {
		if len(a) > maxSize {
			maxSize = len(a)
		}
	}
	result = make([]{{$k.Type}}, 0, maxSize) // This will likely be too small but it's a start.

	idxs := make([]int, len(n)) // Indexes we've processed.
	var j int                   // Index we currently think is minimum.
{{if eq $k.Name "Bytes" }}
	var cmp int                 // Result of comparing most recent value.
{{end}}
	for {
		j = -1

		// Find the smallest minimum in all slices.
		for i := 0; i < len(n); i++ {
			if idxs[i] >= len(n[i]) {
				continue // We have completely drained all values in this slice.
			} else if j == -1 {
				// We haven't picked the minimum value yet. Pick this one.
				j = i
				continue
			}

			// It this value key is lower than the candidate.
{{if eq $k.Name "Bytes" }}
            cmp = bytes.Compare(n[i][idxs[i]], n[j][idxs[j]])
			if cmp == -1 {
				j = i
			} else if cmp == 0 {
				// Duplicate value. Throw it away.
				idxs[i]++
			}
{{else}}
			if n[i][idxs[i]] < n[j][idxs[j]] {
				j = i
			} else if n[i][idxs[i]] == n[j][idxs[j]] {
				// Duplicate value. Throw it away.
				idxs[i]++
			}
{{end}}
		}

		// We could have drained all of the values and be done...
		if j == -1 {
			break
		}

		// First value to just append it and move on.
		if len(result) == 0 {
			result = append(result, n[j][idxs[j]])
			idxs[j]++
			continue
		}

		// Append the minimum value to results if it's not a duplicate of
		// the existing one.
{{if eq $k.Name "Bytes" }}
            cmp = bytes.Compare(result[len(result)-1], n[j][idxs[j]])
			if cmp == -1 {
				result = append(result, n[j][idxs[j]])
			} else if cmp == 0 {
				// Duplicate so drop it.
			}  else {
                panic("value being merged out of order.")
            }
{{else}}
			if result[len(result)-1] < n[j][idxs[j]] {
				result = append(result, n[j][idxs[j]])
			} else if result[len(result)-1] == n[j][idxs[j]] {
				// Duplicate so drop it.
			} else {
                panic("value being merged out of order.")
            }
{{end}}
			idxs[j]++
	}
	return result
}


{{end}}{{end}}