package main
import (
    "fmt"
)
type Node struct { 
    value int
    next *Node
    prev *Node
}
func NewNode(val int) Node {
     return Node{value: val, next : nil, prev : nil}
}
type MyDoubleLinklist struct{
    head *Node
    tail *Node
    length int
}
func NewMyDoubleLinklist(value int) MyDoubleLinklist {
    newNode := NewNode(value)
    return MyDoubleLinklist{ head: &newNode, tail: &newNode, length: 1}
}
func (list *MyDoubleLinklist) append(value int) MyDoubleLinklist {
    newNode := NewNode(value)
    list.tail.next = &newNode
    newNode.prev = list.tail
    list.tail = &newNode
    list.length++
    return *list
}
func (list *MyDoubleLinklist) prepend(value int) MyDoubleLinklist {
    newNode := NewNode(value)
    newNode.next = list.head
    list.head.prev = &newNode
    list.head = &newNode
    list.length++
    return *list
}
func (list *MyDoubleLinklist) insert(index, value int) (MyDoubleLinklist, error) {
    if index < 0 || index > list.length {
        return *list, fmt.Errorf("invalid input index should be in 0 and %d", list.length)
    }
    
    if index == 0 {
        return list.prepend(value), nil
    } else if index == list.length {
        return list.append(value), nil
    }
    
    //get index node at index
    indexNode := list.traverseToIndexNode(index)
    newNode := NewNode(value)
    
    prevNode := indexNode.prev
     
    indexNode.prev = &newNode
    prevNode.next = &newNode
    newNode.prev = prevNode
    newNode.next = indexNode
    
    list.length++
    
    return *list, nil
}
func (list *MyDoubleLinklist) remove(index int) (MyDoubleLinklist, error) {
    if index < 0 || index > list.length {
        return *list, fmt.Errorf("invalid input index should be in 0 and %d", list.length)
    }
    if index == 0 {
        list.head.next = nil
        list.head = list.head.next
        return *list, nil
    } 
    
    //get leader node
    indexNode := list.traverseToIndexNode(index)
    prevNode := indexNode.prev
    nextNode := indexNode.next
    fmt.Printf("\n remove node at %d , leader is : %v", index, indexNode)
    prevNode.next = indexNode.next
    nextNode.prev = indexNode.prev
   
    
    return *list, nil
}
 //return node at index
func(list *MyDoubleLinklist) traverseToIndexNode(index int) *Node {
    idxNode := list.head
    c := 0
    for c < index {
        idxNode = idxNode.next
        c++
    }
    return idxNode
}
func(list *MyDoubleLinklist) print() {
    head := list.head
    for head != nil {
        fmt.Printf("%d \t", head.value)
        head = head.next
    }
    fmt.Println()
}
func(list *MyDoubleLinklist) printReverse() {
    fmt.Println("reverseList: ")
    tail := list.tail
    for tail != nil {
        fmt.Printf("%d \t", tail.value)
        tail = tail.prev
    }
    fmt.Println()
}
func main() {
    list := NewMyDoubleLinklist(5)
    list.append(12)
    list.append(10)
    list.prepend(15)
    list.prepend(1)
    
    list.print()
    list.printReverse()
    
    _, err := list.remove(2)
    if err != nil {
         fmt.Println("insert error: ", err)
    }
    
    fmt.Println("\nafter remove node at index 2")
    list.print()
    list.printReverse()
    
    _, err = list.insert(1, 100)
    if err != nil {
         fmt.Println("insert error: ", err)
    }
    
    fmt.Printf("\nafter insert node value %d at index %d \n", 100, 1)
    list.print()
    list.printReverse()
    
}