package iace
import (
"archive/zip"
"bytes"
"encoding/xml"
"fmt"
)
// buildAssessmentMap builds a map from hazardID string to the latest RiskAssessment.
func buildAssessmentMap(assessments []RiskAssessment) map[string]*RiskAssessment {
m := make(map[string]*RiskAssessment)
for i := range assessments {
a := &assessments[i]
key := a.HazardID.String()
if existing, ok := m[key]; !ok || a.Version > existing.Version {
m[key] = a
}
}
return m
}
// riskLevelColor returns RGB values for PDF fill color based on risk level.
func riskLevelColor(level RiskLevel) (r, g, b int) {
switch level {
case RiskLevelNotAcceptable:
return 180, 0, 0
case RiskLevelVeryHigh:
return 220, 40, 40
case RiskLevelCritical:
return 255, 80, 80
case RiskLevelHigh:
return 255, 165, 80
case RiskLevelMedium:
return 255, 230, 100
case RiskLevelLow:
return 180, 230, 140
case RiskLevelNegligible:
return 140, 210, 140
default:
return 240, 240, 240
}
}
// riskLevelLabel returns a German display label for a risk level.
func riskLevelLabel(level RiskLevel) string {
switch level {
case RiskLevelNotAcceptable:
return "Nicht akzeptabel"
case RiskLevelVeryHigh:
return "Sehr hoch"
case RiskLevelCritical:
return "Kritisch"
case RiskLevelHigh:
return "Hoch"
case RiskLevelMedium:
return "Mittel"
case RiskLevelLow:
return "Niedrig"
case RiskLevelNegligible:
return "Vernachlaessigbar"
default:
return string(level)
}
}
// reductionTypeLabel returns a German label for a reduction type.
func reductionTypeLabel(rt ReductionType) string {
switch rt {
case ReductionTypeDesign:
return "Konstruktiv"
case ReductionTypeProtective:
return "Schutzmassnahme"
case ReductionTypeInformation:
return "Information"
default:
return string(rt)
}
}
// mitigationStatusLabel returns a German label for a mitigation status.
func mitigationStatusLabel(status MitigationStatus) string {
switch status {
case MitigationStatusPlanned:
return "Geplant"
case MitigationStatusImplemented:
return "Umgesetzt"
case MitigationStatusVerified:
return "Verifiziert"
case MitigationStatusRejected:
return "Abgelehnt"
default:
return string(status)
}
}
// regulationLabel returns a German label for a regulation type.
func regulationLabel(reg RegulationType) string {
switch reg {
case RegulationNIS2:
return "NIS-2 Richtlinie"
case RegulationAIAct:
return "EU AI Act"
case RegulationCRA:
return "Cyber Resilience Act"
case RegulationMachineryRegulation:
return "EU Maschinenverordnung 2023/1230"
default:
return string(reg)
}
}
// escapeXML escapes special XML characters in text content.
func escapeXML(s string) string {
var buf bytes.Buffer
if err := xml.EscapeText(&buf, []byte(s)); err != nil {
return s
}
return buf.String()
}
// countByRiskLevel counts assessments per risk level.
func countByRiskLevel(assessments []RiskAssessment) map[RiskLevel]int {
counts := make(map[RiskLevel]int)
for _, a := range assessments {
counts[a.RiskLevel]++
}
return counts
}
// pdfTruncate truncates a string for PDF cell display.
func pdfTruncate(s string, maxLen int) string {
runes := []rune(s)
if len(runes) <= maxLen {
return s
}
if maxLen <= 3 {
return string(runes[:maxLen])
}
return string(runes[:maxLen-3]) + "..."
}
// cellRef builds an Excel cell reference like "A1", "B12".
func cellRef(col string, row int) string {
return fmt.Sprintf("%s%d", col, row)
}
// rgbHex converts RGB values to a hex color string (without #).
func rgbHex(r, g, b int) string {
return fmt.Sprintf("%02X%02X%02X", r, g, b)
}
// addZipEntry writes a text file into a zip archive.
func addZipEntry(zw *zip.Writer, name, content string) error {
w, err := zw.Create(name)
if err != nil {
return err
}
_, err = w.Write([]byte(content))
return err
}
// docxHeading builds a DOCX paragraph with a heading style.
func docxHeading(text string, level int) string {
sizes := map[int]int{1: 64, 2: 52, 3: 44}
sz, ok := sizes[level]
if !ok {
sz = 44
}
escaped := escapeXML(text)
return fmt.Sprintf(`
%s
`, level, sz, sz, escaped)
}
// docxParagraph builds a DOCX paragraph, optionally italic.
func docxParagraph(text string, italic bool) string {
escaped := escapeXML(text)
rpr := ""
if italic {
rpr = ""
}
return fmt.Sprintf(`
%s
%s
`, rpr, escaped)
}