package bambunfc import ( "fmt" "slices" ) // Spool is one physical filament roll (both stickers merged). type Spool struct { Brand string TrayUID string ChipUIDs []string Type string Material string MaterialID string VariantID string Color Color WeightG int DiameterMM float32 LengthM int MinHotendC int MaxHotendC int BedC int DryC int DryHours int Produced string SpoolWidthRaw uint16 } func spoolKey(t Tag) string { return t.Brand + "\x00" + t.TrayUID } func sameFilament(a, b Tag) bool { return a.Type == b.Type && a.Material == b.Material && a.Color == b.Color && a.WeightG == b.WeightG } func tagToSpool(t Tag) Spool { return Spool{ Brand: t.Brand, TrayUID: t.TrayUID, ChipUIDs: []string{t.ChipUID}, Type: t.Type, Material: t.Material, MaterialID: t.MaterialID, VariantID: t.VariantID, Color: t.Color, WeightG: t.WeightG, DiameterMM: t.DiameterMM, LengthM: t.LengthM, MinHotendC: t.MinHotendC, MaxHotendC: t.MaxHotendC, BedC: t.BedC, DryC: t.DryC, DryHours: t.DryHours, Produced: t.Produced, SpoolWidthRaw: t.SpoolWidthRaw, } } // Merge groups tags by brand + tray UID into spools. func Merge(tags []Tag) ([]Spool, error) { order := make([]string, 0) groups := make(map[string][]Tag) for _, t := range tags { if t.TrayUID == "" { return nil, fmt.Errorf("%w: empty tray uid chip %s", ErrIncomplete, t.ChipUID) } k := spoolKey(t) if _, ok := groups[k]; !ok { order = append(order, k) } groups[k] = append(groups[k], t) } spools := make([]Spool, 0, len(order)) for _, k := range order { g := groups[k] s := tagToSpool(g[0]) uids := map[string]struct{}{g[0].ChipUID: {}} for _, t := range g[1:] { if !sameFilament(g[0], t) { return nil, fmt.Errorf("%w: tray %s", ErrConflict, t.TrayUID) } uids[t.ChipUID] = struct{}{} } s.ChipUIDs = make([]string, 0, len(uids)) for u := range uids { s.ChipUIDs = append(s.ChipUIDs, u) } slices.Sort(s.ChipUIDs) spools = append(spools, s) } slices.SortFunc(spools, func(a, b Spool) int { if a.TrayUID < b.TrayUID { return -1 } if a.TrayUID > b.TrayUID { return 1 } return 0 }) return spools, nil }