package plist

import (
	"strings"

	"github.com/474420502/focus/compare"
	"github.com/474420502/focus/list"
	"github.com/davecgh/go-spew/spew"
)

type Node struct {
	prev, next *Node
	value      interface{}
}

type PriorityList struct {
	head, tail *Node
	size       uint
	Compare    compare.Compare
}

// 优先队列的Index 正负都有作用要定义一种新的接口类型
func assertImplementation() {
	var _ list.IList = (*PriorityList)(nil)
}

func New(Compare compare.Compare) *PriorityList {
	pl := &PriorityList{head: &Node{}, tail: &Node{}, size: 0, Compare: Compare}
	pl.head.next = pl.tail
	pl.tail.prev = pl.head
	return pl
}

func (pl *PriorityList) String() string {
	content := ""

	cur := pl.head.next

	for ; cur != pl.tail; cur = cur.next {
		content += spew.Sprint(cur.value) + " "
	}
	content = strings.TrimRight(content, " ")
	return content
}

func (pl *PriorityList) RString() string {
	content := ""

	cur := pl.tail.prev

	for ; cur != pl.head; cur = cur.prev {
		content += spew.Sprint(cur.value) + " "
	}
	content = strings.TrimRight(content, " ")
	return content
}

func (pl *PriorityList) Iterator() *Iterator {
	return &Iterator{pl: pl, cur: pl.head}
}

func (pl *PriorityList) CircularIterator() *CircularIterator {
	return &CircularIterator{pl: pl, cur: pl.head}
}

func (pl *PriorityList) Size() uint {
	return pl.size
}

func (pl *PriorityList) Empty() bool {
	return pl.size == 0
}

func (pl *PriorityList) Clear() {
	pl.head.next = pl.tail
	pl.tail.prev = pl.head
	pl.size = 0
}

func (pl *PriorityList) Push(value interface{}) {
	pl.size++
	pnode := &Node{value: value}
	if pl.size == 1 {
		pl.head.next = pnode
		pl.tail.prev = pnode
		pnode.prev = pl.head
		pnode.next = pl.tail
		return
	}

	cur := pl.head
	for ; cur.next != pl.tail; cur = cur.next {
		if pl.Compare(value, cur.next.value) > 0 {
			cnext := cur.next

			cur.next = pnode
			cnext.prev = pnode
			pnode.prev = cur
			pnode.next = cnext

			return
		}
	}

	cur.next = pnode
	pnode.prev = cur
	pnode.next = pl.tail
	pl.tail.prev = pnode
}

func (pl *PriorityList) Top() (result interface{}, ok bool) {
	if pl.size > 0 {
		return pl.head.next.value, true
	}
	return nil, false
}

func (pl *PriorityList) Pop() (result interface{}, ok bool) {
	if pl.size > 0 {
		pl.size--
		temp := pl.head.next
		temp.next.prev = pl.head
		pl.head.next = temp.next
		return temp.value, true
	}
	return nil, false
}

func (pl *PriorityList) Index(idx int) (interface{}, bool) {
	if n, ok := pl.GetNode(idx); ok {
		return n.value, true
	}
	return nil, false
}

func (l *PriorityList) Contains(values ...interface{}) bool {

	for _, searchValue := range values {
		found := false
		for cur := l.head.next; cur != l.tail; cur = cur.next {
			if cur.value == searchValue {
				found = true
				break
			}
		}

		if !found {
			return false
		}
	}
	return true
}

func (pl *PriorityList) GetNode(idx int) (*Node, bool) {
	if idx >= 0 {
		cur := pl.head.next
		for i := 0; cur != pl.tail; i++ {
			if i == idx {
				return cur, true
			}
			cur = cur.next
		}
	} else {
		cur := pl.tail.prev
		for i := -1; cur != pl.head; i-- {
			if i == idx {
				return cur, true
			}
			cur = cur.prev
		}
	}
	return nil, false
}

func (pl *PriorityList) RemoveWithIndex(idx int) {
	if n, ok := pl.GetNode(idx); ok {
		pl.RemoveNode(n)
	}
}

func (pl *PriorityList) Remove(idx int) (result interface{}, isfound bool) {
	if n, ok := pl.GetNode(idx); ok {
		pl.RemoveNode(n)
		return n.value, true
	}
	return nil, false
}

func (pl *PriorityList) RemoveNode(node *Node) {

	prev := node.prev
	next := node.next
	prev.next = next
	next.prev = prev

	node.prev = nil
	node.next = nil

	pl.size--
}
func (pl *PriorityList) Values() []interface{} {
	values := make([]interface{}, pl.size, pl.size)
	for i, cur := 0, pl.head.next; cur != pl.tail; i, cur = i+1, cur.next {
		values[i] = cur.value
	}
	return values
}

func (l *PriorityList) Traversal(every func(interface{}) bool) {
	for cur := l.head.next; cur != l.tail; cur = cur.next {
		if !every(cur.value) {
			break
		}
	}
}