package routing

import (
	
	
)

const priorityQueueEntryChunkSize = 256

// priorityQueue is an indexed binary min-heap. Entries keep their heap index
// so Dijkstra's algorithm can lower a queued distance without a map lookup.
// Equal priorities are popped in insertion order.
type priorityQueue struct {
	items       []*priorityQueueEntry
	entryChunks [][]priorityQueueEntry
	entryCursor int
	nextOrder   uint64
}

type priorityQueueEntry struct {
	node         *OVGNode
	isHorizontal bool
	priority     float64
	index        int
	order        uint64
}

// reset empties the queue while retaining storage. Entries returned before a
// reset must not be used afterward.
func ( *priorityQueue) () {
	clear(.items)
	.items = .items[:0]
	.entryCursor = 0
	.nextOrder = 0
}

func ( *priorityQueue) () bool {
	return len(.items) == 0
}

func ( *priorityQueue) ( float64,  *OVGNode,  bool,  workBudget) (*priorityQueueEntry, error) {
	if  := reservePriorityQueueWork(, len(.items)+1, 1);  != nil {
		return nil, 
	}

	 := .allocateEntry()
	.node = 
	.isHorizontal = 
	.index = len(.items)
	.order = .nextOrder
	.nextOrder++
	.items = append(.items, )
	.siftUp(.index)
	return , nil
}

func ( *priorityQueue) ( workBudget) (*priorityQueueEntry, error) {
	if .empty() {
		return nil, fmt.Errorf("cannot dequeue minimum of empty priority queue")
	}
	if  := reservePriorityQueueWork(, len(.items), 2);  != nil {
		return nil, 
	}

	 := .items[0]
	 := len(.items) - 1
	 := .items[]
	.items[] = nil
	.items = .items[:]
	.index = -1

	if  != 0 {
		.items[0] = 
		.index = 0
		.siftDown(0)
	}
	return , nil
}

func ( *priorityQueue) ( *priorityQueueEntry,  float64,  workBudget) error {
	if .empty() {
		return fmt.Errorf("cannot decrease priority in an empty priority queue")
	}
	if  == nil {
		return fmt.Errorf("cannot decrease priority: entry is nil")
	}
	if .index < 0 || .index >= len(.items) || .items[.index] !=  {
		return fmt.Errorf("cannot decrease priority: entry is not in the priority queue")
	}
	if  >= .priority {
		return fmt.Errorf("new priority %v is not less than old priority %v", , .priority)
	}
	if  := reservePriorityQueueWork(, .index+1, 1);  != nil {
		return 
	}

	.priority = 
	.siftUp(.index)
	return nil
}

func reservePriorityQueueWork( workBudget, ,  int) error {
	if  == nil {
		return nil
	}
	return .add(uint64(bits.Len(uint()) * ))
}

func ( *priorityQueue) ( float64) *priorityQueueEntry {
	 := .entryCursor / priorityQueueEntryChunkSize
	 := .entryCursor % priorityQueueEntryChunkSize
	if  == len(.entryChunks) {
		.entryChunks = append(.entryChunks, make([]priorityQueueEntry, priorityQueueEntryChunkSize))
	}
	.entryCursor++

	 := &.entryChunks[][]
	* = priorityQueueEntry{priority: , index: -1}
	return 
}

func ( *priorityQueue) ( int) {
	for  > 0 {
		 := ( - 1) / 2
		if !.less(, ) {
			return
		}
		.swap(, )
		 = 
	}
}

func ( *priorityQueue) ( int) {
	for {
		 := *2 + 1
		if  >= len(.items) {
			return
		}
		 := 
		 :=  + 1
		if  < len(.items) && .less(, ) {
			 = 
		}
		if !.less(, ) {
			return
		}
		.swap(, )
		 = 
	}
}

func ( *priorityQueue) (,  int) bool {
	return priorityQueueEntryLess(.items[], .items[])
}

func priorityQueueEntryLess(,  *priorityQueueEntry) bool {
	if .priority != .priority {
		return .priority < .priority
	}
	// Preserve insertion order for equal-cost states. Route selection should not
	// depend on the binary heap's internal shape.
	return .order < .order
}

func ( *priorityQueue) (,  int) {
	.items[], .items[] = .items[], .items[]
	.items[].index = 
	.items[].index = 
}