package main

import (
	"fmt"
	"sync"
)


//golang 红黑树
//只是实现了添加节点和一个分层打印节点的函数
//ref: https://www.jianshu.com/p/e136ec79235c

const (
	Red = 1
	Black = 2
)

type node struct {
	right  *node
	left   *node
	parent *node
	key    int
	color  int
}

type RBTree struct {
	root *node
	//the number of members
	len  int
}

//add operation occured only on leaf
//so just ignore the parent's original son node
//color of the added node is always red
func (n *node) addLeft(key int) *node {
	add := new(node)
	add.key = key
	add.color = Red
	add.parent = n
	n.left = add
	return add
}

//add operation occured only on leaf
//so just ignore the parent's original son node
//color of the added node is always red
func (n *node) addRight(key int) *node {
	add := new(node)
	add.key = key
	add.color = Red
	add.parent = n
	n.right = add
	return add
}

func (rb *RBTree) rotateLeft(n *node) {
	parent := n.parent
	right := n.right
	n.right = right.left
	if right.left != nil {
		right.left.parent = n
	}
	right.left = n
	n.parent = right
	if parent == nil {
		right.parent = nil
		rb.root = right
	} else {
		if n == parent.left {
			parent.left = right
		} else {
			parent.right = right
		}
		right.parent = parent
	}
}

func (rb *RBTree) rotateRight(n *node) {
	parent := n.parent
	left := n.left
	n.left = left.right
	if left.right != nil {
		left.right.parent = n
	}
	left.right = n
	n.parent = left
	if parent == nil {
		left.parent = nil
		rb.root = left
	} else {
		if n == parent.left {
			parent.left = left
		} else {
			parent.right = left
		}
		left.parent = parent
	}
}

func (rb *RBTree) insert(key int) {
	if rb.root == nil {
		rb.root = new(node)
		rb.root.key = key
		rb.root.color = Black
	} else {
		p, ok := rb.find(key)
		if ok {
			//todo replace node value
			return
		}
		//here p must not be nil
		if p.key > key {
			add := p.addLeft(key)
			rb.ajustAdd(add)
		} else {
			add := p.addRight(key)
			rb.ajustAdd(add)
		}
	}
	rb.len++
}

func (rb *RBTree) ajustAdd(add *node) {
	t := add
	p := add.parent
	for p != nil && p.color != Black {
		//pp must not be nil because p is red
		pp := p.parent
		// get uncle
		uncle := pp.left
		if pp.left == p {
			uncle = pp.right
		}

		if uncle == nil || uncle.color == Black {
			if p == pp.left {
				if t == p.right {
					rb.rotateLeft(p)
				}
				rb.rotateRight(pp)
			} else {
				if t == p.left {
					rb.rotateRight(p)
				}
				rb.rotateLeft(pp)
			}

			pp.color = Red
			pp.parent.color = Black
			break
		} else {
			// uncle must be red
			p.color = Black
			uncle.color = Black
			pp.color = Red
			t = pp
			p = t.parent
		}
	}

	if p == nil {
		rb.root = t
		rb.root.color = Black
		rb.root.parent = nil
	}
}

//if the second parameter return true,it indicates found
//else return the parent node that the key will be added
func (rb *RBTree) find(key int) (*node, bool) {
	if rb.root == nil {
		return nil, false
	}
	c := rb.root
	p := c
	for c != nil {
		if c.key > key {
			p = c
			c = c.left
		} else if c.key < key {
			p = c
			c = c.right
		} else {
			return c, true
		}
	}
	return p, false
}

//just for debug
func (rb *RBTree)print() {
	ch := make(chan interface{}, 1000)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		var dealed int
		for {
			select {
			case v := <-ch:
				if n, ok := v.(*node); ok {
					if n == nil {
						continue
					}
					dealed++
					color := "red"
					if n.color == Black {
						color = "black"
					}
					pos := ""
					if n.parent == nil {
						pos = "root"
					} else if n == n.parent.left {
						pos = "left"
					} else if n == n.parent.right {
						pos = "right"
					}

					if n.parent != nil {
						fmt.Printf(" %d(p %d,c %s,p %s)", n.key, n.parent.key, color, pos)
					} else {
						fmt.Printf(" %d(p %s,c %s,p %s)", n.key, "", color, pos)
					}

					ch <- n.left
					ch <- n.right

				} else {
					fmt.Println()
					if dealed == rb.len {
						return
					}
					ch <- "next"
				}
			}
		}
	}()

	ch <- rb.root
	ch <- "next"
	wg.Wait()
}

func main() {
	rb := new(RBTree)
	rb.insert(1)
	rb.insert(2)
	rb.insert(3)
	rb.insert(4)
	rb.insert(5)
	rb.insert(6)
	rb.insert(7)
	rb.insert(8)
	rb.insert(9)
	rb.insert(10)
	rb.insert(11)
	rb.insert(12)
	rb.insert(13)
	rb.print()
}