package jsonvalue

import (
	"bytes"
	"fmt"
	"sort"
)

// Deprecated: ObjectIter is a deprecated type.
type ObjectIter struct {
	K string
	V *V
}

// Deprecated: ArrayIter is a deprecated type.
type ArrayIter struct {
	I int
	V *V
}

// RangeObjects goes through each children when this is an object value
//
// Return true in callback to continue range iteration, while false to break.
//
// 若当前 JSON 值是一个 object 类型时，RangeObjects 遍历所有的键值对。
//
// 在回调函数中返回 true 表示继续迭代，返回 false 表示退出迭代
func (v *V) RangeObjects(callback func(k string, v *V) bool) {
	if !v.IsObject() {
		return
	}
	if nil == callback {
		return
	}

	for k, c := range v.children.object {
		ok := callback(k, c.v)
		if !ok {
			break
		}
	}
}

// RangeObjectsBySetSequence acts just like RangeObjects, but the key sequence
// is arranged by when a key is set to the given object.
//
// RangeObjectsBySetSequence 类似于 RangeObjects 函数, 但是 key 的顺序会依照其被 set
// 进这个 object 的顺序传递。
func (v *V) RangeObjectsBySetSequence(callback func(k string, v *V) bool) {
	if !v.IsObject() {
		return
	}
	if nil == callback {
		return
	}

	type keysAndID struct {
		k  string
		id uint32
		v  *V
	}

	kvs := make([]keysAndID, 0, len(v.children.object))
	for k, child := range v.children.object {
		kvs = append(kvs, keysAndID{
			k:  k,
			id: child.id,
			v:  child.v,
		})
	}
	sort.Slice(kvs, func(i, j int) bool {
		return kvs[i].id <= kvs[j].id
	})

	for _, kv := range kvs {
		ok := callback(kv.k, kv.v)
		if !ok {
			break
		}
	}
}

// Deprecated: IterObjects is deprecated, please Use ForRangeObj() instead.
func (v *V) IterObjects() <-chan *ObjectIter {
	ch := make(chan *ObjectIter, len(v.children.object))

	go func() {
		for k, c := range v.children.object {
			ch <- &ObjectIter{
				K: k,
				V: c.v,
			}
		}
		close(ch)
	}()
	return ch
}

// ForRangeObj returns a map which can be used in for - range block to iteration KVs in a JSON object value.
//
// ForRangeObj 返回一个 map 类型，用于使用 for - range 块迭代 JSON 对象类型的子成员。
func (v *V) ForRangeObj() map[string]*V {
	res := make(map[string]*V, len(v.children.object))
	for k, c := range v.children.object {
		res[k] = c.v
	}
	return res
}

// RangeArray goes through each children when this is an array value
//
// Return true in callback to continue range iteration, while false to break.
//
// 若当前 JSON 值是一个 array 类型时，RangeArray 遍历所有的数组成员。
//
// 在回调函数中返回 true 表示继续迭代，返回 false 表示退出迭代
func (v *V) RangeArray(callback func(i int, v *V) bool) {
	if !v.IsArray() {
		return
	}
	if nil == callback {
		return
	}

	for i, child := range v.children.arr {
		if ok := callback(i, child); !ok {
			break
		}
	}
}

// Deprecated: IterArray is deprecated, please Use ForRangeArr() instead.
func (v *V) IterArray() <-chan *ArrayIter {
	c := make(chan *ArrayIter, len(v.children.arr))

	go func() {
		for i, child := range v.children.arr {
			c <- &ArrayIter{
				I: i,
				V: child,
			}
		}
		close(c)
	}()
	return c
}

// ForRangeArr returns a slice which can be used in for - range block to iteration KVs in a JSON array value.
//
// ForRangeObj 返回一个切片，用于使用 for - range 块迭代 JSON 数组类型的子成员。
func (v *V) ForRangeArr() []*V {
	res := make([]*V, 0, len(v.children.arr))
	return append(res, v.children.arr...)
}

// PathItem is used for
type PathItem struct {
	Idx int    // Index of the array, -1 means this element is NOT an array
	Key string // Key of the object, "" means this element is NOT an object
}

func (p PathItem) String() string {
	if p.Idx < 0 {
		return p.Key
	}
	return fmt.Sprintf("[%d]", p.Idx)
}

// Path is a list of PathItem
type Path []PathItem

// Last returns last element of path
func (p Path) Last() PathItem {
	le := len(p)
	if le == 0 {
		return PathItem{Idx: -1}
	}
	return p[le-1]
}

func (p Path) String() string {
	bdr := bytes.Buffer{}
	for i, item := range p {
		if i > 0 {
			bdr.WriteByte('.')
		}
		bdr.WriteString(item.String())
	}
	return bdr.String()
}

func appendPathIndex(items []PathItem, i int) []PathItem {
	return append(items, PathItem{Idx: i, Key: ""})
}

func appendPathKey(items []PathItem, key string) []PathItem {
	return append(items, PathItem{Idx: -1, Key: key})
}

// WalkFunc is the function type for walking through all sub values of a JSON value.
// Return true to continue walking, while false to break.
//
// WalkFunc 是一个回调函数类型，用于遍历一个 JSON 值的所有子成员。返回 true 表示继续迭代,
// 返回 false 表示退出迭代
type WalkFunc func(path Path, v *V) bool

// Walk walks through all sub values of a JSON value.
//
// Walk 遍历一个 JSON 值的所有子成员。
func (v *V) Walk(fn WalkFunc) {
	if fn == nil {
		return
	}
	v.walk(nil, fn)
}

func (v *V) walk(parent Path, fn WalkFunc) bool {
	shouldContinue := true
	switch v.ValueType() {
	case Object:
		v.RangeObjects(func(k string, sub *V) bool {
			shouldContinue = sub.walk(appendPathKey(parent, k), fn)
			return shouldContinue
		})
	case Array:
		v.RangeArray(func(i int, sub *V) bool {
			shouldContinue = sub.walk(appendPathIndex(parent, i), fn)
			return shouldContinue
		})
	default:
		shouldContinue = fn(parent, v)
	}
	return shouldContinue
}
