123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- package node
- import (
- "encoding/json"
- "fmt"
- "reflect"
- )
- type Node struct {
- name string
- data any
- parent *Node
- children []*Node
- }
- func NewNode() *Node {
- return &Node{}
- }
- func NewNodeWithName(name string) *Node {
- return &Node{name: name}
- }
- func NewNodeWithData(data any) *Node {
- return &Node{data: data}
- }
- func NewNodeWithNameAndData(name string, data any) *Node {
- return &Node{name: name, data: data}
- }
- func NewNodeWithDataAndName(data any, name string) *Node {
- return &Node{name: name, data: data}
- }
- func (n *Node) Name(name ...string) string {
- if len(name) != 0 {
- n.name = name[0]
- }
- return n.name
- }
- func (n *Node) Data(data ...any) any {
- if len(data) != 0 {
- n.data = data[0]
- }
- return n.data
- }
- func (n *Node) Len() int {
- return len(n.children)
- }
- func (n *Node) Parent(parent ...*Node) *Node {
- if len(parent) != 0 {
- n.parent = parent[0]
- }
- return n.parent
- }
- func (n *Node) Root() *Node {
- if n.Parent() == nil {
- return n
- }
- at := n.Parent()
- for at.Parent() != nil {
- at = at.Parent()
- }
- return at
- }
- func (n *Node) Depth() int {
- if n.Parent() == nil {
- return 0
- }
- var (
- depth int = 1
- at *Node = n.Parent()
- )
- for at.Parent() != nil {
- depth++
- at = at.Parent()
- }
- return depth
- }
- func (n *Node) Kids() []*Node {
- return n.children
- }
- func (n *Node) AddKid(kid *Node) bool {
- for _, k := range n.children {
- if k == kid {
- return false
- }
- }
- kid.Parent(n)
- n.children = append(n.children, kid)
- return true
- }
- func (n *Node) NewKid() *Node {
- k := &Node{}
- n.AddKid(k)
- return k
- }
- func (n *Node) NewKidWithName(name string) *Node {
- k := n.NewKid()
- k.Name(name)
- return k
- }
- func (n *Node) NewKidWithData(data any) *Node {
- k := n.NewKid()
- k.Data(data)
- return k
- }
- func (n *Node) NewKidWithNameAndData(name string, data any) *Node {
- k := n.NewKid()
- k.Name(name)
- k.Data(data)
- return k
- }
- func (n *Node) NewKidWithDataAndName(data any, name string) *Node {
- k := n.NewKid()
- k.Name(name)
- k.Data(data)
- return k
- }
- func (n *Node) Index() int {
- if n.Parent() == nil { // There is no parent, so it's not known
- return -1
- }
- // Iterate thru the children of the parent to find ourselves
- for i, kid := range n.Parent().Kids() {
- if kid == n {
- return i
- }
- }
- // Ok we for some reason are not in that list, so it's not known
- return -1
- }
- func (n *Node) Kid(index int) *Node {
- if n == nil || index > n.Len() || index < 0 {
- return nil
- }
- return n.children[index]
- }
- func (n *Node) KidByName(name string, recurse ...bool) *Node {
- for _, kid := range n.children {
- if kid.name == name {
- return kid
- }
- }
- if len(recurse) != 0 {
- if recurse[0] {
- for _, kid := range n.children {
- r := kid.KidByName(name, recurse...)
- if r != nil {
- return r
- }
- }
- }
- }
- return nil
- }
- func (n *Node) RemoveKid(index int) bool {
- if index > n.Len() || index < 0 {
- return false
- }
- n.children[index].Parent(nil)
- _, ok := arrayDelete(&n.children, index)
- return ok
- }
- func (n *Node) RemoveAllKids() {
- for _, kid := range n.children {
- kid.Parent(nil)
- }
- n.children = []*Node{}
- }
- func (n *Node) Detach() bool {
- if n.Parent() != nil {
- return false
- }
- index := n.Index()
- if index == -1 {
- return false
- }
- return n.Parent().RemoveKid(index)
- }
- func (n *Node) Destroy() {
- if n.Parent() != nil {
- n.Detach()
- }
- n.Data(nil)
- n.Name("")
- for _, kid := range n.children {
- kid.Destroy()
- }
- }
- // Checks if the children of this node are better represented as a map or an array
- //
- // This is determined by:
- //
- // * Totaling number of children without names
- //
- // * Comparing the percent of children without names to total children (if less than 50% use a map, if more than 50% use an array)
- func (n *Node) IsMapLike() bool {
- if n.Len() == 0 {
- return false
- }
- var (
- total int = n.Len() // number of children
- noname int = 0 // number of children with no name
- )
- for _, kid := range n.Kids() {
- if len(kid.Name()) == 0 { // When it has no name it's not map-like
- noname += 1
- }
- }
- // Form a percent of no name children and compare it to less than 50%
- return int((float32(noname)/float32(total))*100.0) <= 50
- }
- func (n *Node) from(A any) {
- switch reflect.TypeOf(A).Kind() {
- case reflect.Map:
- // Ok, key, value
- // key == name, value if not a map, array, slice is data
- m := A.(map[string]any)
- for k, v := range m {
- switch reflect.TypeOf(v).Kind() {
- case reflect.Map, reflect.Array, reflect.Slice:
- // New kid, with name, and recurse
- kid := n.NewKidWithName(k)
- kid.from(v)
- default:
- // New kid, with name, and data
- n.NewKidWithNameAndData(k, v)
- }
- }
- case reflect.Array, reflect.Slice:
- // Ok, values
- // no name (use index), value if not a map, array, slice is data
- a := A.([]any)
- for idx, v := range a {
- switch reflect.TypeOf(v).Kind() {
- case reflect.Map, reflect.Array, reflect.Slice:
- kid := n.NewKidWithName(fmt.Sprintf("%d", idx))
- kid.from(v)
- default:
- n.NewKidWithNameAndData(fmt.Sprintf("%d", idx), v)
- }
- }
- default:
- // Ok it's just a single value (most likely)
- n.Data(A)
- }
- }
- func (n *Node) ToMap() any {
- if len(n.Name()) != 0 && n.Len() != 0 { // Name + Children
- if n.IsMapLike() {
- // Map
- m := map[string]any{}
- for i, kid := range n.children {
- if len(kid.Name()) != 0 {
- m[kid.Name()] = kid.ToMap()
- } else {
- m[fmt.Sprint(i)] = kid.ToMap()
- }
- }
- if n.Depth() != 0 {
- return m
- } else {
- return map[string]any{
- n.Name(): m,
- }
- }
- } else {
- // Array
- a := []any{}
- for _, kid := range n.children {
- a = append(a, kid.ToMap())
- }
- if n.Depth() != 0 {
- return a
- } else {
- return map[string]any{
- n.Name(): a,
- }
- }
- }
- } else if len(n.Name()) == 0 && n.Len() != 0 { // No Name + Children
- if n.IsMapLike() {
- // Map
- m := map[string]any{}
- for i, kid := range n.children {
- if len(kid.Name()) != 0 {
- m[kid.Name()] = kid.ToMap()
- } else {
- m[fmt.Sprint(i)] = kid.ToMap()
- }
- }
- return m
- } else {
- // Array
- a := []any{}
- for _, kid := range n.children {
- a = append(a, kid.ToMap())
- }
- if n.Depth() != 0 {
- return a
- } else {
- return map[string]any{
- fmt.Sprint(n.Index()): a,
- }
- }
- }
- } else if n.Data() != nil {
- if n.Depth() != 0 || len(n.Name()) == 0 {
- return n.Data()
- } else {
- return map[string]any{
- n.Name(): n.Data(),
- }
- }
- }
- return nil
- }
- // Marshals the results from ToMap
- func (n *Node) MarshalJSON() ([]byte, error) {
- return json.Marshal(n.ToMap())
- }
- // Unmarshal function
- func (n *Node) UnmarshalJSON(pay []byte) error {
- var m map[string]any
- err := json.Unmarshal(pay, &m)
- if err != nil {
- return err
- }
- n.Destroy()
- // In this case, the struct isn't in a invalid state, it's just a reset
- n.from(m)
- return nil
- }
|