// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package ssa

import (
	"fmt"
	"testing"
)

type sstring string

func (s sstring) String() string {
	return string(s)
}

// wellFormed ensures that a red-black tree meets
// all of its invariants and returns a string identifying
// the first problem encountered. If there is no problem
// then the returned string is empty. The size is also
// returned to allow comparison of calculated tree size
// with expected.
func (t *RBTint32) wellFormed() (s string, i int) {
	if t.root == nil {
		s = ""
		i = 0
		return
	}
	return t.root.wellFormedSubtree(nil, -0x80000000, 0x7fffffff)
}

// wellFormedSubtree ensures that a red-black subtree meets
// all of its invariants and returns a string identifying
// the first problem encountered. If there is no problem
// then the returned string is empty. The size is also
// returned to allow comparison of calculated tree size
// with expected.
func (t *node32) wellFormedSubtree(parent *node32, min, max int32) (s string, i int) {
	i = -1 // initialize to a failing value
	s = "" // s is the reason for failure; empty means okay.

	if t.parent != parent {
		s = "t.parent != parent"
		return
	}

	if min >= t.key {
		s = "min >= t.key"
		return
	}

	if max <= t.key {
		s = "max <= t.key"
		return
	}

	l := t.left
	r := t.right
	if l == nil && r == nil {
		if t.rank != rankLeaf {
			s = "leaf rank wrong"
			return
		}
	}
	if l != nil {
		if t.rank < l.rank {
			s = "t.rank < l.rank"
		} else if t.rank > 1+l.rank {
			s = "t.rank > 1+l.rank"
		} else if t.rank <= l.maxChildRank() {
			s = "t.rank <= l.maxChildRank()"
		} else if t.key <= l.key {
			s = "t.key <= l.key"
		}
		if s != "" {
			return
		}
	} else {
		if t.rank != 1 {
			s = "t w/ left nil has rank != 1"
			return
		}
	}
	if r != nil {
		if t.rank < r.rank {
			s = "t.rank < r.rank"
		} else if t.rank > 1+r.rank {
			s = "t.rank > 1+r.rank"
		} else if t.rank <= r.maxChildRank() {
			s = "t.rank <= r.maxChildRank()"
		} else if t.key >= r.key {
			s = "t.key >= r.key"
		}
		if s != "" {
			return
		}
	} else {
		if t.rank != 1 {
			s = "t w/ right nil has rank != 1"
			return
		}
	}
	ii := 1
	if l != nil {
		res, il := l.wellFormedSubtree(t, min, t.key)
		if res != "" {
			s = "L." + res
			return
		}
		ii += il
	}
	if r != nil {
		res, ir := r.wellFormedSubtree(t, t.key, max)
		if res != "" {
			s = "R." + res
			return
		}
		ii += ir
	}
	i = ii
	return
}

func (t *RBTint32) DebugString() string {
	if t.root == nil {
		return ""
	}
	return t.root.DebugString()
}

// DebugString prints the tree with nested information
// to allow an eyeball check on the tree balance.
func (t *node32) DebugString() string {
	s := ""
	if t.left != nil {
		s = s + "["
		s = s + t.left.DebugString()
		s = s + "]"
	}
	s = s + fmt.Sprintf("%v=%v:%d", t.key, t.data, t.rank)
	if t.right != nil {
		s = s + "["
		s = s + t.right.DebugString()
		s = s + "]"
	}
	return s
}

func allRBT32Ops(te *testing.T, x []int32) {
	t := &RBTint32{}
	for i, d := range x {
		x[i] = d + d // Double everything for glb/lub testing
	}

	// fmt.Printf("Inserting double of %v", x)
	k := 0
	min := int32(0x7fffffff)
	max := int32(-0x80000000)
	for _, d := range x {
		if d < min {
			min = d
		}

		if d > max {
			max = d
		}

		t.Insert(d, sstring(fmt.Sprintf("%v", d)))
		k++
		s, i := t.wellFormed()
		if i != k {
			te.Errorf("Wrong tree size %v, expected %v for %v", i, k, t.DebugString())
		}
		if s != "" {
			te.Errorf("Tree consistency problem at %v", s)
			return
		}
	}

	oops := false

	for _, d := range x {
		s := fmt.Sprintf("%v", d)
		f := t.Find(d)

		// data
		if s != fmt.Sprintf("%v", f) {
			te.Errorf("s(%v) != f(%v)", s, f)
			oops = true
		}
	}

	if !oops {
		for _, d := range x {
			s := fmt.Sprintf("%v", d)

			kg, g := t.Glb(d + 1)
			kge, ge := t.GlbEq(d)
			kl, l := t.Lub(d - 1)
			kle, le := t.LubEq(d)

			// keys
			if d != kg {
				te.Errorf("d(%v) != kg(%v)", d, kg)
			}
			if d != kl {
				te.Errorf("d(%v) != kl(%v)", d, kl)
			}
			if d != kge {
				te.Errorf("d(%v) != kge(%v)", d, kge)
			}
			if d != kle {
				te.Errorf("d(%v) != kle(%v)", d, kle)
			}
			// data
			if s != fmt.Sprintf("%v", g) {
				te.Errorf("s(%v) != g(%v)", s, g)
			}
			if s != fmt.Sprintf("%v", l) {
				te.Errorf("s(%v) != l(%v)", s, l)
			}
			if s != fmt.Sprintf("%v", ge) {
				te.Errorf("s(%v) != ge(%v)", s, ge)
			}
			if s != fmt.Sprintf("%v", le) {
				te.Errorf("s(%v) != le(%v)", s, le)
			}
		}

		for _, d := range x {
			s := fmt.Sprintf("%v", d)
			kge, ge := t.GlbEq(d + 1)
			kle, le := t.LubEq(d - 1)
			if d != kge {
				te.Errorf("d(%v) != kge(%v)", d, kge)
			}
			if d != kle {
				te.Errorf("d(%v) != kle(%v)", d, kle)
			}
			if s != fmt.Sprintf("%v", ge) {
				te.Errorf("s(%v) != ge(%v)", s, ge)
			}
			if s != fmt.Sprintf("%v", le) {
				te.Errorf("s(%v) != le(%v)", s, le)
			}
		}

		kg, g := t.Glb(min)
		kge, ge := t.GlbEq(min - 1)
		kl, l := t.Lub(max)
		kle, le := t.LubEq(max + 1)
		fmin := t.Find(min - 1)
		fmax := t.Find(min + 11)

		if kg != 0 || kge != 0 || kl != 0 || kle != 0 {
			te.Errorf("Got non-zero-key for missing query")
		}

		if g != nil || ge != nil || l != nil || le != nil || fmin != nil || fmax != nil {
			te.Errorf("Got non-error-data for missing query")
		}

	}
}

func TestAllRBTreeOps(t *testing.T) {
	allRBT32Ops(t, []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25})
	allRBT32Ops(t, []int32{22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 3, 2, 1, 25, 24, 23, 12, 11, 10, 9, 8, 7, 6, 5, 4})
	allRBT32Ops(t, []int32{25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1})
	allRBT32Ops(t, []int32{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24})
	allRBT32Ops(t, []int32{1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2})
	allRBT32Ops(t, []int32{24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4, 2, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25})
}
