package achievements import ( "fmt" "sync" ) // MasterList manages the global list of all achievements type MasterList struct { achievements map[uint32]*Achievement mutex sync.RWMutex } // NewMasterList creates a new master achievement list func NewMasterList() *MasterList { return &MasterList{ achievements: make(map[uint32]*Achievement), } } // AddAchievement adds an achievement to the master list // Returns false if achievement with same ID already exists func (m *MasterList) AddAchievement(achievement *Achievement) bool { if achievement == nil { return false } m.mutex.Lock() defer m.mutex.Unlock() if _, exists := m.achievements[achievement.ID]; exists { return false } m.achievements[achievement.ID] = achievement return true } // GetAchievement retrieves an achievement by ID // Returns nil if not found 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 // Returns nil if not found. Safe for modification without affecting master list func (m *MasterList) GetAchievementClone(id uint32) *Achievement { m.mutex.RLock() achievement := m.achievements[id] m.mutex.RUnlock() if achievement == nil { return nil } return achievement.Clone() } // GetAllAchievements returns a map of all achievements (read-only access) // The returned map should not be modified func (m *MasterList) GetAllAchievements() map[uint32]*Achievement { m.mutex.RLock() defer m.mutex.RUnlock() // Return copy of map 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 achievements filtered by category func (m *MasterList) GetAchievementsByCategory(category string) []*Achievement { m.mutex.RLock() defer m.mutex.RUnlock() var result []*Achievement for _, achievement := range m.achievements { if achievement.Category == category { result = append(result, achievement) } } return result } // GetAchievementsByExpansion returns achievements filtered by expansion func (m *MasterList) GetAchievementsByExpansion(expansion string) []*Achievement { m.mutex.RLock() defer m.mutex.RUnlock() var result []*Achievement for _, achievement := range m.achievements { if achievement.Expansion == expansion { result = append(result, achievement) } } return result } // RemoveAchievement removes an achievement from the master list // Returns true if achievement was found and removed func (m *MasterList) RemoveAchievement(id uint32) bool { m.mutex.Lock() defer m.mutex.Unlock() if _, exists := m.achievements[id]; !exists { return false } delete(m.achievements, id) return true } // UpdateAchievement updates an existing achievement // Returns error if achievement doesn't exist func (m *MasterList) UpdateAchievement(achievement *Achievement) error { if achievement == nil { return fmt.Errorf("achievement cannot be nil") } m.mutex.Lock() defer m.mutex.Unlock() if _, exists := m.achievements[achievement.ID]; !exists { return fmt.Errorf("achievement with ID %d does not exist", achievement.ID) } m.achievements[achievement.ID] = achievement return nil } // Clear removes all achievements from the master list func (m *MasterList) Clear() { m.mutex.Lock() defer m.mutex.Unlock() m.achievements = make(map[uint32]*Achievement) } // Size returns the number of achievements in the master list func (m *MasterList) Size() int { m.mutex.RLock() defer m.mutex.RUnlock() return len(m.achievements) } // Exists checks if an achievement with given ID exists func (m *MasterList) Exists(id uint32) bool { m.mutex.RLock() defer m.mutex.RUnlock() _, exists := m.achievements[id] return exists } // GetCategories returns all unique categories func (m *MasterList) GetCategories() []string { m.mutex.RLock() defer m.mutex.RUnlock() categories := make(map[string]bool) for _, achievement := range m.achievements { if achievement.Category != "" { categories[achievement.Category] = true } } result := make([]string, 0, len(categories)) for category := range categories { result = append(result, category) } return result } // GetExpansions returns all unique expansions func (m *MasterList) GetExpansions() []string { m.mutex.RLock() defer m.mutex.RUnlock() expansions := make(map[string]bool) for _, achievement := range m.achievements { if achievement.Expansion != "" { expansions[achievement.Expansion] = true } } result := make([]string, 0, len(expansions)) for expansion := range expansions { result = append(result, expansion) } return result }