package tst

import (
	"fmt"
)

type (
	Node struct {
		key byte
		value interface{}
		left, middle, right *Node
	}
	NodeIterator struct {
		step int
		node *Node
		prev *NodeIterator
	}
	TernarySearchTree struct {
		length int
		root *Node
	}
)

// Create a new ternary search tree
func New() *TernarySearchTree {
	tree := &TernarySearchTree{}
	tree.Init()
	return tree
}
// Iterate over the collection
func (this *TernarySearchTree) Do(callback func(string, interface{})bool) {
	if this.Len() == 0 {
		return
	}
	bs := []byte{}
	i := &NodeIterator{0,this.root,nil}
	for i != nil {
		switch i.step {
		// Left
		case 0:
			i.step++
			if i.node.left != nil {
				i = &NodeIterator{0,i.node.left,i}
				continue
			}
		// Value
		case 1:
			i.step++
			if i.node.key > 0 {
				bs = append(bs, i.node.key)
			}
			if i.node.value != nil {
				if !callback(string(bs), i.node.value) {
					return
				}
				continue
			}
		// Middle
		case 2:
			i.step++
			if i.node.middle != nil {
				i = &NodeIterator{0,i.node.middle,i}
				continue
			}
		// Right
		case 3:
			if len(bs) > 0 {
				bs = bs[:len(bs)-1]
			}
			i.step++
			if i.node.right != nil {
				i = &NodeIterator{0,i.node.right,i}
				continue
			}
		// Backtrack
		case 4:
			i = i.prev
		}
	}
}
// Get the value at the specified key. Returns nil if not found.
func (this *TernarySearchTree) Get(key string) interface{} {
	if this.length == 0 {
		return nil
	}

	node := this.root
	bs := []byte(key)
	for i := 0; i < len(bs); {
		b := bs[i]
		if b > node.key {
			if node.right == nil {
				return nil
			}
			node = node.right
		} else if (b < node.key) {
			if node.left == nil {
				return nil
			}
			node = node.left
		} else {
			i++
			if i < len(bs) {
				if node.middle == nil {
					return nil
				}
				node = node.middle
			} else {
				break
			}
		}
	}
	return node.value
}
func (this *TernarySearchTree) GetLongestPrefix(key string) interface{} {
	if this.length == 0 {
		return nil
	}

	n := this.root
	v := n.value
	bs := []byte(key)
	for i := 0; i < len(bs); {
		b := bs[i]
		if n.value != nil {
			v = n.value
		}
		if b > n.key {
			if n.right == nil {
				break
			}
			n = n.right
		} else if b < n.key {
			if n.left == nil {
				break
			}
			n = n.left
		} else {
			i++
			if i < len(bs) {
				if n.middle == nil {
					break
				}
				n = n.middle
			} else {
				break
			}
		}
	}
	if n.value != nil {
		v = n.value
	}
	return v
}
// Test to see whether or not the given key is contained in the tree.
func (this *TernarySearchTree) Has(key string) bool {
	return this.Get(key) != nil
}
// Initialize the tree (reset it so that it's empty). New will do this for you.
func (this *TernarySearchTree) Init() {
	this.length = 0
	this.root = nil
}
// Insert a new key value pair into the collection
func (this *TernarySearchTree) Insert(key string, value interface{}) {
	// If the value is nil then remove this key from the collection
	if value == nil {
		this.Remove(key)
		return
	}

	if this.length == 0 {
		this.root = &Node{0,nil,nil,nil,nil}
	}

	t := this.root
	bs := []byte(key)
	for i := 0; i < len(bs); {
		b := bs[i]
		if b > t.key {
			if t.right == nil {
				t.right = &Node{b,nil,nil,nil,nil}
			}
			t = t.right
		} else if b < t.key {
			if t.left == nil {
				t.left = &Node{b,nil,nil,nil,nil}
			}
			t = t.left
		} else {
			i++
			if i < len(bs) {
				if t.middle == nil {
					t.middle = &Node{bs[i],nil,nil,nil,nil}
				}
				t = t.middle
			}
		}
	}

	if t.value == nil {
		this.length++
	}
	t.value = value
}
// Get the number of items stored in the tree
func (this *TernarySearchTree) Len() int {
	return this.length
}
// Remove a key from the collection
func (this *TernarySearchTree) Remove(key string) interface{} {
	if this.length == 0 {
		return nil
	}

	var remove *Node
	var direction int

	t := this.root
	bs := []byte(key)
	for i := 0; i < len(bs); {
		b := bs[i]
		if b > t.key {
			// Not in the collection
			if t.right == nil {
				return nil
			}
			// This is a branch so we have to keep it
			remove = t
			direction = 1
			// Move to the next node
			t = t.right
		} else if b < t.key {
			// Not in the collection
			if t.left == nil {
				return nil
			}
			// This is a branch so we have to keep it
			remove = t
			direction = -1
			// Move to the next node
			t = t.left
		} else {
			i++
			if i < len(bs) {
				// Not in the collection
				if t.middle == nil {
					return nil
				}
				// Has a value so we need to keep at least this much
				if t.value != nil {
					remove = t
					direction = 0
				}
				// Move to the next node
				t = t.middle
			}
		}
	}

	// If this was the only item in the tree, set the root pointer to nil
	if this.length == 1 {
		this.root = nil
	} else {
		if direction == -1 {
			remove.left = nil
		} else if direction == 0 {
			remove.middle = nil
		} else {
			remove.right = nil
		}
	}
	this.length--
	return t.value
}
func (this *TernarySearchTree) String() string {
	if this.length == 0 {
		return "{}"
	}

	return this.root.String()
}
// Dump the tree to a string for easier debugging
func (this *Node) String() string {
	str := "{" + string(this.key)
	if this.value != nil {
		str += ":" + fmt.Sprint(this.value)
	}
	if this.left != nil {
		str += this.left.String()
	} else {
		str += " "
	}
	if this.middle != nil {
		str += this.middle.String()
	} else {
		str += " "
	}
	if this.right != nil {
		str += this.right.String()
	} else {
		str += " "
	}
	str += "}"
	return str
}
