package achievements import ( "fmt" "sync" ) // MasterList is a specialized achievement master list optimized for: // - Fast ID-based lookups (O(1)) // - Fast category-based lookups (O(1)) // - Fast expansion-based lookups (O(1)) // - Efficient filtering and iteration type MasterList struct { // Core storage achievements map[uint32]*Achievement // ID -> Achievement mutex sync.RWMutex // Category indices for O(1) lookups byCategory map[string][]*Achievement // Category -> achievements byExpansion map[string][]*Achievement // Expansion -> achievements // Cached metadata categories []string // Unique categories (cached) expansions []string // Unique expansions (cached) metaStale bool // Whether metadata cache needs refresh } // NewMasterList creates a new specialized achievement master list func NewMasterList() *MasterList { return &MasterList{ achievements: make(map[uint32]*Achievement), byCategory: make(map[string][]*Achievement), byExpansion: make(map[string][]*Achievement), metaStale: true, } } // refreshMetaCache updates the categories and expansions cache func (m *MasterList) refreshMetaCache() { if !m.metaStale { return } categorySet := make(map[string]struct{}) expansionSet := make(map[string]struct{}) // Collect unique categories and expansions for _, achievement := range m.achievements { if achievement.Category != "" { categorySet[achievement.Category] = struct{}{} } if achievement.Expansion != "" { expansionSet[achievement.Expansion] = struct{}{} } } // Clear existing caches and rebuild m.categories = m.categories[:0] for category := range categorySet { m.categories = append(m.categories, category) } m.expansions = m.expansions[:0] for expansion := range expansionSet { m.expansions = append(m.expansions, expansion) } m.metaStale = false } // AddAchievement adds an achievement with full indexing func (m *MasterList) AddAchievement(achievement *Achievement) bool { if achievement == nil { return false } m.mutex.Lock() defer m.mutex.Unlock() // Check if exists if _, exists := m.achievements[achievement.AchievementID]; exists { return false } // Add to core storage m.achievements[achievement.AchievementID] = achievement // Update category index if achievement.Category != "" { m.byCategory[achievement.Category] = append(m.byCategory[achievement.Category], achievement) } // Update expansion index if achievement.Expansion != "" { m.byExpansion[achievement.Expansion] = append(m.byExpansion[achievement.Expansion], achievement) } // Invalidate metadata cache m.metaStale = true return true } // GetAchievement retrieves by ID (O(1)) func (m *MasterList) GetAchievement(id uint32) *Achievement { m.mutex.RLock() defer m.mutex.RUnlock() return m.achievements[id] } // GetAchievementClone retrieves a cloned copy of an achievement by ID func (m *MasterList) GetAchievementClone(id uint32) *Achievement { m.mutex.RLock() defer m.mutex.RUnlock() achievement := m.achievements[id] if achievement == nil { return nil } return achievement.Clone() } // GetAllAchievements returns a copy of all achievements map func (m *MasterList) GetAllAchievements() map[uint32]*Achievement { m.mutex.RLock() defer m.mutex.RUnlock() // Return a copy to prevent external modification result := make(map[uint32]*Achievement, len(m.achievements)) for id, achievement := range m.achievements { result[id] = achievement } return result } // GetAchievementsByCategory returns all achievements in a category (O(1)) func (m *MasterList) GetAchievementsByCategory(category string) []*Achievement { m.mutex.RLock() defer m.mutex.RUnlock() return m.byCategory[category] } // GetAchievementsByExpansion returns all achievements in an expansion (O(1)) func (m *MasterList) GetAchievementsByExpansion(expansion string) []*Achievement { m.mutex.RLock() defer m.mutex.RUnlock() return m.byExpansion[expansion] } // GetAchievementsByCategoryAndExpansion returns achievements matching both category and expansion func (m *MasterList) GetAchievementsByCategoryAndExpansion(category, expansion string) []*Achievement { m.mutex.RLock() defer m.mutex.RUnlock() categoryAchievements := m.byCategory[category] expansionAchievements := m.byExpansion[expansion] // Use smaller set for iteration efficiency if len(categoryAchievements) > len(expansionAchievements) { categoryAchievements, expansionAchievements = expansionAchievements, categoryAchievements } // Set intersection using map lookup expansionSet := make(map[*Achievement]struct{}, len(expansionAchievements)) for _, achievement := range expansionAchievements { expansionSet[achievement] = struct{}{} } var result []*Achievement for _, achievement := range categoryAchievements { if _, exists := expansionSet[achievement]; exists { result = append(result, achievement) } } return result } // GetCategories returns all unique categories using cached results func (m *MasterList) GetCategories() []string { m.mutex.Lock() // Need write lock to potentially update cache defer m.mutex.Unlock() m.refreshMetaCache() // Return a copy to prevent external modification result := make([]string, len(m.categories)) copy(result, m.categories) return result } // GetExpansions returns all unique expansions using cached results func (m *MasterList) GetExpansions() []string { m.mutex.Lock() // Need write lock to potentially update cache defer m.mutex.Unlock() m.refreshMetaCache() // Return a copy to prevent external modification result := make([]string, len(m.expansions)) copy(result, m.expansions) return result } // RemoveAchievement removes an achievement and updates all indices func (m *MasterList) RemoveAchievement(id uint32) bool { m.mutex.Lock() defer m.mutex.Unlock() achievement, exists := m.achievements[id] if !exists { return false } // Remove from core storage delete(m.achievements, id) // Remove from category index if achievement.Category != "" { categoryAchievements := m.byCategory[achievement.Category] for i, a := range categoryAchievements { if a.AchievementID == id { m.byCategory[achievement.Category] = append(categoryAchievements[:i], categoryAchievements[i+1:]...) break } } } // Remove from expansion index if achievement.Expansion != "" { expansionAchievements := m.byExpansion[achievement.Expansion] for i, a := range expansionAchievements { if a.AchievementID == id { m.byExpansion[achievement.Expansion] = append(expansionAchievements[:i], expansionAchievements[i+1:]...) break } } } // Invalidate metadata cache m.metaStale = true return true } // UpdateAchievement updates an existing achievement func (m *MasterList) UpdateAchievement(achievement *Achievement) error { if achievement == nil { return fmt.Errorf("achievement cannot be nil") } m.mutex.Lock() defer m.mutex.Unlock() // Check if exists old, exists := m.achievements[achievement.AchievementID] if !exists { return fmt.Errorf("achievement %d not found", achievement.AchievementID) } // Remove old achievement from indices (but not core storage yet) if old.Category != "" { categoryAchievements := m.byCategory[old.Category] for i, a := range categoryAchievements { if a.AchievementID == achievement.AchievementID { m.byCategory[old.Category] = append(categoryAchievements[:i], categoryAchievements[i+1:]...) break } } } if old.Expansion != "" { expansionAchievements := m.byExpansion[old.Expansion] for i, a := range expansionAchievements { if a.AchievementID == achievement.AchievementID { m.byExpansion[old.Expansion] = append(expansionAchievements[:i], expansionAchievements[i+1:]...) break } } } // Update core storage m.achievements[achievement.AchievementID] = achievement // Add new achievement to indices if achievement.Category != "" { m.byCategory[achievement.Category] = append(m.byCategory[achievement.Category], achievement) } if achievement.Expansion != "" { m.byExpansion[achievement.Expansion] = append(m.byExpansion[achievement.Expansion], achievement) } // Invalidate metadata cache m.metaStale = true return nil } // Size returns the total number of achievements func (m *MasterList) Size() int { m.mutex.RLock() defer m.mutex.RUnlock() return len(m.achievements) } // Clear removes all achievements from the master list func (m *MasterList) Clear() { m.mutex.Lock() defer m.mutex.Unlock() // Clear all maps m.achievements = make(map[uint32]*Achievement) m.byCategory = make(map[string][]*Achievement) m.byExpansion = make(map[string][]*Achievement) // Clear cached metadata m.categories = m.categories[:0] m.expansions = m.expansions[:0] m.metaStale = true } // ForEach executes a function for each achievement func (m *MasterList) ForEach(fn func(uint32, *Achievement)) { m.mutex.RLock() defer m.mutex.RUnlock() for id, achievement := range m.achievements { fn(id, achievement) } }