package linkedlist

import (
	"fmt"

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

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

func (node *Node) Value() interface{} {
	return node.value
}

type LinkedList struct {
	head *Node
	tail *Node
	size uint
}

func assertImplementation() {
	var _ list.IList = (*LinkedList)(nil)
	var _ list.ILinkedList = (*LinkedList)(nil)
}

func New() *LinkedList {
	l := &LinkedList{}
	l.head = &Node{}
	l.head.prev = nil

	l.tail = &Node{}
	l.tail.next = nil

	l.head.next = l.tail
	l.tail.prev = l.head
	return l
}

func (l *LinkedList) Iterator() *Iterator {
	return &Iterator{ll: l, cur: l.head}
}

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

func (l *LinkedList) Clear() {

	l.head.next = l.tail
	l.tail.prev = l.head

	l.size = 0
}

func (l *LinkedList) Empty() bool {
	return l.size == 0
}

func (l *LinkedList) Size() uint {
	return l.size
}

func (l *LinkedList) Push(value interface{}) {
	var node *Node
	l.size++

	node = &Node{}
	node.value = value

	tprev := l.tail.prev
	tprev.next = node

	node.prev = tprev
	node.next = l.tail
	l.tail.prev = node
}

func (l *LinkedList) PushFront(values ...interface{}) {

	var node *Node
	l.size += uint(len(values))
	for _, v := range values {
		node = &Node{}
		node.value = v

		hnext := l.head.next
		hnext.prev = node

		node.next = hnext
		node.prev = l.head
		l.head.next = node
	}
}

func (l *LinkedList) PushBack(values ...interface{}) {

	var node *Node
	l.size += uint(len(values))
	for _, v := range values {
		node = &Node{}
		node.value = v

		tprev := l.tail.prev
		tprev.next = node

		node.prev = tprev
		node.next = l.tail
		l.tail.prev = node
	}
}

func (l *LinkedList) PopFront() (result interface{}, found bool) {
	if l.size != 0 {
		l.size--

		temp := l.head.next
		hnext := temp.next
		hnext.prev = l.head
		l.head.next = hnext

		result = temp.value
		found = true
		return
	}
	return nil, false
}

func (l *LinkedList) PopBack() (result interface{}, found bool) {
	if l.size != 0 {
		l.size--

		temp := l.tail.prev
		tprev := temp.prev
		tprev.next = l.tail
		l.tail.prev = tprev

		result = temp.value
		found = true
		return
	}
	return nil, false
}

func (l *LinkedList) Front() (result interface{}, found bool) {
	if l.size != 0 {
		return l.head.next.value, true
	}
	return nil, false
}

func (l *LinkedList) Back() (result interface{}, found bool) {
	if l.size != 0 {
		return l.tail.prev.value, true
	}
	return nil, false
}

func (l *LinkedList) Find(every func(idx uint, value interface{}) bool) (interface{}, bool) {

	idx := uint(0)
	// 头部
	for cur := l.head.next; cur != l.tail; cur = cur.next {
		if every(idx, cur.value) {
			return cur.value, true
		}
		idx++
	}
	return nil, false
}

func (l *LinkedList) FindMany(every func(idx uint, value interface{}) int) (result []interface{}, isfound bool) {
	// the default of isfould  is  false
	idx := uint(0)
	// 头部
	for cur := l.head.next; cur != l.tail; cur = cur.next {
		j := every(idx, cur.value)
		switch {
		case j > 0:
			result = append(result, cur.value)
			isfound = true
		case j < 0:
			return result, isfound
		}
		idx++
	}
	return result, isfound
}

func (l *LinkedList) Index(idx int) (interface{}, bool) {

	if idx < 0 {
		return nil, false
	}
	var uidx = (uint)(idx)

	if uidx >= l.size || idx < 0 {
		return nil, false
	}

	if uidx > l.size/2 {
		uidx = l.size - 1 - uidx
		// 尾部
		for cur := l.tail.prev; cur != l.head; cur = cur.prev {
			if uidx == 0 {
				return cur.value, true
			}
			uidx--
		}

	} else {
		// 头部
		for cur := l.head.next; cur != l.tail; cur = cur.next {
			if uidx == 0 {
				return cur.value, true
			}
			uidx--
		}
	}

	return nil, false
}

func (l *LinkedList) Insert(idx uint, values ...interface{}) bool {
	if idx > l.size { // 插入的方式 可能导致size的范围判断不一样
		return false
	}

	if idx > l.size/2 {
		idx = l.size - idx
		// 尾部
		for cur := l.tail.prev; cur != nil; cur = cur.prev {

			if idx == 0 {

				var start *Node
				var end *Node

				start = &Node{value: values[0]}
				end = start

				for _, value := range values[1:] {
					node := &Node{value: value}
					end.next = node
					node.prev = end
					end = node
				}

				cnext := cur.next

				cur.next = start
				start.prev = cur

				end.next = cnext
				cnext.prev = end

				break
			}

			idx--
		}

	} else {
		// 头部
		for cur := l.head.next; cur != nil; cur = cur.next {
			if idx == 0 {

				var start *Node
				var end *Node

				start = &Node{value: values[0]}
				end = start

				for _, value := range values[1:] {
					node := &Node{value: value}
					end.next = node
					node.prev = end
					end = node
				}

				cprev := cur.prev

				cprev.next = start
				start.prev = cprev

				end.next = cur
				cur.prev = end

				break
			}

			idx--
		}
	}

	l.size += uint(len(values))
	return true
}

// InsertState InsertIf的every函数的枚举  从左到右 1 为前 2 为后 insert here(2) ->cur-> insert here(1)
// UninsertAndContinue 不插入并且继续
// UninsertAndBreak 不插入并且停止
// InsertBack cur后插入并且停止
// InsertFront cur前插入并且停止
type InsertState int

const (
	// UninsertAndContinue 不插入并且继续
	UninsertAndContinue InsertState = 0
	// UninsertAndBreak 不插入并且停止
	UninsertAndBreak InsertState = -1
	// InsertBack cur后插入并且停止
	InsertBack InsertState = 2
	// InsertFront cur前插入并且停止
	InsertFront InsertState = 1
)

// InsertIf  every函数的枚举  从左到右遍历 1 为前 2 为后 insert here(2) ->cur-> insert here(1)
func (l *LinkedList) InsertIf(every func(idx uint, value interface{}) InsertState, values ...interface{}) {

	idx := uint(0)
	// 头部
	for cur := l.head.next; cur != nil; cur = cur.next {
		insertState := every(idx, cur.value)

		if insertState == UninsertAndContinue {
			continue
		}

		if insertState > 0 { // 1 为前 2 为后 insert here(2) ->cur-> insert here(1)
			var start *Node
			var end *Node

			start = &Node{value: values[0]}
			end = start

			for _, value := range values[1:] {
				node := &Node{value: value}
				end.next = node
				node.prev = end
				end = node
			}

			if insertState == InsertBack {
				cprev := cur.prev
				cprev.next = start
				start.prev = cprev
				end.next = cur
				cur.prev = end
			} else { // InsertFront
				cnext := cur.next
				cnext.prev = end
				start.prev = cur
				cur.next = start
				end.next = cnext
			}

			l.size += uint(len(values))
			return
		}

		// 必然 等于 UninsertAndBreak
		return
	}
}

func remove(cur *Node) {
	curPrev := cur.prev
	curNext := cur.next
	curPrev.next = curNext
	curNext.prev = curPrev
	cur.prev = nil
	cur.next = nil
}

func (l *LinkedList) Remove(idx int) (interface{}, bool) {

	if idx < 0 {
		return nil, false
	}

	var uidx uint = (uint)(idx)
	if l.size <= uidx {
		// log.Printf("out of list range, size is %d, idx is %d\n", l.size, idx)
		return nil, false
	}

	l.size--
	if uidx > l.size/2 {
		uidx = l.size - uidx // l.size - 1 - idx,  先减size
		// 尾部
		for cur := l.tail.prev; cur != l.head; cur = cur.prev {
			if uidx == 0 {
				remove(cur)
				return cur.value, true
			}
			uidx--
		}

	} else {
		// 头部
		for cur := l.head.next; cur != l.tail; cur = cur.next {
			if uidx == 0 {
				remove(cur)
				return cur.value, true

			}
			uidx--
		}
	}

	panic(fmt.Sprintf("unknown error"))
}

// RemoveState RemoveIf的every函数的枚举
// RemoveAndContinue 删除并且继续
// RemoveAndBreak 删除并且停止
// UnremoveAndBreak 不删除并且停止遍历
// UnremoveAndContinue 不删除并且继续遍历
type RemoveState int

const (
	// RemoveAndContinue 删除并且继续
	RemoveAndContinue RemoveState = iota
	// RemoveAndBreak 删除并且停止
	RemoveAndBreak
	// UnremoveAndBreak 不删除并且停止遍历
	UnremoveAndBreak
	// UnremoveAndContinue 不删除并且继续遍历
	UnremoveAndContinue
)

// RemoveIf every的遍历函数操作remove过程 如果没删除result 返回nil, isRemoved = false
func (l *LinkedList) RemoveIf(every func(idx uint, value interface{}) RemoveState) (result []interface{}, isRemoved bool) {
	// 头部
	idx := uint(0)
TOPFOR:
	for cur := l.head.next; cur != l.tail; idx++ {
		removeState := every(idx, cur.value)
		switch removeState {
		case RemoveAndContinue:
			result = append(result, cur.value)
			isRemoved = true
			temp := cur.next
			remove(cur)
			cur = temp
			l.size--
			continue TOPFOR
		case RemoveAndBreak:
			result = append(result, cur.value)
			isRemoved = true
			temp := cur.next
			remove(cur)
			cur = temp
			l.size--
			return
		case UnremoveAndContinue:
		case UnremoveAndBreak:
			return
		}

		cur = cur.next
	}
	return
}

func (l *LinkedList) 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 (l *LinkedList) Values() (result []interface{}) {
	l.Traversal(func(value interface{}) bool {
		result = append(result, value)
		return true
	})
	return
}

func (l *LinkedList) String() string {
	return spew.Sprint(l.Values())
}

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