mirror of
				https://github.com/Theodor-Springmann-Stiftung/kgpz_web.git
				synced 2025-10-30 01:25:30 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			291 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			291 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package viewmodels
 | |
| 
 | |
| import (
 | |
| 	"slices"
 | |
| 
 | |
| 	"github.com/Theodor-Springmann-Stiftung/kgpz_web/xmlmodels"
 | |
| )
 | |
| 
 | |
| // CategoriesListView represents the data for the categories overview page
 | |
| type CategoriesListView struct {
 | |
| 	Categories map[string]CategoryWithPieceCount
 | |
| 	Sorted     []string
 | |
| }
 | |
| 
 | |
| // CategoryDetailView represents a specific category with its available years
 | |
| type CategoryDetailView struct {
 | |
| 	Category         xmlmodels.Category
 | |
| 	CategoryReadable map[string]interface{}
 | |
| 	AvailableYears   []YearWithPieceCount
 | |
| 	PieceCount       int
 | |
| }
 | |
| 
 | |
| // CategoryPiecesView represents pieces filtered by category and year
 | |
| type CategoryPiecesView struct {
 | |
| 	Category         xmlmodels.Category
 | |
| 	CategoryReadable map[string]interface{}
 | |
| 	Year             int
 | |
| 	Pieces           []xmlmodels.Piece
 | |
| 	PieceCount       int
 | |
| 	AvailableYears   []YearWithPieceCount
 | |
| }
 | |
| 
 | |
| // CategoryWithPieceCount represents a category with total piece count and available years
 | |
| type CategoryWithPieceCount struct {
 | |
| 	Category       xmlmodels.Category
 | |
| 	Readable       map[string]interface{}
 | |
| 	PieceCount     int
 | |
| 	AvailableYears []YearWithPieceCount
 | |
| }
 | |
| 
 | |
| // YearWithPieceCount represents a year with piece count for a specific category
 | |
| type YearWithPieceCount struct {
 | |
| 	Year       int
 | |
| 	PieceCount int
 | |
| }
 | |
| 
 | |
| // CategoriesView returns categories data for the overview page
 | |
| func CategoriesView(lib *xmlmodels.Library) *CategoriesListView {
 | |
| 	res := CategoriesListView{Categories: make(map[string]CategoryWithPieceCount)}
 | |
| 
 | |
| 	// Count pieces per category and year
 | |
| 	categoryPieceCounts := make(map[string]int)
 | |
| 	categoryYearCounts := make(map[string]map[int]int) // categoryID -> year -> count
 | |
| 
 | |
| 	for _, piece := range lib.Pieces.Array {
 | |
| 		// Get years for this piece
 | |
| 		pieceYears := make(map[int]bool)
 | |
| 		for _, issueRef := range piece.IssueRefs {
 | |
| 			if issueRef.When.Year > 0 {
 | |
| 				pieceYears[issueRef.When.Year] = true
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// Process CategoryRefs
 | |
| 		for _, catRef := range piece.CategoryRefs {
 | |
| 			if catRef.Ref != "" {
 | |
| 				categoryPieceCounts[catRef.Ref]++
 | |
| 				if categoryYearCounts[catRef.Ref] == nil {
 | |
| 					categoryYearCounts[catRef.Ref] = make(map[int]int)
 | |
| 				}
 | |
| 				for year := range pieceYears {
 | |
| 					categoryYearCounts[catRef.Ref][year]++
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// Process WorkRefs with categories
 | |
| 		for _, workRef := range piece.WorkRefs {
 | |
| 			categoryID := workRef.Category
 | |
| 			if categoryID == "" {
 | |
| 				categoryID = "rezension" // Default category for WorkRefs
 | |
| 			}
 | |
| 			categoryPieceCounts[categoryID]++
 | |
| 			if categoryYearCounts[categoryID] == nil {
 | |
| 				categoryYearCounts[categoryID] = make(map[int]int)
 | |
| 			}
 | |
| 			for year := range pieceYears {
 | |
| 				categoryYearCounts[categoryID][year]++
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Build categories list with piece counts and available years
 | |
| 	for _, category := range lib.Categories.Array {
 | |
| 		if categoryPieceCounts[category.ID] > 0 {
 | |
| 			// Merge readable and readable HTML data
 | |
| 			readable := category.Readable(lib)
 | |
| 			readableHTML := category.ReadableHTML()
 | |
| 			for k, v := range readableHTML {
 | |
| 				readable[k] = v
 | |
| 			}
 | |
| 
 | |
| 			// Build available years list for this category
 | |
| 			var availableYears []YearWithPieceCount
 | |
| 			if yearCounts, exists := categoryYearCounts[category.ID]; exists {
 | |
| 				years := make([]int, 0, len(yearCounts))
 | |
| 				for year := range yearCounts {
 | |
| 					years = append(years, year)
 | |
| 				}
 | |
| 				slices.Sort(years)
 | |
| 
 | |
| 				for _, year := range years {
 | |
| 					availableYears = append(availableYears, YearWithPieceCount{
 | |
| 						Year:       year,
 | |
| 						PieceCount: yearCounts[year],
 | |
| 					})
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			res.Categories[category.ID] = CategoryWithPieceCount{
 | |
| 				Category:       category,
 | |
| 				Readable:       readable,
 | |
| 				PieceCount:     categoryPieceCounts[category.ID],
 | |
| 				AvailableYears: availableYears,
 | |
| 			}
 | |
| 			res.Sorted = append(res.Sorted, category.ID)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Sort by category ID
 | |
| 	slices.Sort(res.Sorted)
 | |
| 
 | |
| 	return &res
 | |
| }
 | |
| 
 | |
| // CategoryDetailView returns category data with available years
 | |
| func CategoryView(categoryID string, lib *xmlmodels.Library) *CategoryDetailView {
 | |
| 	// Get the category
 | |
| 	category := lib.Categories.Item(categoryID)
 | |
| 	if category == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	// Count pieces per year for this category
 | |
| 	yearPieceCounts := make(map[int]int)
 | |
| 	totalPieces := 0
 | |
| 
 | |
| 	for _, piece := range lib.Pieces.Array {
 | |
| 		matchesCategory := false
 | |
| 
 | |
| 		// Check direct CategoryRefs
 | |
| 		for _, catRef := range piece.CategoryRefs {
 | |
| 			if catRef.Ref == categoryID {
 | |
| 				matchesCategory = true
 | |
| 				break
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// Check WorkRefs with categories if not found in direct refs
 | |
| 		if !matchesCategory {
 | |
| 			for _, workRef := range piece.WorkRefs {
 | |
| 				if workRef.Category == categoryID || (workRef.Category == "" && categoryID == "rezension") {
 | |
| 					matchesCategory = true
 | |
| 					break
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if matchesCategory {
 | |
| 			totalPieces++
 | |
| 			// Extract years from IssueRefs
 | |
| 			for _, issueRef := range piece.IssueRefs {
 | |
| 				year := issueRef.When.Year
 | |
| 				if year > 0 {
 | |
| 					yearPieceCounts[year]++
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Build available years list
 | |
| 	var availableYears []YearWithPieceCount
 | |
| 	years := make([]int, 0, len(yearPieceCounts))
 | |
| 	for year := range yearPieceCounts {
 | |
| 		years = append(years, year)
 | |
| 	}
 | |
| 	slices.Sort(years)
 | |
| 
 | |
| 	for _, year := range years {
 | |
| 		availableYears = append(availableYears, YearWithPieceCount{
 | |
| 			Year:       year,
 | |
| 			PieceCount: yearPieceCounts[year],
 | |
| 		})
 | |
| 	}
 | |
| 
 | |
| 	// Merge readable and readable HTML data
 | |
| 	readable := category.Readable(lib)
 | |
| 	readableHTML := category.ReadableHTML()
 | |
| 	for k, v := range readableHTML {
 | |
| 		readable[k] = v
 | |
| 	}
 | |
| 
 | |
| 	return &CategoryDetailView{
 | |
| 		Category:         *category,
 | |
| 		CategoryReadable: readable,
 | |
| 		AvailableYears:   availableYears,
 | |
| 		PieceCount:       totalPieces,
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // NewCategoryPiecesView returns pieces filtered by category and year
 | |
| func NewCategoryPiecesView(categoryID string, year int, lib *xmlmodels.Library) *CategoryPiecesView {
 | |
| 	// Get the category
 | |
| 	category := lib.Categories.Item(categoryID)
 | |
| 	if category == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	var pieces []xmlmodels.Piece
 | |
| 	yearPieceCounts := make(map[int]int)
 | |
| 
 | |
| 	for _, piece := range lib.Pieces.Array {
 | |
| 		matchesCategory := false
 | |
| 
 | |
| 		// Check direct CategoryRefs
 | |
| 		for _, catRef := range piece.CategoryRefs {
 | |
| 			if catRef.Ref == categoryID {
 | |
| 				matchesCategory = true
 | |
| 				break
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		// Check WorkRefs with categories if not found in direct refs
 | |
| 		if !matchesCategory {
 | |
| 			for _, workRef := range piece.WorkRefs {
 | |
| 				if workRef.Category == categoryID || (workRef.Category == "" && categoryID == "rezension") {
 | |
| 					matchesCategory = true
 | |
| 					break
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if matchesCategory {
 | |
| 			// Count all years for this category (for navigation)
 | |
| 			for _, issueRef := range piece.IssueRefs {
 | |
| 				if issueRef.When.Year > 0 {
 | |
| 					yearPieceCounts[issueRef.When.Year]++
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			// Check if piece appears in the specified year
 | |
| 			for _, issueRef := range piece.IssueRefs {
 | |
| 				if issueRef.When.Year == year {
 | |
| 					pieces = append(pieces, piece)
 | |
| 					break
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// Build available years list
 | |
| 	var availableYears []YearWithPieceCount
 | |
| 	years := make([]int, 0, len(yearPieceCounts))
 | |
| 	for yearVal := range yearPieceCounts {
 | |
| 		years = append(years, yearVal)
 | |
| 	}
 | |
| 	slices.Sort(years)
 | |
| 
 | |
| 	for _, yearVal := range years {
 | |
| 		availableYears = append(availableYears, YearWithPieceCount{
 | |
| 			Year:       yearVal,
 | |
| 			PieceCount: yearPieceCounts[yearVal],
 | |
| 		})
 | |
| 	}
 | |
| 
 | |
| 	// Merge readable and readable HTML data
 | |
| 	readable := category.Readable(lib)
 | |
| 	readableHTML := category.ReadableHTML()
 | |
| 	for k, v := range readableHTML {
 | |
| 		readable[k] = v
 | |
| 	}
 | |
| 
 | |
| 	return &CategoryPiecesView{
 | |
| 		Category:         *category,
 | |
| 		CategoryReadable: readable,
 | |
| 		Year:             year,
 | |
| 		Pieces:           pieces,
 | |
| 		PieceCount:       len(pieces),
 | |
| 		AvailableYears:   availableYears,
 | |
| 	}
 | |
| } | 
