// This file provides functions for sorting colors.

package colorful

import (
	
	
)

// An element represents a single element of a set.  It is used to
// implement a disjoint-set forest.
type element struct {
	parent *element // Parent element
	rank   int      // Rank (approximate depth) of the subtree with this element as root
}

// newElement creates a singleton set and returns its sole element.
func newElement() *element {
	 := &element{}
	.parent = 
	return 
}

// find returns an arbitrary element of a set when invoked on any element of
// the set, The important feature is that it returns the same value when
// invoked on any element of the set.  Consequently, it can be used to test if
// two elements belong to the same set.
func ( *element) () *element {
	for .parent !=  {
		.parent = .parent.parent
		 = .parent
	}
	return 
}

// union establishes the union of two sets when given an element from each set.
// Afterwards, the original sets no longer exist as separate entities.
func union(,  *element) {
	// Ensure the two elements aren't already part of the same union.
	 := .find()
	 := .find()
	if  ==  {
		return
	}

	// Create a union by making the shorter tree point to the root of the
	// larger tree.
	switch {
	case .rank < .rank:
		.parent = 
	case .rank > .rank:
		.parent = 
	default:
		.parent = 
		.rank++
	}
}

// An edgeIdxs describes an edge in a graph or tree.  The vertices in the edge
// are indexes into a list of Color values.
type edgeIdxs [2]int

// An edgeDistance is a map from an edge (pair of indices) to a distance
// between the two vertices.
type edgeDistance map[edgeIdxs]float64

// allToAllDistancesCIEDE2000 computes the CIEDE2000 distance between each pair of
// colors.  It returns a map from a pair of indices (u, v) with u < v to a
// distance.
func allToAllDistancesCIEDE2000( []Color) edgeDistance {
	 := len()
	 := make(edgeDistance, *)
	for  := 0;  < -1; ++ {
		for  :=  + 1;  < ; ++ {
			[edgeIdxs{, }] = [].DistanceCIEDE2000([])
		}
	}
	return 
}

// sortEdges sorts all edges in a distance map by increasing vertex distance.
func sortEdges( edgeDistance) []edgeIdxs {
	 := make([]edgeIdxs, 0, len())
	for  := range  {
		 = append(, )
	}
	sort.Slice(, func(,  int) bool {
		return [[]] < [[]]
	})
	return 
}

// minSpanTree computes a minimum spanning tree from a vertex count and a
// distance-sorted edge list.  It returns the subset of edges that belong to
// the tree, including both (u, v) and (v, u) for each edge.
func minSpanTree( int,  []edgeIdxs) map[edgeIdxs]struct{} {
	// Start with each vertex in its own set.
	 := make([]*element, )
	for  := range  {
		[] = newElement()
	}

	// Run Kruskal's algorithm to construct a minimal spanning tree.
	 := make(map[edgeIdxs]struct{}, )
	for ,  := range  {
		,  := [0], [1]
		if [].find() == [].find() {
			continue // Same set: edge would introduce a cycle.
		}
		[] = struct{}{}
		[edgeIdxs{, }] = struct{}{}
		union([], [])
	}
	return 
}

// traverseMST walks a minimum spanning tree in prefix order.
func traverseMST( map[edgeIdxs]struct{},  int) []int {
	// Compute a list of neighbors for each vertex.
	 := make(map[int][]int, len())
	for  := range  {
		,  := [0], [1]
		[] = append([], )
	}
	for ,  := range  {
		sort.Ints()
		copy([], )
	}

	// Walk the tree from a given vertex.
	 := make([]int, 0, len())
	 := make(map[int]bool, len())
	var  func(int)
	 = func( int) {
		// Visit the starting vertex.
		 = append(, )
		[] = true

		// Recursively visit each child in turn.
		for ,  := range [] {
			if ![] {
				()
			}
		}
	}
	()
	return 
}

// Sorted sorts a list of Color values.  Sorting is not a well-defined operation
// for colors so the intention here primarily is to order colors so that the
// transition from one to the next is fairly smooth.
func ( []Color) []Color {
	// Do nothing in trivial cases.
	 := make([]Color, len())
	if len() < 2 {
		copy(, )
		return 
	}

	// Compute the distance from each color to every other color.
	 := allToAllDistancesCIEDE2000()

	// Produce a list of edges in increasing order of the distance between
	// their vertices.
	 := sortEdges()

	// Construct a minimum spanning tree from the list of edges.
	 := minSpanTree(len(), )

	// Find the darkest color in the list.
	var  Color
	var  int             // Index of darkest color
	 := math.MaxFloat64 // Lightness of darkest color (distance from black)
	for ,  := range  {
		 := .DistanceCIEDE2000()
		if  <  {
			 = 
			 = 
		}
	}

	// Traverse the tree starting from the darkest color.
	 := traverseMST(, )

	// Convert the index list to a list of colors, overwriting the input.
	for ,  := range  {
		[] = []
	}
	return 
}