backend/analyzer/Filters.go (107 lines of code) (raw):
package analyzer
import (
"bytes"
_ "embed"
"encoding/binary"
"encoding/json"
"log"
"reflect"
"sort"
"strconv"
"text/template"
)
type Filters map[string]struct {
State string
Entries FilterEntries
}
type FilterEntries []FilterEntry
type FilterEntry struct {
Checked bool
GroupLabel string
ID string
EntryLabel string
GroupLineHighlightingColor string //Fills automatically based on the LineHighlightingColor of the DynamicEntity
//innerFilters []innerFilter
}
//type innerFilter struct {
//
//}
// func AddInnerFilter(){}
func (f *Filters) IsEmpty() bool {
return reflect.ValueOf(*f).IsZero()
}
func (f Filters) ConvertToJSON() string {
f.setFiltersGroupsState()
marshal, _ := json.Marshal(f)
return string(marshal)
}
func (f Filters) ConvertToHTML() string {
f.setFiltersGroupsState()
var tpl bytes.Buffer
t := template.Must(template.New("Filters.gohtml").
ParseFS(tmplFS, "Filters.gohtml"))
err := t.Execute(&tpl, f)
if err != nil {
log.Printf("Template Filters.gohtml parsing failed. Error: %s", err.Error())
}
return tpl.String()
}
// Append adds generated filter to slice of filters
func (f Filters) Append(entity DynamicEntity, entityEntryPath string) {
fi, _ := f[entity.Name]
fi.Entries = append(fi.Entries, FilterEntry{
Checked: entity.entityInstances[entityEntryPath].Visible,
ID: entity.entityInstances[entityEntryPath].Hash,
GroupLabel: entity.Name,
GroupLineHighlightingColor: entity.LineHighlightingColor,
EntryLabel: entity.GetDisplayName(entityEntryPath),
})
f[entity.Name] = fi
}
func (f *Filters) SortByFilename() {
for _, filterEntries := range *f {
sort.Slice(filterEntries.Entries, func(i, j int) bool {
return sortName(filterEntries.Entries[i].EntryLabel) < sortName(filterEntries.Entries[j].EntryLabel)
})
}
}
func (f *Filters) getEntriesWithStates() (filtersList map[string]bool) {
filtersList = make(map[string]bool)
for _, entries := range *f {
for _, entry := range entries.Entries {
filtersList[entry.ID] = entry.Checked
}
}
return filtersList
}
func (f Filters) setFiltersGroupsState() {
for name, fi := range f {
i := 0
for _, entry := range fi.Entries {
if entry.Checked {
i++
}
}
if i == len(fi.Entries) {
fi.State = "checked"
} else if i == 0 {
fi.State = "unchecked"
} else {
fi.State = "mixed"
}
f[name] = fi
}
}
func sortName(filename string) string {
name := filename
// split numeric suffix
i := len(name) - 1
for ; i >= 0; i-- {
if '0' > name[i] || name[i] > '9' {
break
}
}
i++
// string numeric suffix to uint64 bytes
// empty string is zero, so integers are plus one
b64 := make([]byte, 64/8)
s64 := name[i:]
if len(s64) > 0 {
u64, err := strconv.ParseUint(s64, 10, 64)
if err == nil {
binary.BigEndian.PutUint64(b64, u64+1)
}
}
// prefix + numeric-suffix
return name[:i] + string(b64)
}