package tree import ( "fmt" "path" "sort" "strings" "github.com/bouncepaw/mycorrhiza/hyphae" "github.com/bouncepaw/mycorrhiza/util" ) type sibling struct { name string hasChildren bool } func (s *sibling) checkThisChild(hyphaName string) { if !s.hasChildren && path.Dir(hyphaName) == s.name { s.hasChildren = true } } func (s *sibling) asHTML() string { class := "navitree__entry navitree__sibling" if s.hasChildren { class += " navitree__sibling_fertile navitree__entry_fertile" } else { class += " navitree__sibling_infertile navitree__entry_infertile" } return fmt.Sprintf( `
  • %s
  • `, class, s.name, util.BeautifulName(path.Base(s.name)), ) } type mainFamilyMember struct { name string children []*mainFamilyMember } func (m *mainFamilyMember) checkThisChild(hyphaName string) (adopted bool) { if path.Dir(hyphaName) == m.name { m.children = append(m.children, &mainFamilyMember{ name: hyphaName, children: make([]*mainFamilyMember, 0), }) return true } return false } func (m *mainFamilyMember) asHTML() string { if len(m.children) == 0 { return fmt.Sprintf(`
  • %s
  • `, m.name, util.BeautifulName(path.Base(m.name))) } sort.Slice(m.children, func(i, j int) bool { return m.children[i].name < m.children[j].name }) html := fmt.Sprintf(`
  • %s
  • ` } func mainFamilyFromPool(hyphaName string, subhyphaePool map[string]bool) *mainFamilyMember { var ( nestLevel = strings.Count(hyphaName, "/") adopted = make([]*mainFamilyMember, 0) ) for subhyphaName, _ := range subhyphaePool { subnestLevel := strings.Count(subhyphaName, "/") if subnestLevel-1 == nestLevel && path.Dir(subhyphaName) == hyphaName { delete(subhyphaePool, subhyphaName) adopted = append(adopted, mainFamilyFromPool(subhyphaName, subhyphaePool)) } } return &mainFamilyMember{name: hyphaName, children: adopted} } func subhyphaeMatrix(hyphaName string, subhyphaePool map[string]bool) string { var html string children := mainFamilyFromPool(hyphaName, subhyphaePool).children sort.Slice(children, func(i, j int) bool { return children[i].name < children[j].name }) for _, child := range children { html += child.asHTML() } return html } // Tree generates a tree for `hyphaName` as html and returns next and previous hyphae if any. func Tree(hyphaName string) (relatives, subhyphae, prev, next string) { var ( // One of the siblings is the hypha with name `hyphaName` siblings = findSiblings(hyphaName) subhyphaePool = make(map[string]bool) I int ) for h := range hyphae.YieldExistingHyphae() { for _, s := range siblings { s.checkThisChild(h.Name) } if strings.HasPrefix(h.Name, hyphaName+"/") { subhyphaePool[h.Name] = true } } for i, s := range siblings { if s.name == hyphaName { I = i relatives += fmt.Sprintf(`
  • %s
  • `, util.BeautifulName(path.Base(hyphaName))) } else { relatives += s.asHTML() } } if I != 0 { prev = siblings[I-1].name } if I != len(siblings)-1 { next = siblings[I+1].name } return fmt.Sprintf(``, relatives), subhyphaeMatrix(hyphaName, subhyphaePool), prev, next } func findSiblings(hyphaName string) []*sibling { siblings := []*sibling{&sibling{name: hyphaName, hasChildren: true}} for h := range hyphae.YieldExistingHyphae() { if path.Dir(hyphaName) == path.Dir(h.Name) && hyphaName != h.Name { siblings = append(siblings, &sibling{name: h.Name, hasChildren: false}) } } sort.Slice(siblings, func(i, j int) bool { return siblings[i].name < siblings[j].name }) return siblings }