package qslcard import ( "sync" "hamlog/internal/applog" ) // CountryInfo resolves the "auto" country element: a display label and the // ISO code of the embedded flag ("" = no flag available). type CountryInfo struct { Label string `json:"label"` FlagISO string `json:"flag_iso"` } // RenderModel is a template with every placeholder filled, ready for the // frontend to instantiate as SVG (editor preview and final rasterization use // the same model so output cannot drift from preview). type RenderModel struct { Template Template `json:"template"` QSOFields map[string]string `json:"qso_fields"` // values for qso_box.fields } // warnedPlaceholders dedupes the "unknown placeholder" log line so a bulk // render doesn't flood the log. var warnedPlaceholders sync.Map // Resolve substitutes {profile.*} and {qso.*} placeholders from vars (keys // are the full "namespace.key" form) and resolves the country element. An // unknown placeholder resolves to "" and is logged once. func Resolve(t Template, vars map[string]string, country CountryInfo) RenderModel { resolve := func(text string) string { return placeholderRe.ReplaceAllStringFunc(text, func(m string) string { key := m[1 : len(m)-1] // strip braces → "namespace.key" if v, ok := vars[key]; ok { return v } if _, seen := warnedPlaceholders.LoadOrStore(key, true); !seen { applog.Printf("qslcard: unknown placeholder %q resolves to empty", m) } return "" }) } out := t out.Elements = make([]Element, len(t.Elements)) copy(out.Elements, t.Elements) for i := range out.Elements { e := &out.Elements[i] switch e.Type { case ElemCallsign, ElemOperator, ElemInfoLine: e.Text = resolve(e.Text) case ElemCountry: if e.Flag == "auto" { e.Flag = country.FlagISO } if e.Label == "auto" { e.Label = country.Label } } } if t.QSOBox != nil { box := *t.QSOBox box.Title = resolve(box.Title) box.Footer = resolve(box.Footer) out.QSOBox = &box } model := RenderModel{Template: out, QSOFields: map[string]string{}} if out.QSOBox != nil { for _, f := range out.QSOBox.Fields { model.QSOFields[f] = vars["qso."+f] } } return model }