package main

import "fmt"

type Node[T comparable] struct {
	val  T
	next *Node[T]
}

func (elem *Node[T]) Add(newVal T) {
	currPos := elem.GoToEnd()
	currPos.next = &Node[T]{val: newVal, next: nil}
}

func (elem *Node[T]) GoToEnd() *Node[T] {
	currPos := elem
	for currPos.next != nil {
		currPos = currPos.next
	}
	return currPos
}

func (elem *Node[T]) GoToPosition(len int) *Node[T] {
	currPos := elem
	index := 0
	for currPos.next != nil && index != len {
		currPos = currPos.next
		index++
	}
	return currPos
}

func (elem *Node[T]) Insert(newVal T, index int) {
	currPos := elem.GoToPosition(index - 1)
	nextNode := currPos.next
	currPos.next = &Node[T]{val: newVal, next: nextNode}
}

func (elem Node[T]) Index(cmpVal T) int {
	currPos := &elem
	index := 0
	for currPos != nil && currPos.val != cmpVal {
		currPos = currPos.next
		index++
	}
	if currPos == nil {
		return -1
	}
	return index
}

func (elem Node[T]) GoToEndWithOutput() {
	currPos := elem
	for currPos.next != nil {
		fmt.Println(currPos)
		currPos = *currPos.next
	}
	fmt.Println(currPos)
}

func main() {
	linkedList := Node[int]{val: 12}
	linkedList.Add(4)
	linkedList.GoToEndWithOutput()
	fmt.Println()
	linkedList.Add(7)
	linkedList.GoToEndWithOutput()
	fmt.Println()
	linkedList.Add(22)
	linkedList.GoToEndWithOutput()
	fmt.Println()
	linkedList.Add(65)
	linkedList.GoToEndWithOutput()
	fmt.Println()
	linkedList.Add(2)
	linkedList.GoToEndWithOutput()
	fmt.Println()
	linkedList.Add(3)
	linkedList.GoToEndWithOutput()
	fmt.Println()
	linkedList.Add(1)
	linkedList.GoToEndWithOutput()
	fmt.Println()
	linkedList.Insert(10, 4)
	linkedList.GoToEndWithOutput()
	fmt.Println()
	linkedList.Insert(11, 5)
	linkedList.GoToEndWithOutput()
	fmt.Println()
	fmt.Println(linkedList.Index(11))
}
